《Data Strurcture》
来源:互联网 发布:银行软件测试招聘 编辑:程序博客网 时间:2024/06/14 00:36
学习笔记 《数据结构》 严蔚敏
2014 Fall
考量算法的时间复杂度一般指最坏时间复杂度,故我们可以针对特殊的用途对算法进行针对性的优化,使之在大多数情况下的效率较高。
Chapter Two Linear Table
data structure:
1. 顺序存储:数组
2. 链式存储:单链表,双向链表,循环链表
Chapter Three Stack & List
Stack
栈和队列是特殊的线性表
Stack:LIFO(Last in first out)
Operation:Push, Pop
Data structure:1. 顺序栈(array) static data; 2. 链式栈(pointer + list)dynamic data
Application of stack
(1) 数值转换
十进制数N转化为八进制数公式:N = (N div d) * d + (N mod d)
div: 整除,mod:取模,d为要转化的进制
e.g. 十进制1348转化为八进制数2504的过程如下:
N N div 8 N mod 8
1348 168 4
168 21 0
21 2 5
2 0 2
then,逆序输出为2504,即用栈存储N mod 8的值然后再pop栈
(2)数学运算/表达式求值
表达式包括:括号,加减,乘除
例如:1 + 2 * 5 - 6 / 4
(3)迷宫求解
思想:穷举法,用到回溯操作,可以用栈来实现,当然也可以用递归
(4)Hanoi汉诺塔
经典的递归问题
描述:存在三个支架X,Y,Z,初始时只有X架子上摆放了N个按照从小到大的圆环,要求每次移动一个圆环,最终将所有圆环按照从小打到大的顺序全部摆放在Z支架上。
算法描述:
Definition function : hanoi (n, x, y, z) means move n rings from x to z via y.
1. if n=1, move (1, x -> z)
2. if n>1, hanoi ((n-1), x, z, y), move(n, x->z), hanoi ((n-1), y, x, z)
Queue队列
Feature: FIFO , specail linear list
Operation: EnQueue, DeQueue
Data sturcture:
(1) pointer list
typedef struct QNode {
elemtype data;
struct QNode * next;
}QNode, *QnodePtr;
typedef struct {
QueuePtr front;
QueuePtr rear;
}LinkQueue;
(2) Array for cycle queue
elemType data[max];
typedef struct {
elemType * base;
int front;
int rear;
}SqQueue;
Tricks:
仅用Q.rear是否等于Q.front无法判断Queue是否为empty或者full,So
两种方式解决:
1. 浪费一个空间,优
2. 设定一个标记位,比如Queue成员个数num
Chapter Four String
S = 'abcdefg'
常见问题:求字串/找字串
问题类型:模式匹配
复杂度:两个For循环的算法O(n * m)
改进算法:kmp算法 O (n + m)
主要思想:尽量减少主串的回溯距离,让主串不回溯,从子串的第K个子串和主串的第i个继续比较(其中第K个子串在next[j]中记录);关键:kmp算法中涉及的子串的next数组的生成算法,此时只需要子串,无需主串。多开销O(m)的时间复杂度,来计算next数组。
next数组的生成算法不为一。
注意:仅当主串与模式串之间存在很多部分匹配时,KMP算法才会比O(n * m)普通算法快很多
Chapter Five Array
C语言中,以行序为主序来存储数组 Loc(i,j) = Loc(0,0)+(b2 * i + j)L
二位数组多用于存储Matrix数据
对于特殊矩阵,比如对称矩阵,稀疏矩阵,都可以利用压缩存储方式,比如三元组顺序表(用数值+行号+列号标记一个元素信息)
另外,Martrix也可用十字链表来存储
广义表的推广
递归定义:表头 + 子表 (广义表)
Chapter Six Tree
定义
递归式定义:根 + 子树 (sub-tree)
叶子——分支结点度——结点拥有的子树数目
深度(高度)——树中结点的最大层数,根为第一层
二叉树:不存在度大于2的结点,子树左右之分
二叉树的存储结构
1. 二叉链表 【lchild + data + rchild】
2. 三叉链表【lchild + data + parent + rchild 】
二叉树遍历
1. 先(根)序遍历
2. 中序遍历
3. 后序遍历
基于递归原则
e.g. PreOrderTraverse(T) {
XXX(T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
e.g. 中序遍历二叉树的非递归算法
InOrderTraverse(BiTree T) {
InitStack(S);
P = T;
while(p || !StackEmpty(s)) {
if(p) {push(S, p); p = p->lchild;}
else {pop(S,p); printf(p->data); p - p->rchildj}
}//while
}
Tips: 将遍历过程用图示表示,容易得出非递归算法
无论哪一种方式遍历二叉树,时间复杂度都为O(n)
赫夫曼树(HuffmanTree)
又称最优树,一种带权路径长度最短的树
树的路径长度——从树根到每个节点的路径长度之和
树的带权路径长度——WPL = sum(WkLk) (k = 1,2, .... n)
主要应用:赫夫曼编码
回溯法与树的遍历
回溯法是设计递归过程中的一种重要方法,其实质就是一种先序遍历一颗“状态树”的过程
Chapter Seven Graph
图的特性:
e——边的数目,其值不大于1/2 * n * (n - 1)
n——顶点的数目
n个顶点的树有且只有n - 1条边
n个顶点的图若小于 n - 1条边,则是非连通图
存储结构:
(1) 数组(相邻矩阵)
n个结点,便有n平方个数据单元n * n矩阵存储,其中数据单元存储权值
(2) 邻接表
struct node {
int data;
struct node * adj;
}
struct node GRAPH[100]; //存储100个结点的图,每个node结点依次记录所有的相邻结点指针
(3) 十字链表
图的遍历
(1) DFS深度优先,类似于树的先跟遍历
(2) BFS广度优先
主要问题:
1. 最小生成树MST(mininum cost spanning tree)
两种常用算法:普利姆(Prim)算法 O(n平方); 克鲁斯卡尔(Kruskal)算法 O(eloge)
2. 关键路径
3. 最短路径
迪杰斯特拉(Dijkstra)算法 O(n平方):从某一个点到其余各个顶点的最短路径
弗洛伊德(Floyd)算法,O(n三次方):从每一对顶点之间的最短路径
Chapter Eigth Dymanic allocation
基本概念
解决问题:如何高效的分配和使用内存
基本思路:可利用空间表及其分配方式
存储结构:链表:记录每一块可利用空间的大小,每次内存分配和释放都来更新空间表。
优化方案:
(1) 构建多个空间表,用于不同大小的内存需求,例如0-512 512-1k,1k-10k,。。。。。,根据需求内存大小分配对应的空间表。
优点:产生的内存fragment比较小
缺点:内存利用率不高
(2)整体(全局)动态空间表,系统开始时创建以整个内存为一个大空间区域的空间表,随着程序的运行不断寻找到合适的空闲块来分配,一般heap动态分配算法采用这种方式,比如malloc/free实现
注意:1. 每次分配空间,要去找合适的空闲块; 2. 每次回收空间,可能要合并相邻的空闲块
整体空间表中对空闲块不唯一的选择策略:
1. 首次拟合(少用); 2。 最佳拟合(最合适的空闲块);3. 最差拟合(最大的空闲块)
注意:实际应用时,会对空间表的空闲单元进行排序,建立一张索引表。
分配策略:
(1) 为了避免修改指针,每次将高地址部分分配出去,这样低地址部分留作剩余空闲块,链表结点不变
(2)为避免"极小"空闲块的浪费,如果出现不满足待分配的空闲块,例如连“表头”数据都不满足。为了避免这种情况,设定一个阈值E,当发现某一个空闲块大小减去实际需求大小的值小于E时,将整个空闲块分配出去!
伙伴系统(buddy system)
同上述的空间表类似,不同之处在于空间单元大小为2的指数幂,2的0次方,2的1次方,2的2次方,。。。。。2的k次方。
1. 将大小相同的空间表连成一个表,最多k+1个表
2. 将k+1个表的表头放在一个数组中,有点类似于十字链表,只不过纵列是数组
具体分配和回收策略
大致思想如下:
(1)(我认为的)每个表中,分配固定大小的空间,并且尽量找到最匹配的表。即,分配7M空间,从4-8M的表中分配8M出来,虽然浪费1M,但是不会产生碎片,即使内存利用率不高。如果不这样做,就必须考虑内存回收策略了,如下。
(2)关键难点是回收策略,仅考虑“伙伴”的两个空闲块合并,
伙伴的定义:由同一大块分裂出来的小块,(我认为)就是同一个表,即都在2的N次方的这块空闲区域分配的空间
优点:算法简单,速度快
缺点:容易产生碎片
注明:每个表会预先分配出一大块内存,然后当具体分配小块内存时,就从这一大块内存中分配
解决内存leak,即无用内存的方法:
(1)访问计数器,记录指针数目,当没有指针指向此区域,即自动free,防止忘掉手动free
(2)强行收回,当前指针指向的内存标记出来,剩余的一律强制free
存储紧缩的方式:
本质是:移动内存,减少fregment
Chapter Nine Search Table
基本概念
由同一类型的数据元素构成的集合
主要根据关键字key来searching
基本思路:
1. 先对Table进行排序,然后可用折半查找
2. 建立多级索引表,来逐一递减划分
key (22)(48)(86)
addr(1) (7) (13)
Data 22 23 XX XX XX XX 48 59 ........... 86 108 215 ......
其中:22在index1; 48在index 7; 86在index13
动态查找表
若元素不存在,则插入表中,即表示不断更新的。
二叉排序树:又称二叉查找树 O(logn)
平衡二叉树(AVL tree)BalancedBinaryTree O(logn)
B- 树 :平衡的多路查找树
B+ 树:应用于文件系统的B-树变种
哈希表
Hash函数:将元素的key和存储位置建立对应关系,免去查找,一次定位成功
Hash表也称之为散列表,不可避免会出现冲突。
设计hash表的两个考虑函数:1. hash函数;2. 冲突函数 (线性再散列,OR 再hash,OR链地址)
Chapter Ten Sorting
(1)插入排序
直接插入排序O(n2); 折半插入排序O(n2)
(2)希尔排序(Shell's sort)
又称“缩小增量排序” (Diminishing Increment Sort)
属于一种插入排序,类似于先宏观调整,后微观调整;
也类似于,元素移动是先较大范围的移动,而非一步步的调整,先粗后细,效率较高
O(n1.5)即n的3分之2次方
(3)快速排序
冒泡排序bubbleSort O(n2)
QuickSort 对bubbleSort的改进,通过交换,每一轮都会对剩余部分整体上划分两个部分,一部分大于比较key,一部分小于key,再对这两部分分别用QuickSort。
O(nlogn)
(4)选择排序 SKIP
- 《Data Strurcture》
- data
- data ()
- data
- Data
- data
- data
- data
- data
- data
- <data>
- data
- DATA
- data
- data
- data
- data
- @Data
- 如何搜索到更多的资源 IOS
- UTF-8 字符集排序规则
- hpp文件
- Apache常用函数解释
- python开发_sqlite3_绝对完整
- 《Data Strurcture》
- cocos2dx3.2打开Url
- 剑指Offer之 - 不用加减乘除做加法
- 2015.4.28 今天开博客了
- IOS 设备 通过HTML页面在线安装APP配置(面向越狱设备或者有开发者账号调试APP)
- 【JAVA集合类(大公司面试喜欢问的) 】
- 深入理解Git (一) - 元数据
- 如何让PDF转换成Excel
- 第八周项目1 实现复数类中的运算符重载 (用类的友元函数)