ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

北师大数据结构期末考试复习

2021-09-11 20:02:35  阅读:135  来源: 互联网

标签:结点 北师大 img 转存 期末考试 外链 数据结构 防盗链 图片


绪论

数据

数值性数据,非数值性数据

输入,输出,存储数据

数据元素(数据的基本单位)

有时一个数据元素可以由若干数据项(Data Item)组成。数据项是具有独立含义的最小标识单位。

数据对象(数据的子集)

具有相同性质的数据成员(数据元素)的集合

数据结构 Data_Structure = { D, R, M }

D 是某一数据元素的集合;
R 是该集合中所有数据成员之间的关系的有限集合;
M 是作用在该集合所有数据成员之上的方法(或操作)。

数据的逻辑结构

数据的逻辑结构抛弃了数据元素及其关系的实现细节,只反映了系统的需求(从用户使用层面上)而不考虑如何实现。
数据的逻辑结构从逻辑关系上描述数据,与数据的存储无关。
数据的的逻辑结构与数据元素的内容无关。
数据的逻辑结构与它所包含的数据元素个数无关。
数据的逻辑结构与数据元素所处位置无关。

分类
线性结构

线性表

非线性结构

多维数组
广义表

图(或网络)

无结构

集合

数据的存储结构(物理结构)

内容存储:数据元素的内容或值

关系存储:各数据元素之间的逻辑关系

附加存储:为使施加于数据结构上的运算得以实现而附加的存储空间

顺序存储表示:连续空间存储

链接存储表示:动态分配内存空间

索引存储表示:用于对索引文件的实现(索引表)

散列存储表示:用于直接存取文件的实现(函数求出的关键码)

数据类型

基本数据类型

构造数据类型

抽象数据类型

信息隐藏

数据封装

使用与实现相分离

算法: 算法+数据结构=程序

输入:0个或多个输入

输出:1个或多个输出

确定性

有穷性

有效性

评价(复杂度,完善)

正确性

可读性

健壮性

高效性

简单性

基本方法

穷举型(素数)

迭代法(求根)

递推法(斐波那契数列)

递归法(同上)

动态规划法

time() 后期测试

double start, stop;
time (&start);	
int k = seqsearch (a, n, x);
time (&stop);			
double runTime = stop - start;
printf ( ”%d%d\n " , n, runTime );

时间复杂度

c < log2n < n < nlog2n < n^2 < n^3 < 2^n < 3^n < n!

for(int i = 0;i < m;i++)

语句频度:m+1

递归的复杂度(递推后去计算)

2.线性表

定义 n(≥0)个数据元素的有限序列,记作(a1, a2, …, an)
ai 是表中数据元素,n 是表长度。

特点:线性排列

除第一个元素外,其他每一个元素有一个且仅有一个直接前趋。

除最后一个元素外,其他每一个元素有一个且仅有一个直接后继。

线性表key point

1.表中元素具有逻辑上的顺序性,在序列中各元素排列有其先后次序,有唯一的首元素和尾元素。
2.表中元素个数有限。
3.表中元素都是数据元素。即每一表元素都是原子数据,不允许“表中套表”。
4.表中元素的数据类型都相同。这意味着每一表元素占有相同数量的存储空间。

顺序表

定义

将线性表中的元素相继存放在一个连续的存储空间中,即构成顺序表。

存储

它是线性表的顺序存储表示,可利用一维数组描述存储结构。

特点

元素的逻辑顺序与物理顺序一致。

访问方式

可顺序存取,可按下标直接存取。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FmPB80jr-1631361136971)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210103155834911.png)]

LOC是元素存储位置,l是元素大小

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6kHUpfhB-1631361136973)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210103155928887.png)]

静态结构:表一旦装满,不能扩充

int n;
T data[MAXN];

动态结构:可以扩充

int maxsize;
int n;
T *data;
查找

从顺序表的头开始顺序查找

查找成功:n*(n+1)/2n = (n+1)/2

查找不成功:n

插入
for(int j = L.n-1;j >= i-1;j--)// 第i个位置插入
{
    L.data[j+1] = L.data[j];
}
L.data[i-1] = x;

插入时平均移动元素个数:n*(n+1)/2(n+1) = n/2

删除
for(int j = i;j < L.n;j++) // 删除第i个元素
{
    L.data[j-1] = L.data[j];
}

删除时平均移动元素个数:n*(n-1)/2n = (n-1)/2

链表(连接存储)

链表中第一个元素结点称为首元结点,最后一个元素称为尾结点。首元结点不是头结点。

单链表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j25WW0ML-1631361136987)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210103161822923.png)]

线性结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3b6A1cSW-1631361136993)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210103161843031.png)]

结点可以连续,可以不连续存储
结点的逻辑顺序与物理顺序可以不一致
表可扩充

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gikqYGIq-1631361136996)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210103162055240.png)]

定义
struct node{
    T data;
    struct node *link;
};
插入
newnode->link = first;
first = newnode; // 在第一个节点前插入

//首先定位到插入位置p后面
newnode->link = p->link;
p->link = newnode;
删除
q = first;
first = first->link;
delete q;	// 删除表中第一个元素

//删除p后面的节点
q = p->link;
p->link = q->link;
delete q;

带头结点的单链表

头结点位于表的最前端,本身不带数据,仅标志表头。
设置头结点的目的是
统一空表与非空表的操作
简化链表操作的实现。

前插法建立单链表

从一个空表开始,重复读入数据:
生成新结点
将读入数据存放到新结点的数据域中
将该新结点插入到链表的前端
直到读入结束符为止。

输入顺序与链接顺序相反

while(val != endtag)
{
    LinkNode *s = (LinkNode*)malloc(sizeof(LinkNode));
    s->data = val;
    s->link = first->link;
    first->link = s;
}

后插法建立单链表

输入顺序与链接顺序相同

rear->link = s;
s = rear;
清空,计算长度,按值查找,定位

循环链表(约瑟夫环)

循环单链表是单链表的变形。链表尾结点的 link 指针不是 NULL,而是指向了表的前端。

为简化操作,在循环单链表中往往加入头结点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x9cuJLtr-1631361136997)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210103164435110.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8SrvqP42-1631361136999)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210103164837602.png)]

循环单链表的判空条件是

first -> link == first;

循环单链表的特点是:只要知道表中某一结点的地址,就可搜寻到所有其他结点的地址。
在搜寻过程中,没有一个结点的 link 域为空。

循环单链表的所有操作的实现类似于单链表,差别在于检测到链尾,指针不为NULL,而是回到链头。

在表尾可直接插入新结点,时间复杂性 O(1);
在表尾删除时要找前趋,时间复杂性 O(n);
在表头插入相当于在表尾插入;
在表头可直接删除,时间复杂性 O(1)。

双向链表

双向链表是指在前趋和后继方向都能遍历的线性链表。双向链表每个结点的结构为:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pTQeMidO-1631361137000)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210103165317973.png)]

双向链表通常采用带头结点的循环双链表形式。每一个结点处于两个链中。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XfyhjXyY-1631361137003)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210103165343965.png)]

p->lLink 指示结点 p 的前趋结点
p->rLink 指示结点 p 的后继结点
p->lLink->rLink指示结点 p 的前趋结点的后继结点,即结点 p 本身
p->rLink->lLink指示结点 p 的后继结点的前趋结点,即结点 p 本身

定位
插入

p的前驱结点为新插入结点

newnode->llink = p->llink;
p->llink = newnode;
newnode->rlink = p;
newnode->llink->rlink = newnode;

p的后继节点为新插入节点

newnode->rlink = p->rlink;
p->rlink=  newnode;
newnode->llink = p;
newnode->rlink->llink = newnode;
删除
p->rlink->llink = p->llink;
p->llink->rlink = p->rlink;

顺序表与链表的比较

基于空间的比较

存储分配的方式
顺序表的存储空间可以是静态分配的,也可以是动态分配的。
链表的存储空间是动态分配的。

存储密度 = 结点数据本身所占的存储量/结点结构所占的存储总量
顺序表的存储密度 = 1
链表的存储密度 < 1

基于时间的比较

存取方式
顺序表可以随机存取,也可以顺序存取。
链表只能顺序存取。

