《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

0 0
原创粉丝点击