数据结构复习资料亲自整理.docx

上传人:b****7 文档编号:9838803 上传时间:2023-02-07 格式:DOCX 页数:35 大小:924.26KB
下载 相关 举报
数据结构复习资料亲自整理.docx_第1页
第1页 / 共35页
数据结构复习资料亲自整理.docx_第2页
第2页 / 共35页
数据结构复习资料亲自整理.docx_第3页
第3页 / 共35页
数据结构复习资料亲自整理.docx_第4页
第4页 / 共35页
数据结构复习资料亲自整理.docx_第5页
第5页 / 共35页
点击查看更多>>
下载资源
资源描述

数据结构复习资料亲自整理.docx

《数据结构复习资料亲自整理.docx》由会员分享,可在线阅读,更多相关《数据结构复习资料亲自整理.docx(35页珍藏版)》请在冰豆网上搜索。

数据结构复习资料亲自整理.docx

数据结构复习资料亲自整理

一、简答题

1、链表:

链表就是一串存储数据的链式结构。

链式的优点在于,每个数据之间都是相关联的。

2、线性结构:

线性结构是一个有序数据元素的集合。

常用的线性结构有:

线性表,栈,队列,双队列,数组,串。

3、树与二叉树

二叉树是每个结点最多有两个子树的有序树;

树是由n(n>=1)个有限节点组成一个具有层次关系的集合。

树和二叉树的2个主要差别:

1.树中结点的最大度数没有限制,而二叉树结点的最大度数为2;

  2.树的结点无左、右之分,而二叉树的结点有左、右之分。

4、堆

堆通常是一个可以被看做一棵树的数组对象。

堆总是满足下列性质:

堆中某个节点的值总是不大于或不小于其父节点的值;

堆总是一棵完全二叉树。

5、二叉排序树

二叉排序数的(递归)定义:

1、若左子树非空,则左子树所有节点的值均小于它的根节点;2、若右子树非空,则右子树所有节点的值均大于于它的根节点;3、左右子树也分别为二叉排序树。

二、应用题

1、树与二叉树

1前中后序遍历序列

一、已知前序、中序遍历,求后序遍历

例:

前序遍历:

GDAFEMHZ中序遍历:

ADEFGHMZ

画树求法:

第一步,根据前序遍历的特点,我们知道根结点为G

第二步,观察中序遍历ADEFGHMZ。

其中root节点G左侧的ADEF必然是root的左子树,G右侧的HMZ必然是root的右子树。

第三步,观察左子树ADEF,左子树的中的根节点必然是大树的root的leftchild。

在前序遍历中,大树的root的leftchild位于root之后,所以左子树的根节点为D。

第四步,同样的道理,root的右子树节点HMZ中的根节点也可以通过前序遍历求得。

在前序遍历中,一定是先把root和root的所有左子树节点遍历完之后才会遍历右子树,并且遍历的左子树的第一个节点就是左子树的根节点。

同理,遍历的右子树的第一个节点就是右子树的根节点。

2树与二叉树的转换

树转换为二叉树:

二叉树转换为树:

3二叉树线索化

注意:

  图中的实线表示指针,虚线表示线索。

  结点C的左线索为空,表示C是中序序列的开始结点,无前趋;

  结点E的右线索为空,表示E是中序序列的终端结点,无后继。

  线索二叉树中,一个结点是叶结点的充要条件为:

左、右标志均是1。

2、图

1邻接表

一、邻接表

邻接表是图的一种链式存储结构。

邻接表中,对图中每个顶点建立一个单链表,第i个单链表中的结点表示依附于顶点Vi的边(对有向图是以顶点Vi为尾的弧)。

邻接表中的表结点和头结点结构:

表结点

adjvex

nextarc

info

头结点

data

firstarc

二、无向图的邻接表

3、

4、图7-5

三、有向图的邻接表和逆邻接表