插入/删除时移动元素个数
顺序表平均需要移动近一半元素。
链表不需要移动元素,只需要修改指针。
若插入/删除仅发生在表的两端,宜采用带尾指针的循环链表。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MWvVQ0ZV-1631361137004)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210103172524706.png)]

一元多项式

静态数组表示

int degree;	// 实际阶数
int coef[Maxdegree+1];	// 系数数组

优点:简化操作

缺点:系数多项式不经济

只保存非0项

struct data{
    float coef;	// 系数
	int exp;	// 指数
};

struct polynomial{
    int maxsize;	// 数组最大保存项数
    int n;	//实际项数
    data* Term;
}

链表

typedef struct node {		//多项式数据定义	
    float coef;	              	//系数	    
    int exp;		   	//指数
    struct node * link;	//链接指针
};

多项式的项数可以动态地增长,不存在存储溢出问题。

插入、删除方便,不移动元素。

加法(类似于归并排序)

?静态链表

3.栈和队列

栈(后进先出)

只允许在一端插入和删除(栈顶)

另一端(栈底)

顺序栈

struct seqstack{
    int *elem;
    int top, maxsize;	// top为栈顶指针
};

//初始化时S.top = -1
//判断栈空为判断S.top == -1是否为true
//判断栈满是否为S.top == S.maxsize-1

void push(SeqStack& S, int x)
{
    //栈满判断,栈满处理(建立新栈,将原来的栈拷贝)
    S.elem[++S.top] = x;
}

bool pop(SeqStack& S, int& x)
{
    //判断栈是否为空
    x = S.elem[S.top--];
    return true;
}

bool getTop(SeqStack& S, int& x)
{
    // 判断是否栈空
    x = S.elem[S.top];
    return true;
}

双栈共享一个栈空间

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FgYWFiXw-1631361137006)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106095937669.png)]

两个栈共享一个数组空间V[MaxSize],设立栈顶指针数组t[2]和栈底指针数组b[2]

t[i]和b[i]指定栈i的栈顶和栈底

初始

t[0] = b[0] = -1;	// 一开始未存元素
t[1] = b[1] = maxSize;

栈满条件

t[0] + 1 = t[1];

栈空条件

t[0] = b[0];
t[1] = b[1];

链式栈

顺序栈有栈满问题,一旦栈满需要做溢出处理,扩充栈空间,时间和空间开销较大。
链式栈无栈满问题,只要存储空间还有就可扩充。
链式栈的栈顶在链头,插入与删除仅在栈顶处执行。(前插法建立栈)

栈的混洗

当进栈元素的编号为1, 2, …, n时,可能的出栈序列有多少种

卡特兰数:1/(n+1)*C(2n,n)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vv4BxP3C-1631361137007)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106103722470.png)]

队列

队列是只允许在一端删除,在另一端插入的线性表
允许删除的一端叫做队头 (front),允许插入的一端叫做队尾 (rear)。

顺序队列

struct{
    int elem[maxsize];
    int rear, front;
};

队列与栈的共性在于它们都是限制了存取位置的线性表;区别在于存取位置有所不同。

进出队列的方案

1.先加元素再动指针(队尾指针指示实际队尾的后一位置,队头指针指示实际队头的位置)

2.先动指针再加元素(队尾指针指示实际队尾的位置,对头指的是实际队头的前一位置)

队满时再进队出现的溢出往往是假溢出,即还有空间但用不上

循环队列

队列存放数组被当作首尾相接的环形表处理。
队头、队尾指针加 1 时从 queSize-1 直接进到0,可用语言的取模(%)运算实现。

front = (front+1)%quesize;	//队头加1
rear = (rear+1)%quesize;	//队尾加1
front = rear = 0;	//初始化
front == rear;	//队空判断
(rear+1)%quesize == front	//队满判断

进队和出队指针都是顺时针前进

链式队列

链式队列采用不带头结点的单链表存储队列元素,队头在链头,队尾在链尾

链式队列在进队时无队满问题,但有队空问题。
队空条件为 front->link == NULL,不必判断是否 rear == front。

队列的应用

打印杨辉三角

栈的应用

括号匹配

当遇到左括号“(”,进栈,扫描下一字符;
当遇到右括号“)”,判断栈是否空?
若栈空,则“)”多于“(”,报错;
若栈不空,则退栈顶的“(”,扫描下一字符;
当遇到的不是括号,扫描下一字符;
若表达式扫描完,栈不空,则“(”多于“)”,报错。

表达式求值

一个表达式由操作数(亦称运算对象)、操作符 (亦称运算符) 和分界符组成

算术表达式有三种表示:
中缀(infix)表示
<操作数> <操作符> <操作数>,如 A+B;
前缀(prefix)表示
<操作符> <操作数> <操作数>,如 +AB;
后缀(postfix)表示
<操作数> <操作数> <操作符>,如 AB+;

中缀表达式求值:两个栈

后缀表达式求值:一个栈

后缀表达式求值

从左向右顺序地扫描表达式,并用一个栈暂存扫描到的操作数或计算结果。
在后缀表达式的计算顺序中已隐含了加括号的优先次序,括号在后缀表达式中不出现。

算法

顺序扫描表达式的每一项,根据它的类型做如下相应操作:

  1. 若该项是操作数,则将其压栈;
  2. 若该项是操作符,则连续从栈中退出两个操作数Y和X,形成运算指令XY,并将计算结果重新压栈
中缀表达式转为后缀表达式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vLGExFKX-1631361137010)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106112740155.png)]

isp 叫做栈内 (in stack priority) 优先数
icp 叫做栈外 (in coming priority) 优先数。
操作符优先数相等的情况只出现在括号配对或栈底的“#”号与输入流最后的“#”号配对时。
在把中缀表达式转换为后缀表达式的过程中,需要检查算术运算符的优先级,以实现运算规则。

操作符栈初始化,将结束符 ‘#’ 进栈。然后读入中缀表达式字符流的首字符 ch。
重复执行以下步骤,直到 ch = ‘#’,同时栈顶的操作符也是‘#’,停止循环。
1)若ch是操作数,直接输出,读入下一个字符 ch。
2)若 ch 是操作符,判断 ch 的优先级 icp 和位于栈顶的操作符op的优先级 isp:
①若 icp (ch) > isp (op),令ch进栈,读入下一个字符ch。(看后面是否有更高的)

​ ②若 icp (ch) < isp (op),退栈并输出。(执行先前保存在栈内的优先级高的操作符)

​ ③若 icp (ch) == isp (op),退栈但不输出,若退出的是“(”号读入下一个字符ch。(销括号)

中缀表达式计算表达式的值

使用两个栈,操作符栈OPTR (operator),操作数栈OPND(operand)

为了实现这种计算,仍需要考虑各操作符的优先级,参看前面给出的优先级表。

对中缀表达式求值的一般规则:
1.建立并初始化OPTR栈和OPND栈,然后在OPTR栈中压入一个“#”
2.扫描中缀表达式,取一字符送入ch。
3.当ch != ‘#’ 或OPTR栈的栈顶 != ‘#’时, 执行以下工作, 否则结束算法。在OPND栈的栈顶得到运算结果。
①若ch是操作数,进OPND栈,从中缀表达式取下一字符送入ch;

②若ch是操作符,比较icp(ch)的优先级和isp(OPTR)的优先级:
若icp(ch) > isp(OPTR),则ch进OPTR栈,从中缀表达式取下一字符送入ch;
若icp(ch) < isp(OPTR),则从OPND栈退出a2和a1,从OPTR栈退出θ, 形成运算指令 (a1)θ(a2),结果进OPND栈;
若icp(ch) == isp(OPTR) 且ch == ‘)’,则从OPTR栈退出’(’,对消括号,然后从中缀表达式取下一字符送入ch;

递归

若一个对象部分地包含它自己,或用它自己给自己定义,则称这个对象是递归的;若一个过程直接地或间接地调用自己,则称这个过程是递归的过程。

定义是递归的(阶乘)
数据结构是递归的(单链表)

单链表中一个结点,它的指针域为NULL,其后继是一个链表,是空链表;
单链表中一个结点,它的指针域非空,其后继仍是一个单链表,是非空单链表。
从结构上,用指针定义结点,又用结点定义指针。

struct node{
    int data;
    struct node *link;	//	定义结点用指针
}LinkNode, *LinkList;	// 定义指针用结点

问题的解法是递归的(汉诺塔)

void printlist(LinkNode *f)	//正向输出
{
    if(f != NULL)
    {
    	printf("%d",f->data);
    	printflist(f->link);   
    }
}

void printreverselist(LinkNode *f)	//逆向输出
{
    if(f != NULL)
    {
        printreverselist(f->link);
        printf("%d",f->data);
    }
}

递归过程在实现时,需要自己调用自己。
层层向下递归,退出时的次序正好相反
主程序第一次调用递归过程为外部调用;递归过程每次递归调用自己为内部调用。它们返回调用它的过程的地址不同。
每次调用必须记下返回上层什么地方的地址。

尾递归和单向递归可直接用迭代实现其非递归过程

其他情形必须借助栈实现非递归过程。

尾递归(阶乘)

程序内只有一个递归语句,且位于程序最后。它不再需要使用返回地址(反正回到上一层的最后),也不需继续使用局部变量。

递归函数传递的参数可以作为循环变量,从而把尾递归改为循环,加快了算法的执行速度。

单项递归(斐波那契)

单向递归是指递归过程执行时虽然可能有多个分支,但可以保存前面计算的结果以供后面的语句使用。

栈将递归算法改为非递归算法(汉诺塔)

注意顺序

先(n-1,B,A,C)

然后(1,A,B,C)

最后(n-1,A,C,B)

递归与分治法(大->小)
递归与回溯法(DFS)

双端队列

允许在队列的两端进行插入和删除

全进全出双端队列出对顺序:n!

普通先进先出队列:1

输入,输出受限的双端队列

优先队列(类似于堆)

每次从队列中取出的是具有最高优先权的元素

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TmtUrsXj-1631361137012)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106124803035.png)]

数字越小,优先权越高

每次在优先队列中插入新元素时,新元素总是插入在队尾;
在优先队列中每次从队列中查找权值最小的元素删除,再把队列最后元素填补到被删元素位置。

4.字符串

空串和空白串不同,例如 “ ” 和 “” 分别表示长度为1的空白串和长度为0的空串。

串中任意个连续字符组成的子序列称为该串的子串,包含子串的串相应地称为主串。(包含关系)

字符串初始化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-94WE4uIh-1631361137014)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106125956643.png)]

输入: gets(str)

输出:puts(str)

长度:strlen(str) 不包括’\0’和分界符

连接:strcat(str1,str2) str2加到str1上

字符串比较函数:strcmp(str1,str2) 字典序比较,返回str1-str2

字符串的实现

定长顺序存储

即顺序串,使用静态分配的字符数组存储字符串中的字符序列。

字符数组的长度预先用 maxSize 指定,一旦空间存满不能扩充。

struct Seqstring{
  char ch[MaxSize+1];	//存储数组
  int n;	//串中实际字符个数
};

0~maxSize 存放字符单元,另外用整数n记录实际存放的字符个数,多留一个’\0’的位置。

堆分配存储表示(动态分配)

即堆式串。字符数组的存储空间是动态分配的。串的最大空间数 maxSize 和串中实际字符个数 n 保存在串的定义中。

可以根据需要,随时改变字符数组的大小。

struct Hstring{
    char *ch;
    int maxSize;	// 最大长度
    int n;	// 当前长度
}
提取字串操作

pos+len-1<maxsize pos~pos+len-1

pos+len-1>=maxsize pos~maxsize-1

块链存储表示

链表的每个结点可以存储 1 个字符,称其“块的大小”为 1,也可以存储 n 个字符,称其“块的大小”为 n。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jMyolKo9-1631361137015)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106132132714.png)]

显然,存储密度越高,存储利用率越高。

字符串模式匹配(BF算法)

二重循环(T为主串,P为子串)

for(int i = 0;i <= T.n-P.n;i++)
{
	for(int k = i, j = 0;j < P.n;j++,k++)
	{
		if(T.ch[k] != P.ch[j]) break;
	}
    if(j == P.n) return i;
}

5.多维数组和广义表

数组

存储结构:按下标“读/写”

逻辑结构:查找,定位,插入,删除

一维数组

一维数组只能按元素的下标直接存取数组元素的值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DA9wiOtd-1631361137016)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106135300019.png)]

多维数组

多维数组属于数组套数组,可以看做是一维数组的推广。多维数组的特点是每一个数据元素可以有多个直接前驱和多个直接后继。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zqBOJzRq-1631361137017)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106135524644.png)]

二维数组A【m】【n】 可看成是由 m 个行向量组成的向量,也可看成是由 n 个列向量组成的向量。

静态:数组空间用完不能扩充

动态:数组空间用完可以扩充

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J8Y2YdLK-1631361137018)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106135935111.png)]

行优先存放:Loc(a【i】【j】) = a + (i*m+j) * l

其中,m 是每行元素个数,即列数。

l为每个元素所占的字节

列优先存放(以列为主序):Loc(a【i】【j】)=a+(j*n+i) * l

其中,n 是每列元素个数,即行数。

a【i1】【i2】【i3】 = a+(i1* m2 * m3 + i2 * m3 + i3) * l

n维数组:& ( a【i1】【i2】 … 【in】 ) = a +
( i1 * m2 * m3 * … * mn + i2 * m3 * m4 * … * mn+……+ in-1 * mn + in ) * l

特殊矩阵的压缩存储

非0元素或0元素的分布有一定规律的矩阵

对称矩阵

只保存对称矩阵的对角线和对角线以上 (下) 的元素,则称此为对称矩阵的压缩存储。

若只存对角线及对角线以上的元素,称为上三角矩阵;若只存对角线或对角线以下的元素,称之为下三角矩阵。

新的数组中共有n*(n+1)/2个元素

下三角矩阵

若i >= j a【i】【j】 = (i+1)*i/2+j

若i < j a【i】【j】 = a【j】【i】 = (j+1)*j/2+i

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9q5y3TWh-1631361137020)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106192313075.png)]

上三角矩阵

若i <= j a【i】【j】 = n+(n-1)+……+(n-i+1)+(j-i) = (2*n-i-1) * i/2+j

若i > j a【i】【j】 = a 【j】【i】 = (2*n-j-1) * j / 2 + i

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I8Lf1rbo-1631361137022)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106192234347.png)]

三对角矩阵

共有3*n-2个元素

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XjZ61juo-1631361137024)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106192728933.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-snBCQuub-1631361137026)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106192204900.png)]

a【i】【j】 = 2+3 * (i-1)+j-i +1 = 2 * i + j

若a【i】【j】在数组B中第k个位置

i = [k+1]/3

j = k-2*i

w对角矩阵

一个 w 对角矩阵是指主对角线两侧各有(w-1)/2条次对角线,其他位置都是零元素的矩阵,所以又称为带状矩阵(w为奇数)

(矩形->平行四边形)

如果把它的 w 条对角线元素按行优先方式存放到一个一维数组B中,为找到元素ai,j 在 B 中位置,一种简化处理是先把 w 条对角线上的元素压缩在一个 n*w 的二维数组 A’ 中, 让a’0,0 存放在B0,就可以简单地找到 ai,j 的存储位置了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kDQyocVN-1631361137027)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106194140567.png)]

注意:w对角矩阵二维数组转化为一维数组时不删去0

稀疏矩阵

设矩阵 A 中有 s 个非零元素。令 e = s/(m*n),称 e 为矩阵的稀疏因子。
有人认为 e≤0.05 时称之为稀疏矩阵。

每一个三元组 (i, j, aij) 唯一确定了矩阵A的一个非零元素。因此,稀疏矩阵可由表示非零元素的一系列三元组及其行列数唯一确定。

在三元组表中,行为主序,所有非零元素的三元组按行号递增的顺序排列;行号相等的按列号递增的顺序排序。

带行指针数组的二元组表

稀疏矩阵的三元组表可以用带行指针数组的二元组表代替。
在行指针数组中元素个数与矩阵行数相等。第 i 个元素的下标 i 代表矩阵的第 i 行,元素的内容即为稀疏矩阵第 i 行的第一个非零元素在二元组表中的存放位置。
二元组表中每个二元组只记录非零元素的列号和元素值,且各二元组按行号递增的顺序排列。
与三元组表相比,省去了重复的行号。