(一)在有向图的邻接表中,第i个单链表链接的边都是顶点i发出的边。

(二)为了求第i个顶点的入度,需要遍历整个邻接表。

因此可以建立逆邻接表。

(三)在有向图的逆邻接表中,第i个单链表链接的边都是进入顶点i的边。

  

            

四、邻接表小结

◆ 设图中有n个顶点,e条边,则用邻接表表示无向图时,需要n个顶点结点,2e个表结点;用邻接表表示有向图时,若不考虑逆邻接表,只需n个顶点结点,e个边结点。

◆ 在无向图的邻接表中,顶点vi的度恰为第i个链表中的结点数。

◆ 在有向图中,第i个链表中的结点个数只是顶点vi的出度。

在逆邻接表中的第i个链表中的结点个数为vi的入度。

2邻接矩阵(有向、无向)

1.图的邻接矩阵表示法

 在图的邻接矩阵表示法中:

 ①用邻接矩阵表示顶点间的相邻关系

 ②用一个顺序表来存储顶点信息

2.图的邻接矩阵(AdacencyMatrix)

 设G=(V,E)是具有n个顶点的图,则G的邻接矩阵是具有如下性质的n阶方阵:

【例】下图中无向图G5和有向图G6的邻接矩阵分别为Al和A2。

3广度优先遍历

广度优先遍历是连通图的一种遍历策略。

其基本思想如下:

1、从图中某个顶点V0出发,并访问此顶点;

2、从V0出发,访问V0的各个未曾访问的邻接点W1,W2,…,Wk;然后,依次从W1,W2,…,Wk出发访问各自未被访问的邻接点;

3、重复步骤2,直到全部顶点都被访问为止。

例如下图中:

1.从0开始,首先找到0的关联顶点3,4

2.由3出发,找到1,2;由4出发,找到1,但是1已经遍历过,所以忽略。

3.由1出发,没有关联顶点;由2出发,没有关联顶点。

所以最后顺序是0,3,4,1,2

4深度优先遍历

深度优先遍历是连通图的一种遍历策略。

其基本思想如下:

设x是当前被访问顶点,在对x做过访问标记后,选择一条从x出发的未检测过的边(x,y)。

若发现顶点y已访问过,则重新选择另一条从x出发的未检测过的边,否则沿边(x,y)到达未曾访问过的y,对y访问并将其标记为已访问过;然后从y开始搜索,直到搜索完从y出发的所有路径,即访问完所有从y出发可达的顶点之后,才回溯到顶点x,并且再选择一条从x出发的未检测过的边。

上述过程直至从x出发的所有边都已检测过为止。

例如下图中:

1.从0开始,首先找到0的关联顶点3

2.由3出发,找到1;由1出发,没有关联的顶点。

3.回到3,从3出发,找到2;由2出发,没有关联的顶点。

4.回到4,出4出发,找到1,因为1已经被访问过了,所以不访问。

所以最后顺序是0,3,1,2,4

⑤Prim算法

基本思想:

假设G=(V,E)是连通的,TE是G上最小生成树中边的集合。

算法从U={u0}(u0∈V)、TE={}开始。

重复执行下列操作:

在所有u∈U,v∈V-U的边(u,v)∈E中找一条权值最小的边(u0,v0)并入集合TE中,同时v0并入U,直到V=U为止。

此时,TE中必有n-1条边,T=(V,TE)为G的最小生成树。

Prim算法的核心:

始终保持TE中的边集构成一棵生成树。

注意:

prim算法适合稠密图,其时间复杂度为O(n^2),其时间复杂度与边得数目无关,而kruskal算法的时间复杂度为O(eloge)跟边的数目有关,适合稀疏图。

⑥Krusal算法