十字链表
稀疏矩阵的头节点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bYJLDNXk-1631361137029)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106195248705.png)]

head = true 是头结点的标识。
第 i 行与第 i 列共用一个头结点,用 next 链接。链表中按行列号顺序链接各行列的头结点。
right 指向该行链表首元结点的指针;down 指向该列链表首元结点的指针。
对链表扫描从头结点开始,最后以NULL结束。

稀疏矩阵的元素节点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2w1cgKZN-1631361137030)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106195558194.png)]

head = false是稀疏矩阵元素结点的标识。
row 和 col 是非零元素的行/列号,value 是该非零元素的值。
right 是在行链表中指向该行下一个非零元素结点的指针;down是在列链表中指向该列下一个非零元素结点的指针。
每一元素结点同时处于某行某列链表中。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e7qo5BDp-1631361137031)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106200041014.png)]

稀疏矩阵的转置

矩阵 A 的行成为矩阵 B 的列
矩阵 A 的列成为矩阵 B 的行

复杂度O(cols*terms)

设矩阵列数为 Cols,对矩阵三元组表扫描Cols 次。第 k 次检测列号为 k 的项。
第 k 次扫描找寻所有列号为 k 的项,将其行号变列号、列号变行号,连同该元素的值,顺次存于转置矩阵三元组表。

快速转置算法

快速转置的想法是:对原矩阵 a 扫描一遍,统计出每一列中相同列数的个数,按 a 中每一元素的列号,立即确定在转置矩阵 b 三元组表中的位置,并装入它。
为加速转置速度,建立两个辅助数组 rowSize 和 rowStart:
rowSize 记录矩阵转置前各列非零元素个数,转置后就是各行非零元素个数;
rowStart 记录转置后各行非零元素在转置三元组表中开始存放位置。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yCzMQc86-1631361137033)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106201157504.png)]

广义表

广义表是 n ( ≥0 ) 个表元素组成的有限序列,记作
LS (a1, a2, a3, …, an)
LS 是表名,ai 是表元素,可以是表(称为子表),可以是单元素(称为原子,不可再分)。

n为表的长度。n = 0 的广义表为空表。
n > 0时,表的第一个表元素称为广义表 的表头(head),除此之外,其它表元素组成的表称为广义表的表尾(tail)。

广义表的长度:最大括号里的逗号数+1

广义表的深度:每个元素的最大括号匹配数+1

空表长度为0,深度为1

广义表的第一个表元素即为该表的表头,除表头元素外其他表元素组成的表即为该表的表尾。

广义表的存储表示(头尾表示法)

除空表外,广义表可以分为表头、表尾两部分。表头可以是单元素,也可以是子表,但表尾一定是子表。因此,广义表的头尾表示有两种结点:

表结点。包括指向表头结点的指针hlink和指向表尾结点的指针tlink;

单元素结点。保存单元素数据值的data域。

每个结点有一个标志域tag。tag = 0,表示该结点是单元素结点;tag = 1,表示该结点是表结点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-15U1k0cV-1631361137035)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106203959598.png)]

空表没有结点,指向空表的头指针为空。

非空表的头指针指向一个表结点。该结点的hlink指针指向表头元素结点,tlink指向表尾(该表尾肯定还是表)。

如果有多个指针指向一个表结点,则出现共享情况;如果表中某元素是子表,其 hlink 又指向该表,则出现递归情况。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a95pYWoM-1631361137037)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106204325046.png)]

广义表的扩展线性链表表示(层级关系)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zvcmVV8i-1631361137038)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106204734749.png)]

单元素结点的标志 tag = 0,value 存放元素的值,tlink 存放指向同一层下一表元素结点的指针;

表结点的标志 tag = 1,hlink 存放指向子表的指针hlink,tlink 与单元素结点tlink的含义相同

与头尾表示相比,优点是每个广义表都有一个起到“头结点”作用的表结点,即使空表,也有一个表结点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ePwplEa-1631361137039)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106205016969.png)]

广义表的层次表示

在这种表示中有 3 种结点:原子结点、子表结点和头结点(非表头元素结点)。
头结点的作用是要简化插入和删除操作。如果插入或删除表头元素结点,有了头结点,就像带头结点的单链表,不必修改其他表中指向该表头的指针。
在表的头结点中存储该表的引用计数。如果要删除该链表,需要先查看引用计数,如果有多个链共享该链表,就不能删除它,只需将其引用计数减一。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AWS8VuV9-1631361137041)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106205349634.png)]

tag = 0时,存放的引用计数为除了自己本身,自身被其他表所调用的次数,特别的,自身调用自身的引用计数也要+1。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6tNnFN6y-1631361137042)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210106205525352.png)]

6.树与二叉树

树:自由树,有根树

自由树:一棵自由树 Tf 可定义为一个二元组
Tf = (V, E)

V是由n个元素组成的有限非空顶点集合,E是由n-1个序对的边集合。

有根树:r是一个特定的根结点,只有直接后继。根以外的其他结点划分为m个互不相交的有限集合T1,……,Tm,每个集合又是一棵树,称之为根的子树。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OlGjOJql-1631361137044)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210107203423639.png)]

树的特点

树是分层结构,又是递归结构。每棵子树的根结点有且仅有一个直接前趋,但可以有 0 个或多个直接后继。

术语

结点(node):包含数据元素的值及相关指针的存储单位。
结点的度(degree):结点所拥有的子树棵数。
叶结点(leaf):度为0的结点,又称终端结点。
分支结点(branch):除叶结点外的其他结点,又称为非终端结点或非叶结点。
子女(child):若结点 x 有子树,则子树的根结点即为结点 x 的子女。
双亲(parent):又称为父结点。若结点 x 有子女,它即为子女的双亲。

兄弟(sibling):同一双亲的子女互称为兄弟。
祖先(ancestor):从根结点到该结点所经分支上的所有结点。
子孙(descendant):某一结点的子女,以及这些子女的子女都是该结点的子孙。
结点间的路径(path):树中任一结点vi经过一系列结点v1, v2, …, vk到vj,其中(vi, v1), (v1, v2), …, (vk, vj)是树中的分支,则称vi, v1, v2, …, vk, vj是vi与vj间的路径。
结点的深度(depth):结点所处层次,即从根到该结点的路径上的分支数加一。根结点在第1层。

结点的深度和结点的高度是不同的。结点的深度即结点所处层次,是从根向下逐层计算的;结点的高度是从下向上逐层计算的:叶结点的高度为1, 其他结点的高度是取它的所有子女结点最大高度加一。
树的深度与高度相等。
树的深度按离根最远的叶结点算,树的高度按根结点算,都是6。
非叶结点包括根结点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xOwz60mQ-1631361137046)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210107204723118.png)]

树的度(degree):树中结点的度的最大值。
有序树(ordered tree):树中根结点的各棵子树T1, T2, …是有次序的,即为有序树。其中,T1叫做根的第1棵子树,T2叫做根的第2棵子树,…。
无序树:树中结点的各棵子树之间的次序是不重要的,可以互相交换位置。
森林(forest):m(m≥0)棵树的集合。在数据结构中,删去一棵非空树的根结点,树就变成森林(不排除空的森林);反之,若增加一个根结点,让森林中每一棵树的根结点都变成它的子女,森林就成为一棵树。

二叉树

一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根结点加上两棵分别称为左子树和右子树的、互不相交的二叉树组成。

二叉树的性质

①若二叉树的层次从 1 开始, 则在二叉树的第 i 层最多有 2^(i-1) 个结点。

②高度为 h 的二叉树最多有 2^h -1个结点。

空树的高度为 0,只有根结点的树的高度为 1。

③对任何一棵二叉树, 如果其叶结点有 n0 个, 度为2的非叶结点有 n2 个, 则有n0=n2+1

节点数量:n0+n1+n2

边数量:n1+2*n2

n0+n1+n2=n1+2*n2+1

满二叉树

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m56LeSp8-1631361137048)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210107205906703.png)]

完全二叉树

其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层从右向左连续缺若干结点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H5ciftZg-1631361137049)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210107205926451.png)]

④具有 n (n≥0) 个结点的完全二叉树的高度为[log2(n+1)]

​ 2^(h-1)-1<n ≤ 2^h-1

如将一棵有 n 个结点的完全二叉树自顶向下,同一层自左向右连续给结点编号: 0, 1, 2, …, n-1,则有以下关系:
若i = 0, 则 i 无双亲;
若i > 0, 则 i 的双亲为[(i-1)/2]。
若2i+1 < n, 则 i 的左子女为 2i+1;
若2i+2 < n, 则 i 的右子女为2i+2。
若 i 为偶数, 且i != 0, 则其左兄弟为i-1;
若 i 为奇数, 且i != n-1,则其右兄弟为i+1。

注意不是从1开始编号

完全二叉树的顺序存储表示

运用一维数组进行存储

对于一般二叉树,必须仿照完全二叉树对结点编号,即使有缺失也要编号,再按完全二叉树存储。

三元组表示形式

分支用三元组{p, c, d}描述,p是双亲数据,c 是子女数据,d 是分支方向,= 0 是左分支, = 1 是右分支。

二叉链表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TdR5cY5A-1631361137051)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210107212216680.png)]

三叉链表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ho7bt4di-1631361137052)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210107212236195.png)]

二叉树的遍历

访问根结点记作 V,
遍历根的左子树记作 L,
遍历根的右子树记作 R,

先序:VLR

中序:LVR

后序:LRV

void inorder(Tree &T)	// 中序遍历
{
    if(T != NULL)
    {
        inorder(T->lchild);
        printf("%d",T->data);
        inorder(T->rchild);
    }
}

void preorder(Tree &T)	// 先序遍历
{
    if(T != NULL)
    {
        printf("%d",T->data);
        Preorder(T->lchild);
        Preorder(T->rchild);
    }
}

void PostOrder(Tree &T)
{
    if(T != NULL)
    {
        PostOrder(T->lchild);
        PostOrder(T->rchild);
        printf("%d",T->data);
	}
}

表达式树的生成

按照运算符优先级对表达式加括号

每脱一层括号将表达式分为两部分:左子树和右子树

交换所有分支的左右子女
void Exchange(Tree &T)
{
    if(T != NULL && T->lchild != NULL && T->rchild != NULL)
    {
        Tree *s = t->lchild;
        t->lchild = t->rchild;
        t->rchild = s;
        Exchange(T->lchild);
        Exchange(T->rchild);
    }
}
求二叉树高度递归算法
int Height(Tree &T)
{
    if(T == NULL) return 0;
    else{
        int m = Height(t->lchild);
        int n = Height(t->rchild);
        return max(m,n)+1;
    }
}

?欧拉巡回

栈的先序遍历非递归算法:

从根节点开始,对一个节点,对其进行访问,进栈其右节点,左进只它的左节点

栈的中序遍历非递归方法:

从根节点开始,对一个结点,将其进栈,左进至它的左节点。

退栈时,进入它的右节点。

栈的后序遍历非递归算法

从根节点开始,对一个节点,一直向左进栈其左节点。退栈是,访问其父节点的右节点

二叉树的层次序遍历(队列)

层次序遍历从二叉树的根结点开始,自上向下,自左向右分层依次访问树中的各个结点。

二叉树的计数

由二叉树的先序序列和中序序列可唯一地确定一棵二叉树。

固定先序排列,选择所有可能的中序排列,可以构造出多少种不同的二叉树?

卡特兰数:1/(n+1)C(2n,n)

线索二叉树

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qpuHtW9e-1631361137054)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210107220712962.png)]

增加前趋Pred指针和后继Succ指针的二叉树

增设两个标志 ltag 和 rtag,指明指针是指示子女还是前趋/后继。后者称为线索。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WJhVHVW8-1631361137055)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210107220820408.png)]

ltag(或rtag) = 0 表示指针指示左子女

ltag(或rtag) = 1 表示相应指针为前趋或者后继线索

对于所有左指针指向空的节点:将该节点的左指针指线索二叉树:向该节点在中序遍历中的上一节点;对于所有右指针指向空的节点,将该节点的右指针指向该节点在中序遍历中的下一结点。

线索二叉树:对于所有左指针指向空的节点:将该节点的左指针指向该节点在中序遍历中的上一节点;对于所有右指针指向空的节点,将该节点的右指针指向该节点在中序遍历中的下一结点。

从左子树的最左子树依次访问:若rtag = 1则直接指向它的后继节点
否则,找到按照层次结构找到它右子树最左边节点(会经过其右子树)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-82WpEckY-1631361137056)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210107221825001.png)]

找中序遍历下的前趋

若ltag == 1 直接找到它的前趋

否则 找到左子树的最右结点

树与森林

双亲表示法

记录它的值和父节点

子女链表表示

记录它的值和它所有的孩子(单链表)

子女指针表示

等长的节点(树的度)

广义表表示

下图给出的树的广义表描述 A(B(E, F), C, D(G))。
子表的头结点是子树的根,其后链接它的所有子女。如果子女是叶结点(单元素或原子),结点中直接赋值,否则结点中是子表的头指针。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KRjr6UGJ-1631361137060)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210107222743019.png)]

子女-兄弟链表表示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Cz61SSG-1631361137061)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210107223037426.png)]

森林->二叉树

森林左节点为左儿子

右节点为最近的右兄弟

树的先根次序遍历

当树非空时
访问根结点
依次先根遍历根的各棵子树

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h0oOeV4f-1631361137062)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210107223550651.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YyT2UF6s-1631361137064)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210107223812605.png)]

为ABEFCDG

树的先根遍历可以借助对应二叉树的先序遍历算法实现

树的后根遍历各棵子树

当树非空时
依次后根遍历根的各棵子树
访问根结点

如上图:EFBCGDA

对应二叉树的中序遍历

广度优先(层次次序遍历)

一层一层逐步遍历(从左到右,从上到下)

森林->二叉树(长子兄弟法)

二叉树的左节点为长子,右节点为兄弟

森林的先根次序遍历

一颗一颗树遍历,对应二叉树先序遍历结果

森林的中根次序遍历

从每个节点的子数森林进行访问,相当于二叉树的中序遍历

森林的广度优先遍历

一层一层遍历

从根,到根节点的所有子女。

7.树与二叉树的应用

Huffman树

路径长度

两个结点之间的路径长度 PL 是连接两结点的路径上的分支数。

树的路径长度是各结点到根结点的路径长度之和PL。

带权路径长度

二叉树的带权路径长度是各叶结点所带权值 wi 与该结点到根的路径长度 li 的乘积的和。

带权路径长度达到最小的二叉树即为Huffman树。
在Huffman树中,权值大的结点离根最近

Huffman树构造算法

①在 F 中选取两棵根结点权值最小的二叉树, 做为左、右子树构造一棵新的二叉树。置新的二叉树的根结点的权值为其左、右子树上根结点的权值之和。
②在 F 中删去这两棵二叉树。
③把新的二叉树加入 F。

Huffman树的叶结点又称为外结点,分支结点又称为内结点。外结点是结果,内结点是过程。
Huffman树是严格二叉树。有 n 个外结点,就有 n-1 个内结点,表示需要构造 n-1 次二叉树。树中总结点数为2n-1。
Huffman算法每次选根结点权值最小的子树来构造新二叉树时,未明确规定谁做左子树,谁做右子树,所以构造出来的Huffman树可能不惟一。
Huffman树的最小带权路径长度是惟一的。

Huffman编码

左子树为0,右子树为1。(变长编码)

最佳判定树

①初始排列

②相邻结点权值相加,取其和最小者构造二叉树,注意不要打乱原来的排列

③重复上一步,直到构成一棵树为止

设有一个关键码集合,按完全二叉树的顺序存储方式存放在一个一维数组中。对它们从根开始,自顶向下,同一层自左向右从 0 开始连续编号。若满足
Ki <=K 2i+1 && Ki <= K 2i+2
或 Ki <= K 2i+1 && Ki <= K 2i+2,
则称该关键码集合构成一个堆。
前者称为小根堆,后者称为大根堆。

左右节点无明确大小关系

插入

堆尾插入新元素,沿通向根的路径向上调整

若比父节点小,则交换

删除

删除节点用堆尾元素去补

对比左右结点,将左右节点的比它小的较小值与其进行交换。

二叉查找树