图中先将每个顶点看作独立的子图,然后查找最小权值边,这条边是有限制条件的,边得两个顶点必须不在同一个图中,如上图,第一个图中找到最小权值边为(v1,v3),且满足限制条件,继续查找到边(v4,v6),(v2,v5),(v3,v6),当查找到最后一条边时,仅仅只有(v2,v3)满足限制条件,其他的如(v3,v4),(v1,v4)都在一个子图里面,不满足条件,至此已经找到最小生成树的所有边。

⑦拓扑排序

由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。

对上图进行拓扑排序的结果:

2->8->0->3->7->1->5->6->9->4->11->10->12

5、检索

1二叉排序建立

typedefstructnode

{

intdata;

structnode*lchild;

structnode*rchild;

}node;

voidInit(node*t)

{

t=NULL;

}

voidInOrder(node*t)//中序遍历输出

{

if(t!

=NULL)

{

InOrder(t->lchild);

printf("%d",t->data);

InOrder(t->rchild);

}

}

2二叉排序删除

btree*DelNode(btree*p)

{

if(p->lchild)

{

btree*r=p->lchild;//r指向其左子树;

btree*prer=p->lchild;//prer指向其左子树;

while(r->rchild!

=NULL)//搜索左子树的最右边的叶子结点r

{

prer=r;

r=r->rchild;

}

p->data=r->data;

if(prer!

=r)//若r不是p的左孩子,把r的左孩子作为r的父亲的右孩子

prer->rchild=r->lchild;

else

p->lchild=r->lchild;//否则结点p的左子树指向r的左子树

free(r);

returnp;

}

else

{

btree*q=p->rchild;//q指向其右子树;

free(p);

returnq;

}

}

3Huffman树、编码与解码

例.给定有18个字符组成的文本:

AADATARAEFRTAAFTER求各字符的哈夫曼码。

(1)统计:

(2)构造Huffman树:

(3)在左分枝标0,右分枝标1:

(4)确定Huffman编码:

(5)译码:

例.给定代码序列:

001000111010101011110

文本为:

AAFARADET

 

4散列存储

6、内排序

1希尔排序

voidShellPass(SeqListR,intd)