二叉查找树又称为二叉排序树,它或者是一棵空树,或者是具有下列性质的二叉树:
每个结点都有一个作为查找依据的关键码(key),所有结点的关键码互不相同。
左子树(如果非空)上所有结点的关键码都小于根结点的关键码。
右子树(如果非空)上所有结点的关键码都大于根结点的关键码。
左子树和右子树也是二叉查找树。

中序遍历下时从小到大的

PPT45(充分必要)

查找

如果给定值等于根结点的关键码值,则查找成功。
如果给定值小于根结点的关键码值,则继续递归查找根结点的左子树;
否则。递归查找根结点的右子树。

查找成功时检测指针停留在树中某个结点。

查找不成功时检测指针停留在某个失败结点。

查找的关键码比较次数最多不超过树的高度。

插入

先进行查找

查找成功:树中已有这个元素,不再插入。
查找不成功:树中原来没有关键码等于给定值的结点,把新元素加到查找操作停止的地方。

删除

①被删结点的右子树为空,可以拿它的左子女结点顶替它的位置,再释放它。
②被删结点的左子树为空,可以拿它的右子女结点顶替它的位置,再释放它。
③被删结点的左、右子树都不为空,可以在它的右子树中寻找中序下的第一个结点(所有比被删关键码大的关键码中它的值最小),用它的值填补到被删结点中,再来处理这个结点的删除问题。当然,也可以到它的左子树中寻找中序下的最后一个结点。

性能分析

不同排列,构成不同二叉查找树1/(n+1)C(2n,n)

查找成功的平均查找长度ASL

内结点的权值p[i] 与查找该节点时所需的关键码比较次数c[i]乘积之和

查找不成功的平均查找长度ASL

外结点的权值q[j]和所需关键码比较次数c[j](l[j]-1)乘积之和

图(b)的情形所得的平均查找长度最小。一般把平均查找长度达到最小的判定树称作最优二叉查找树。

在相等查找概率的情形下,最优二叉查找树的上面 h-1(h是高度)层都是满的,只有第 h 层不满。如果结点集中在该层的左边,则它是完全二叉树;如果结点散落在该层各个地方,则有人称之为理想平衡树。

AVL树

一棵AVL树又称为高度平衡的二叉查找树

它或者是空树,或者是具有下列性质的二叉查找树:它的左子树和右子树都是AVL树,且左子树和右子树的高度之差的绝对值不超过1。

给出该结点左子树的高度减去右子树的高度所得的高度差,这个数字即为结点的平衡因子 bf:-1,0,1

平衡化旋转

单旋转 (LL旋转和RR旋转)
双旋转 (LR旋转和RL旋转)

每当插入一个新节点后,从插入位置沿通向根的路径回溯,检查各结点的平衡因子。

如果在某一结点发现高度不平衡,停止回溯。从发生不平衡的结点起,沿刚才回溯的路径取直接下两层的结点。
如果这三个结点处于一条直线上,则采用单旋转进行平衡化。单旋转可按其方向分为LL旋转和RR旋转, 其中一个是另一 个的镜像,其方向与不平衡的形状相关。
如果这三个结点处于一条折线上,则采用双旋转进行平衡化。双旋转分为LR旋转和RL旋转两类。

左单旋转(RR单旋)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lRTA9Pmk-1631361137071)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210108213933863.png)]

右单旋转(LL单旋)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-flEFm2Et-1631361137072)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210108214025000.png)]

先左后右双旋(LR双旋)

先父亲结点,再父亲的父亲结点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FJs8DQHG-1631361137073)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210108214642412.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qHKFJpaR-1631361137074)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210108214658089.png)]

先左后右双旋(RL双旋)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YiSn1nco-1631361137075)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210108214711228.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VVu1YxT9-1631361137076)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210108214728087.png)]

插入

在插入新结点后,需从插入结点沿通向根的路径向上回溯,如果发现有不平衡的结点,需从这个结点出发,使用平衡旋转方法进行平衡化处理。

①结点pr的平衡因子为0。说明刚才是在 pr 的较矮的子树上插入了新结点,此时不需做平衡化处理,返回主程序。子树的高度不变。

②结点pr的平衡因子的绝对值 |bf| = 1。说明插入前pr的平衡因子是0,插入新结点后,以pr为根的子树不需平衡化旋转。但该子树高度增加,

③结点pr的平衡因子的绝对值|bf| = 2。说明新结点在较高的子树上插入,造成了不平衡,需要做平衡化旋转。

若平衡因子同号:单旋

若平衡因子异号:双旋

删除

如果被删结点x最多只有一个子女:

将结点x从树中删去。
因为结点x最多有一个子女,可以简单地把x的双亲结点中原来指向结点x的指针改指到这个子女结点;
如果结点x没有子女,x双亲结点的相应指针置为NULL。
将原来以结点x为根的子树的高度减1。

如果被删结点x有两个子女:

查找结点x在中序次序下的直接前驱结点y (同样可以找直接后继)。
把结点y的内容传送给结点x,现在问题转移到删除结点 y。把结点y当作被删结点x。
因为结点y最多有一个子女,我们可以简单地用1.给出的方法进行删除。

在执行结点x的删除之后,需要从结点x开始,沿通向根的路径反向追踪高度的变化对路径上各个结点的影响。

同号或0:单旋

异号:双旋

(调整可能不止一次)

高度

设在新结点插入前AVL树的高度为h,结点个数为n,则插入一个新结点,其时间代价是O(h)。

设 N h 是高度为 h 的AVL树的最小结点个数。根的一棵子树的高度为h-1,另一棵子树的高度为h-2,这两棵子树也是高度平衡的。

N0 = 0 (空树)
N1 = 1 (仅有根结点)
N h = N h-1 + N h-2 +1 , h > 1

如果高度 h 固定,最少结点数为Nh;最多结点数为2h – 1,即满二叉树情形。

并查集

双亲表示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k5zrg7rc-1631361137078)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210108221447297.png)]

find 查找集合元素的根

union 合并

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Eq4cBTBa-1631361137079)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210108222243647.png)]

?按高度查找,压缩元素的查找路径

8.图

图是由顶点集合(vertex)及顶点间的关系集合组成的一种数据结构。

概念

有向图与无向图

完全图

有向图:n*(n-1)

无向图:n*(n-1)/2

邻接顶点

子图

顶点的度(入度,出度)

路径

路径长度(加权图)

简单路径

回路

连通图与连通分量

强连通图与强连通分量

生成树

图的存储表示

邻接矩阵

稀疏图(边数e,顶点个数n,e远远小于n^2)稠密图

加权图的邻接矩阵

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CdnOoQpF-1631361137080)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210108223845611.png)]

邻接表

无向图:n个顶点结点,2e个边结点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ywrDDzZ2-1631361137081)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210108223946381.png)]

有向图:出边表和入边表。(只考虑其中一个表时)n个顶点结点,e个边结点

网络的邻接表:比有向图多一个权值域

邻接多重表
无向图

边结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qfoCNBJB-1631361137082)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210108224652852.png)]

其中, mark 是处理标记; vertex1和vertex2是该边两顶点位置。Path1 指向下一条依附 vertex1的边;path2 指向下一条依附 vertex2 的边。

对于带权图还需设置一个存放与该边相关的权值的域 cost。

顶点结点的结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ed7MOtvS-1631361137083)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210108224737915.png)]

存储顶点信息的结点表以顺序表方式组织,每一个顶点结点有两个数据成员:其中,data 存放与该顶点相关的信息,Firstout 是指示第一条依附该顶点的边的指针。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xZUHqeIz-1631361137084)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210108224936316.png)]

有向图

边结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YAW4xNGf-1631361137085)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210108225021358.png)]

其中,mark 是处理标记;vertex1 和 vertex2指明该有向边始顶点和终顶点的位置。nextout指向同一顶点发出的下一条边的边结点;nextin 指向进入同一顶点的下一条边的边结点。
需要时还可有权值域 cost。

顶点结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6o1i5ayN-1631361137086)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210108225116926.png)]

每个顶点有一个结点,它相当于出边表和入边表的头结点:其中,数据成员 data 存放与该顶点相关的信息,指针 Firstout 指示以该顶点为始顶点的出边表的第一条边,Firstin 指示以该顶点为终顶点的入边表的第一条边。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HPzTw6je-1631361137087)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210108225141465.png)]