{//希尔排序中的一趟排序,d为当前增量

for(i=d+1;i<=n;i++)//将R[d+1..n]分别插入各组当前的有序区

if(R[i].key

R[0]=R[i];j=i-d;//R[0]只是暂存单元,不是哨兵

do{//查找R[i]的插入位置

R[j+d];=R[j];//后移记录

j=j-d;//查找前一记录

}while(j>0&&R[0].key

R[j+d]=R[0];//插入R[i]到正确的位置上

}//endif

}//ShellPass

voidShellSort(SeqListR)

{

intincrement=n;//增量初值,不妨设n>0

do{

increment=increment/3+1;//求下一增量

ShellPass(R,increment);//一趟增量为increment的Shell插入排序

}while(increment>1)

}//ShellSort

2直接插入排序

voidlnsertSort(SeqListR)

{//对顺序表R中的记录R[1..n]按递增序进行插入排序

inti,j;

for(i=2;i<=n;i++)//依次插入R[2],…,R[n]

if(R[i].key

//应在原有位置上

R[0]=R[i];j=i-1;//R[0]是哨兵,且是R[i]的副本

do{//从右向左在有序区R[1..i-1]中查找R[i]的插入位置

R[j+1]=R[j];//将关键字大于R[i].key的记录后移

j--;

}while(R[0].key

R[j+1]=R[0];//R[i]插入到正确的位置上

}//endif

}//InsertSort

3选择排序

voidSelectSort(SeqListR)

 {

inti,j,k;

for(i=1;i

k=i;

for(j=i+1;j<=n;j++)//在当前无序区R[i..n]中选key最小的记录R[k]

if(R[j].key

k=j;//k记下目前找到的最小关键字所在的位置

if(k!

=i){//交换R[i]和R[k]

R[0]=R[i];R[i]=R[k];R[k]=R[0];//R[0]作暂存单元

}//endif

}//endfor

}//SeleetSort

4交换排序

voidBubbleSort(SeqListR)

{//R(l..n)是待排序的文件,采用自下向上扫描,对R做冒泡排序

inti,j;

Booleanexchange;//交换标志

for(i=1;i

exchange=FALSE;//本趟排序开始前,交换标志应为假

for(j=n-1;j>=i;j--)//对当前无序区R[i..n]自下向上扫描

if(R[j+1].key

R[0]=R[j+1];//R[0]不是哨兵,仅做暂存单元

R[j+1]=R[j];

R[j]=R[0];

exchange=TRUE;//发生了交换,故将交换标志置为真

}

if(!

exchange)//本趟排序未发生交换,提前终止算法

return;

}//endfor(外循环)

}//BubbleSort

voidQuickSort(SeqListR,intlow,inthigh)

{//对R[low..high]快速排序

intpivotpos;//划分后的基准记录的位置

if(low

pivotpos=Partition(R,low,high);//对R[low..high]做划分

QuickSort(R,low,pivotpos-1);//对左区间递归排序

QuickSort(R,pivotpos+1,high);//对右区间递归排序

}

}//QuickSort

5归并排序

voidMerge(SeqListR,intlow,intm,inthigh)

{//将两个有序的子文件R[low..m)和R[m+1..high]归并成一个有序的

//子文件R[low..high]

inti=low,j=m+1,p=0;//置初始值

RecType*R1;//R1是局部向量,若p定义为此类型指针速度更快

R1=(ReeType*)malloc((high-low+1)*sizeof(RecType));

if(!

R1)//申请空间失败

Error("Insufficientmemoryavailable!

");

while(i<=m&&j<=high)//两子文件非空时取其小者输出到R1[p]上

R1[p++]=(R[i].key<=R[j].key)?

R[i++]:

R[j++];

while(i<=m)//若第1个子文件非空,则复制剩余记录到R1中

R1[p++]=R[i++];

while(j<=high)//若第2个子文件非空,则复制剩余记录到R1中

R1[p++]=R[j++];

for(p=0,i=low;i<=high;p++,i++)

R[i]=R1[p];//归并完成后将结果复制回R[low..high]

}//Merge

 

三、选择题

1、二叉树的第i层至多有2^(i−1)个结点;深度为k的二叉树至多有2^k−1个结点(根结点的深度为1)

2、二维数组A[10...20,5....10]采用行序为主存方式存储,每个元素占4个存储单元,且A[10,5]的存储地址为1000,则A[18,9]的存储地址?

a.不管按行还是按列,都是顺序存储。

按行存储,每行10-5+1共6个元素。

A[10,9]距离A[10,5]之间相差4个元素;A[18,9]与A[10,9]相差8行,共8×6=48个元素;所以A[18,9]与A[10,5]相差4+48=52个元素,共52×4=208个存储单元;A[18,9]的地址应该是1208。

b.更一般的算法:

基地址+(行标之差×每行元素个数+列标之差)×元素所占存储单元

3、n个顶点的连通图最多多少边、最少多少条边?

答:

最多n(n-1)/2,最少n-1

4、设一个无向图有5顶点,度数分别是4,3,3,2,2,求该图边数?

答:

每条边与两个顶点相连接,所以所有顶点上的度数之和就是图中边的两倍,本题中共有4+3+3+2+2=14个边的端点,因而共有14/2=7条边。

6、建立最小堆

建堆过程

6、huffman编码

7、直接排序法过程

用直接排序法将无序列{49,38,65,97,76,13,27}按照从大到小的顺序排为有序列时,每一趟将把当前最大的放到第一位,然后例举出前五趟

就是每一趟将把当前最大的放到第一位.即第一趟{97,49,38,65,76,13,27}

第二趟{97,76,49,38,65,13,27},第三趟{97,76,65,49,38,13,27},

第四趟{97,76,65,49,38,13,27},第五趟{97,76,65,49,38,13,27}

8、

四、编程题

1、二叉树:

二叉树的建立:

#include

#defineElemTypechar

//节点声明,数据域、左孩子指针、右孩子指针

typedefstructBiTNode{

chardata;

structBiTNode*lchild,*rchild;

}BiTNode,*BiTree;

//先序建立二叉树

BiTreeCreateBiTree(){

charch;

BiTreeT;

scanf("%c",&ch);

if(ch=='#')T=NULL;

else{

T=(BiTree)malloc(sizeof(BiTNode));

T->data=ch;

T->lchild=CreateBiTree();

T->rchild=CreateBiTree();

}

returnT;//返回根节点

}

//先序遍历二叉树

voidPreOrderTraverse(BiTreeT){

if(T){

printf("%c",T->data);

PreOrderTraverse(T->lchild);

PreOrderTraverse(T->rchild);

}

}

//中序遍历

voidInOrderTraverse(BiTreeT){

if(T){

PreOrderTraverse(T->lchild);

printf("%c",T->data);

PreOrderTraverse(T->rchild);

}

}

//后序遍历

voidPostOrderTraverse(BiTreeT){

if(T){

PreOrderTraverse(T->lchild);

PreOrderTraverse(T->rchild);

printf("%c",T->data);

}

}

voidmain(){

BiTreeT;

T=CreateBiTree();//建立

PreOrderTraverse(T);//输出

getch();

}

 

1在二叉树中插入结点x,找中序首点(顺着左支一直走)、尾点(顺右)

//首先执行查找算法,找出被插结点的父亲结点。

判断被插结点是其父亲结点的左、右儿子。

将被插结点作为叶子结点插入。

若二叉树为空。

则首先单独生成根结点。

注意:

新插入的结点总是叶子结点。

//

typedefstructnode

{

intdata;

structnode*lchild;

structnode*rchild;

}node;

node*Insert(node*t,intkey)

{

if(t==NULL)

{

node*p;

p=(node*)malloc(sizeof(node));

p->data=key;

p->lchild=NULL;

p->rchild=NULL;

t=p;

}

else

{

if(keydata)

t->lchild=Insert(t->lchild,key);

else

t->rchild=Insert(t->rchild,key);

}

returnt;//important!

}

typedefstructNode

{

intdata;

structNode*lc,*rc;

}node,*Link;

voidinsert(Link*L,intn)

{

if(*L==NULL)

{

(*L)=newnode;//若找到插入位置,则新申请节点

(*L)->lc=(*L)->rc=NULL;

(*L)->data=n;

}

else

{

if(n==(*L)->data)//若n与当前节点的值相等,则不需插入了

return;

elseif(n<(*L)->data)//若n比当前节点的值小,则往当前节点的左子树插

insert(&(*L)->lc,n);

else//若n比当前节点的值大,则往当前节点的右子树插

insert(&(*L)->rc,n);

}

}

中序遍历:

typedefstructBiTNode/*结点结构*/

{

intdata;

structBiTNode*lchild,*rchild;

}BiTNode,*BiTree;

voidInorder(BiTreeT)

{/*中序遍历二叉树*/

if(T)

{

①Inorder(T->lchild);/*遍历左子树*/

②printf("%d",T->data);/*访问结点*/

③Inorder(T->rchild);/*遍历右子树*/

}

}

当调用该子函数时:

加入传的就是根节点,他将不断的递归一直到最左的一个叶子节点,就是不断重复①

T位最左叶子节点是那么第一句再递归式就失败了,所有退回上一层输出②,紧接着就执行③开始递归

以此类推在递归第三句时候也是严格按着1,2,3这个顺序执行。

 

2求一度结点,叶子结点

intcount=0;

voidpreOrder(TTree:

tree){

if(tree!

=NULL){

count++;//先根访问,且计数

//这里显示tree的数据

if(tree->Left!

=NULL)

preOrder(tr

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 农林牧渔 > 农学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1