图的遍历与连通性

DFS(深度优先搜索)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WlO7Zw5F-1631361137088)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210110085224583.png)]

深度优先搜索算法在访问图中某一起始顶点 v 后, 由 v 出发, 访问它的任一邻接顶点 w1; 再从 w1 出发,访问与 w1邻 接但还没有访问过的顶点 w2; 然后再从 w2 出发, 进行类似的访问, … 如此进行下去, 直至所有的邻接顶点都被访问过的顶点 u 为止。
接着, 退回一步, 退到前一次刚访问过的顶点, 看是否还有其它没有被访问的邻接顶点。如果有, 则访问此顶点, 之后再从此顶点出发, 进行与前述类似的访问; 如果没有, 就再退回一步进行搜索。
重复上述过程, 直到连通图中所有顶点都被访问过为止。

BFS(广度优先搜索)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PE1DsnUl-1631361137089)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210110085245147.png)]

BFS在访问了起始顶点 v 之后, 由 v 出发,依次访问 v 的各个未被访问过的邻接顶点 w1, w2, …, wt, 然后再顺序访问 w1, w2, …, wt 的所有还未被访问过的邻接顶点。再从这些访问过的顶点出发,再访问它们的所有还未被访问过的邻接顶点, … 如此做下去,直到图中所有顶点都被访问到为止。
深度优先搜索是一种回溯的算法,而广度优先搜索不是,它是一种分层的顺序搜索过程,每向前走一步可能访问一批顶点。因此,广度优先搜索不是一个递归的过程。

求连通分量的算法

对图的每一个顶点进行检测:若已被访问过,则该顶点一定是落在图中已求得的连通分量上;若还未被访问,则从该顶点出发遍历图,可求得图的另一个连通分量。

求强连通分量

①首先对图进行一次DFS,在回退时记忆对结点回溯的顺序

②把图的所有的有向边逆转

③再对得到的图沿回溯顺序 EDCFBAIJHG 从编号最高的 G 开始,再进行一次 DFS,所得到的深度优先森林(树)即为强连通分量的划分。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xePCWA68-1631361137090)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210110090243045.png)]

双连通分量

在无向连通图 G 中, 当且仅当删去 G 中的顶点 v及所有依附于 v 的所有边后, 可将图分割成两个或两个以上的连通分量,则称顶点 v 为关节点。

没有关节点的连通图叫做双连通图(重连通图)。

深度优先生成树上找关节点:

①深度优先生成树的根是关节点的充要条件是它至少有两个子女。

②叶结点不是关节点。

③若一个顶点u的每一个子孙v都可以通过一条不经过u的路径访问到u的某一祖先,则u不为关节点

在双连通图上,任何一对顶点之间至少存在有两条路径,在删去某个顶点及与该顶点相关联的边时,也不破坏图的连通性。
因此,在非双连通图上,找到其深度优先生成树中的叶结点(其度为 1),用最少的连线把叶结点与其祖先的某结点(其度最好为1)(兄弟不可)连接起来,就能消除非双连通图中的关节点,形成双连通图。

最小生成树

必须使用且仅使用该带权图中的n-1 条边来联结网络中的 n 个顶点;
不能使用产生回路的边;
各边上的权值的总和达到最小。

Kruskal算法

根据边权值从小到大找,若形成回路则舍去此边,直到找到n-1条为止

Prim算法

根据起始顶点开始,找到权值最小的一条边,并将此边删除。每一次都在一个已经选中过的顶点和一个未选中的顶点之间找到一个权值最小的边,直到有n个顶点,n-1条边为止

?破圈法等

最短路径算法

Dijkstra算法

给定一个带权有向图 D 与源点 v,求从 v 到 D 中其它顶点的最短路径。限定各边上的权值大于或等于0。

开始时以最初的起点初始化距离数组

每次找到距离数组中最小的路径,以其终点为新的起点,更新那个距离数组

?多源最短路径

拓扑排序

从度为0的顶点开始进行删除,同时删除其所有边,直到所有顶点都遍历

★关键路径

事件Vi 的最早可能开始时间Ve(i)

它是从开始点V1 到顶点Vi 的最长路径长度。

事件Vi 的最迟允许开始时间Vl[i]

它是在保证结束点Vn 在Ve[n] 时刻完成的前提下,事件Vi 的允许的最迟开始时间。

活动ak 的最早可能开始时间 e[k]

设活动ak 在边<Vi , Vj>上, 则e[k]是从开始点V1到顶点Vi 的最长路径长度。因此e[k] = Ve[i]。

活动ak 的最迟允许开始时间 l[k]

它是在不会引起时间延误的前提下,该活动允许的最迟开始时间。
l[k] = Vl[j] - dur(<i, j>)。
其中,dur(<i, j>)是完成 ak 所需的时间。

时间余量 l[k] - e[k]

​ 表示活动 ak 的最早可能开始时间和最迟允许开始时间的时间余量。l[k] == e[k] 表示活动 ak 是没有时间余量的关键活动。
为找出关键活动,需要求各个活动的 e[k] 与 l[k],以判别是否 l[k] == e[k]。

Ve[1] = 0 递推Ve[i] = max(Ve[j]+dur(vj,vi))

Vl[n] = Ve[n] 递推Vl[i] = min(vl[j],dur(vj,vi))

e[k] = Ve[i]

l[k] = Vl[j] - dur(<Vi , Vj >)

e[k] = l[k]则是关键节点

9.查找

顺序查找

监视哨(无序)

查找成功:1/n*n * (n+1)/2 = (n+1) / 2

查找不成功:n+1

有序表

不成功:1/(n+1)*(n+n * (n+1)/2)

折半查找

注意:小于等于

mid向下取整

int left = 0, right = L.n-1, mid;
while ( left <= right ) {
    mid = ( left + right ) / 2;  is = mid;
    if ( x == L.data[mid] ) return mid;    //查找成功
    else {
        if ( x > L.data[mid] ) left = mid+1; //右缩查找区间
        else right = mid-1;		     //左缩查找区间
    }
}
is = left;  return -1;

性能分析

注意:查找成功n个,查找不成功n+1个,且都在最后一排和倒数第二排

静态查找树

每次的子树的根为ki,满足

{k1,k2,……k n-1, kn} | k1~k i-1 - k i+1 ~ kn | 之差最小

进而逐步构造树

B树

查找平均长度:查找子表的平均查找长度+子表内平均查找长度

m路查找树

每一个节点都有m个子树,数据在最后一层,其他都是索引

B树

一棵 m 阶 B 树是一棵平衡的 m 路查找树,它或者是空树,或者是满足下列性质的树:
除失败结点外,所有结点最多有 m 棵子树;
根结点至少有 2 个子女;
除根结点和失败结点外,所有结点至少有 【m/2】+1 个子女。
所有的失败结点都位于同一层,它们是虚结点,是当查找值 x 不在树中时才能到达的结点。指向这些结点的指针为空。

B树每个节点关键码个数[[m/2],m-1]

插入

插入时若超过m-1,则以【m/2】+1为基准分裂

自底向上分裂节点,进行调整

删除

叶结点删除:

若能删,不造成影响直接删

不能删,优先找左右兄弟借,双亲结点下移,兄弟节点上移

若不能借,找相邻右兄弟结合,再找左兄弟。

非叶结点删除:

找中序遍历下个节点替代,进而调整

B+树

子树中多一个自己本身

散列函数

把不同的关键码映射到同一个散列地址上

散列函数的定义域必须包括需要存储的全部 关键码, 如果散列表允许有 m 个地址时,其 值域必须在 0 到 m-1 之间。

散列函数计算出来的地址应能均匀分布在整个地址空间中

除留余数法

hash (key) = key % p p <= m

取一个不大于 m,但最接近于或等于 m 的质数 p 作为除数

处理冲突

开地址法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yAnAWXWP-1631361137092)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210110144044819.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aa2uTGv8-1631361137093)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210110144105790.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kA0J4Q9r-1631361137094)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210110144119607.png)]

但在存放时发现此地址已被另一个表项 R1 占据, 发生了冲突。为此, 需把 R2 存放到表中“下一个”空位中。

因为取模,所以是从左到右循环

成功概率是以正确元素来算的

失败概率是以格子数量来算的

链地址法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rLbc2d3i-1631361137095)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210110143927195.png)]

装填因子

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y97Sb8aw-1631361137096)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210110144556477.png)]

上面链地址法中为8/10

10.排序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lESigqui-1631361137098)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210110144833355.png)]

排序码比较次数

不受排序码初始排列影响的方法是:
折半插入排序(O(nlog2n))
简单选择排序(O(n2))
两路归并排序(O(nlog2n))
堆排序( O(nlog2n) )
锦标赛排序( O(nlog2n) )
其他排序方法受排序码初始排列影响。
直接插入排序(O(n)~O(n2))
快速排序( O(nlog2n)~O(n2) )
起泡排序(O(n)~O(n2))

元素移动次数

不受排序码初始排列影响的方法是:
两路归并排序(O(nlog2n))
堆排序( O(nlog2n) )
表排序(0)
锦标赛排序(0)
其他排序方法受排序码初始排列影响。
直接插入排序(0~O(n2))
折半插入排序(0~O(n2) )
起泡排序(0~O(n2))
快速排序( O(nlog2n)~O(n2) )
简单选择排序(0~O(n) )

附加空间达到O(1)的排序方法属于原地排序

直接插入排序
折半插入排序
希尔排序
起泡排序
简单选择排序
堆排序

不稳定的排序方法

希尔排序(缩小增量)
简单选择排序(每次选择最小的)
快速排序(双指针向中间指)
堆排序(大根堆,每次删除根)

稳定的排序算法

直接插入排序(打牌不断插入)
折半插入排序(插入时折半查找)
起泡排序(把最大的往后沉)
锦标赛排序(淘汰赛,外结点待排序,内结点胜者结点号,每次比完一个胜者,将其设为无穷大)
归并排序(两个有序表的合成)
表排序

快速排序

任取待排序记录序列中的某个记录 (例如取第一个记录) 作为基准, 按照该记录的排序码值的大小, 将整个记录序列划分为左右两个子序列:
左侧子序列中所有记录的排序码值都小于或等于基准记录的排序码值;
右侧子序列中所有记录的排序码值都大于基准记录的排序码值。

int Partition ( DataList& L, int low, int high ) {
    int i = low, j = high;
    DataType pivot = L.data[low];    //基准元素
    while ( i < j ) {			    //扫描整个序列
        while ( i < j && L.data[j] >= pivot ) j--;
			//反向检测到排序码小于基准的元素
        if ( i < j ) {
            L.data[i] = L.data[j];  i++;
			//把小于基准的元素移到左边去
            while ( i < j && L.data[i] <= pivot ) i++;
			//正向检测到排序码大于基准的元素
 if ( i < j ) { L.data[j] = L.data[i];  j--; }
			//把大于基准的元素移到右边去
        } // end if ( i < j )
	} // end while( i < j )	
	L.data[i] = pivot;  return i;	//将基准元素就位	
}  

基数排序

多排序码排序(分配,收集)
最高位优先

从最高位一位一位连成串

最低位优先

k1,k2,……k n-1, kn} | k1~k i-1 - k i+1 ~ kn | 之差最小

进而逐步构造树

B树

查找平均长度:查找子表的平均查找长度+子表内平均查找长度

m路查找树

每一个节点都有m个子树,数据在最后一层,其他都是索引

B树

一棵 m 阶 B 树是一棵平衡的 m 路查找树,它或者是空树,或者是满足下列性质的树:
除失败结点外,所有结点最多有 m 棵子树;
根结点至少有 2 个子女;
除根结点和失败结点外,所有结点至少有 【m/2】+1 个子女。
所有的失败结点都位于同一层,它们是虚结点,是当查找值 x 不在树中时才能到达的结点。指向这些结点的指针为空。

B树每个节点关键码个数[[m/2],m-1]

插入

插入时若超过m-1,则以【m/2】+1为基准分裂

自底向上分裂节点,进行调整

删除

叶结点删除:

若能删,不造成影响直接删

不能删,优先找左右兄弟借,双亲结点下移,兄弟节点上移

若不能借,找相邻右兄弟结合,再找左兄弟。

非叶结点删除:

找中序遍历下个节点替代,进而调整

B+树

子树中多一个自己本身

散列函数

把不同的关键码映射到同一个散列地址上

散列函数的定义域必须包括需要存储的全部 关键码, 如果散列表允许有 m 个地址时,其 值域必须在 0 到 m-1 之间。

散列函数计算出来的地址应能均匀分布在整个地址空间中

除留余数法

hash (key) = key % p p <= m

取一个不大于 m,但最接近于或等于 m 的质数 p 作为除数

处理冲突

开地址法

[外链图片转存中…(img-yAnAWXWP-1631361137092)]

[外链图片转存中…(img-aa2uTGv8-1631361137093)]

[外链图片转存中…(img-kA0J4Q9r-1631361137094)]

但在存放时发现此地址已被另一个表项 R1 占据, 发生了冲突。为此, 需把 R2 存放到表中“下一个”空位中。

因为取模,所以是从左到右循环

成功概率是以正确元素来算的

失败概率是以格子数量来算的

链地址法

[外链图片转存中…(img-rLbc2d3i-1631361137095)]

装填因子

[外链图片转存中…(img-y97Sb8aw-1631361137096)]

上面链地址法中为8/10

10.排序

[外链图片转存中…(img-lESigqui-1631361137098)]

排序码比较次数

不受排序码初始排列影响的方法是:
折半插入排序(O(nlog2n))
简单选择排序(O(n2))
两路归并排序(O(nlog2n))
堆排序( O(nlog2n) )
锦标赛排序( O(nlog2n) )
其他排序方法受排序码初始排列影响。
直接插入排序(O(n)~O(n2))
快速排序( O(nlog2n)~O(n2) )
起泡排序(O(n)~O(n2))

元素移动次数

不受排序码初始排列影响的方法是:
两路归并排序(O(nlog2n))
堆排序( O(nlog2n) )
表排序(0)
锦标赛排序(0)
其他排序方法受排序码初始排列影响。
直接插入排序(0~O(n2))
折半插入排序(0~O(n2) )
起泡排序(0~O(n2))
快速排序( O(nlog2n)~O(n2) )
简单选择排序(0~O(n) )

附加空间达到O(1)的排序方法属于原地排序

直接插入排序
折半插入排序
希尔排序
起泡排序
简单选择排序
堆排序

不稳定的排序方法

希尔排序(缩小增量)
简单选择排序(每次选择最小的)
快速排序(双指针向中间指)
堆排序(大根堆,每次删除根)

稳定的排序算法

直接插入排序(打牌不断插入)
折半插入排序(插入时折半查找)
起泡排序(把最大的往后沉)
锦标赛排序(淘汰赛,外结点待排序,内结点胜者结点号,每次比完一个胜者,将其设为无穷大)
归并排序(两个有序表的合成)
表排序

快速排序

任取待排序记录序列中的某个记录 (例如取第一个记录) 作为基准, 按照该记录的排序码值的大小, 将整个记录序列划分为左右两个子序列:
左侧子序列中所有记录的排序码值都小于或等于基准记录的排序码值;
右侧子序列中所有记录的排序码值都大于基准记录的排序码值。

int Partition ( DataList& L, int low, int high ) {
    int i = low, j = high;
    DataType pivot = L.data[low];    //基准元素
    while ( i < j ) {			    //扫描整个序列
        while ( i < j && L.data[j] >= pivot ) j--;
			//反向检测到排序码小于基准的元素
        if ( i < j ) {
            L.data[i] = L.data[j];  i++;
			//把小于基准的元素移到左边去
            while ( i < j && L.data[i] <= pivot ) i++;
			//正向检测到排序码大于基准的元素
 if ( i < j ) { L.data[j] = L.data[i];  j--; }
			//把大于基准的元素移到右边去
        } // end if ( i < j )
	} // end while( i < j )	
	L.data[i] = pivot;  return i;	//将基准元素就位	
}  

基数排序

多排序码排序(分配,收集)
最高位优先

从最高位一位一位连成串

最低位优先

从最低位开始一位一位连成串

标签:结点,北师大,img,转存,期末考试,外链,数据结构,防盗链,图片
来源: https://blog.csdn.net/weixin_45360119/article/details/120242276

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有