数据结构设计与技巧.docx

上传人:b****7 文档编号:9032846 上传时间:2023-02-02 格式:DOCX 页数:68 大小:179.22KB
下载 相关 举报
数据结构设计与技巧.docx_第1页
第1页 / 共68页
数据结构设计与技巧.docx_第2页
第2页 / 共68页
数据结构设计与技巧.docx_第3页
第3页 / 共68页
数据结构设计与技巧.docx_第4页
第4页 / 共68页
数据结构设计与技巧.docx_第5页
第5页 / 共68页
点击查看更多>>
下载资源
资源描述

数据结构设计与技巧.docx

《数据结构设计与技巧.docx》由会员分享,可在线阅读,更多相关《数据结构设计与技巧.docx(68页珍藏版)》请在冰豆网上搜索。

数据结构设计与技巧.docx

数据结构设计与技巧

数据结构设计与技巧讲义

【考查目标】

1.理解数据结构的基本概念;掌握数据的逻辑结构、存储结构及其差异,以及各种基本操作的实现。

2.掌握基本的数据处理原理和方法的基础上,能够对算法进行设计与分析。

3.能够选择合适的数据结构和方法进行问题求解。

一、线性表

(一)线性表的定义和基本操作

(二)线性表的实现

1.顺序存储结构

2.链式存储结构

3.线性表的应用

二、栈、队列和数组

(一)栈和队列的基本概念

(二)栈和队列的顺序存储结构

(三)栈和队列的链式存储结构

(四)栈和队列的应用

(五)特殊矩阵的压缩存储

三、树与二叉树

(一)树的概念

(二)二叉树

1.二叉树的定义及其主要特征

2.二叉树的顺序存储结构和链式存储结构

3.二叉树的遍历

4.线索二叉树的基本概念和构造

5.二叉排序树

6.平衡二叉树

(三)树、森林

1.书的存储结构

2.森林与二叉树的转换

3.树和森林的遍历

(四)树的应用

1.等价类问题

2.哈夫曼(Huffman)树和哈夫曼编码

四、图

(一)图的概念

(二)图的存储及基本操作

1.邻接矩阵法

2.邻接表法

(三)图的遍历

1.深度优先搜索

2.广度优先搜索

(四)图的基本应用及其复杂度分析

1.最小(代价)生成树

2.最短路径

3.拓扑排序

4.关键路径

五、查找

(一)查找的基本概念

(二)顺序查找法

(三)折半查找法

(四)B-树

(五)散列(Hash)表及其查找

(六)查找算法的分析及应用

六、内部排序

(一)排序的基本概念

(二)插入排序

1.直接插入排序

2.折半插入排序

(三)气泡排序(bubblesort)

(四)简单选择排序

(五)希尔排序(shellsort)

(六)快速排序

(七)堆排序

(八)二路归并排序(mergesort)

(九)基数排序

(一十)各种内部排序算法的比较

(一十一)内部排序算法的应用

【知识点解析】

1.线性表

线性表是一种最简单的数据结构,在线性表方面,主要考查线性表的定义和基本操作、线性表的实现。

在线性表实现方面,要掌握的是线性表的存储结构,包括顺序存储结构和链式存储结构,特别是链式存储结构,是考查的重点。

另外,还要掌握线性表的基本应用。

2.栈、队列和数组

栈和队列是两种特殊的线性表,在这方面,要求我们掌握栈和队列的基本概念,以及他们之间的区别。

对于栈和队列的存储结构(包括顺序存储结构、链式存储结构)要有较深的理解,对于栈和队列的应用,例如,排队问题、子程序调用问题、表达式问题等,要搞清楚。

一维数组属于线性表范畴,但多维数组不属于线性表。

在这方面,主要掌握数组的存储结构,例如按行优先、按列优先等,某个元素存在的地址是什么。

对于特殊矩阵(二维数组)的压缩存储原理也要搞清楚。

3、树与二叉树

二叉树和树是两种不同的概念,这一点是必须要搞清楚的。

在这个部分,我们要掌握树的定义、二叉树的定义及主要特征(特殊的二叉树、二叉树的性质)。

在二叉树的顺序存储结构和链式存储结构方面,特别是链式存储结构,因为很多应用都是建立在链式存储基础上,例如,二叉树的遍历(前序遍历、中序遍历、后序遍历)就是一种典型的应用。

在特殊的二叉树中,完全二叉树的概念是必须要搞清楚的,其次,线索二叉树的基本概念和构造、二叉排序树、平衡二叉树的基本概念和应用,特别是二叉排序树的基本性质和特点要能很好地理解。

多棵独立的树就组成了森林,树的存储结构和遍历、森林的遍历、树和二叉树的转换、森林和二叉树的转换等知识,也要有了了解。

最后就是树的应用,通常会作为综合应用类试题出现,包括等价类问题、哈夫曼(Huffman)树和哈夫曼编码等。

4、图

在数据结构中,图的结构是最复杂的,这里的概念也是最多的。

我们要掌握图的基本概念(有向图、无向图、连通、路径、子图、出度、入度、生成树、最短路径、关键路径等)。

图的存储及基本操作主要有邻接矩阵法和邻接表法,我们要掌握这有向图和无向图的这2种存储方法,要清楚图的连通和存储方法之间的关系。

例如,一个顶点的出度和临界矩阵中1的个数有什么关系,等等。

图的遍历方法有深度优先搜索和广度优先搜索,我们要掌握这2种遍历方法的算法实现。

给出一个具体的图,要能知道它的遍历次序。

在数据结构课程中,图的基本应用是最多的,也是最复杂的,我们要掌握这些应用的复杂度分析。

要掌握的具体应用主要包括最小(代价)生成树、最短路径、拓扑排序、关键路径。

在给出的一个具体的图中,我们要会利用已知条件,求出上述应用的结果。

5、查找

在给定的数据集合中查找某个关键值就是查找,查找的基本方法主要有顺序查找法、折半查找法、B-树、散列(Hash)表及其查找。

考的比较多的是折半查找和散列表,我们要掌握它们的基本概念和方法,例如散列表的碰撞如何解决,装载因子的概念等。

另外,我们要掌握各种查找算法的分析及应用,最好能把各种查找在查找成功、查找失败的情况下的最好、平均、最坏的平均查找次数的计算方法搞清楚。

6、内部排序

根据考试大纲,只考查内部排序。

所谓内部排序,就是在内存中进行排序。

在这一部分中,主要要掌握直接插入排序、折半插入排序、冒泡排序(bubblesort)、简单选择排序、希尔排序(shellsort)、快速排序、堆排序、二路归并排序(mergesort)、基数排序的基本概念和方法。

搞清楚这些排序方法的流程,以及它们之间的区别。

在这个知识点,一个很重要的考查点就是各种内部排序算法的比较,一般的书上都会有这样的一个表格,列出了所有排序在各种情况下(最好、最坏、平均)的时间复杂度和空间复杂度,这个表是需要我们记下来的。

当然,如果我们能掌握复杂度的计算方法,自己能推算出来,那就更好了。

最后,就是要掌握内部排序算法的基本应用,以及算法的实现。

【复习方法】

1、教材的选择

从考试大纲来看,所要求的知识在一般的大学数据结构教材中都已经包含,所以,选择哪本书并不是最重要的事情。

不过,根据希赛教育推荐,对于数据结构的复习,可以选择清华大学出版社的《数据结构(第二版)》(严蔚敏主编)。

这本书有多种语言的版本,建议选择C语言的版本,在复习的过程中,还可以配以相应的习题集。

2、学习方法

对于数据结构的学习,难在其中的算法及实现。

有条件的考生,可以在计算机上编写程序,自己实现教材上的算法(要注意,书上的算法通常都采用伪代码编写,需要我们自己用某种程序设计语言去具体实现)。

如果没有条件,那就只有在心里进行推导了,可以使用实际的例子,手工“实现”算法。

《数据结构》

【考查目标】

1.理解数据结构的基本概念;掌握数据的逻辑结构、存储结构及其差异,以及各种基本操作的实现。

2.掌握基本的数据处理原理和方法的基础上,能够对算法进行设计与分析。

3.能够选择合适的数据结构和方法进行问题求解。

一、线性表

大纲要求:

(一)线性表的定义和基本操作

(二)线性表的实现

1.顺序存储结构

2.链式存储结构

3.线性表的应用

知识点:

1.深刻理解数据结构的概念,掌握数据结构的“三要素”:

逻辑结构、物理(存储)结构及在这种结构上所定义的操作“运算”。

2.时间复杂度和空间复杂度的定义,常用计算语句频度来估算算法的时间复杂度。

以下六种计算算法时间的多项式是最常用的。

其关系为:

O

(1)

指数时间的关系为:

O(2n)

3.线性表的逻辑结构,是指线性表的数据元素间存在着线性关系。

主要是指:

除第一及最后一个元素外,每个结点都只有一个前趋和只有一个后继。

在顺序存储结构中,元素存储的先后位置反映出这种逻辑关系,而在链式存储结构中,是靠指针来反映这种逻辑关系的。

4.顺序存储结构用向量(一维数组)表示,给定下标,可以存取相应元素,属于随机存取的存储结构。

5.线性表的顺序存储方式及其在具体语言环境下的两种不同实现:

表空间的静态分配和动态分配。

掌握顺序表上实现插入、删除、定位等运算的算法。

6.尽管“只要知道某结点的指针就可以存取该元素”,但因链表的存取都需要从头指针开始,顺链而行,故链表不属于随机存取结构。

要理解头指针、头结点、首元结点和元素结点的差别。

头结点是在插入、删除等操作时,为了算法的统一而设立的(若无头结点,则在第一元素前插入元素或删除第一元素时,链表的头指针总在变化)。

对链表(不包括循环链表)的任何操作,均要从头结点开始,头结点的指针具有标记作用,故头指针往往被称为链表的名字,如链表head是指链表头结点的指针是head。

理解循环链表中设置尾指针而不设置头指针的好处。

链表操作中应注意不要使链意外“断开”。

因此,若在某结点前插入一个元素或删除某元素,必须知道该元素的前驱结点的指针。

7.链表是本部分学习的重点和难点。

重点掌握以下几种常用链表的特点和运算:

单链表、循环链表、双向链表、双向循环链表的生成、插入、删除、遍历以及链表的分解和归并等操作。

并能够设计出实现线性表其它运算的算法。

8.从时间复杂度和空间复杂度的角度综合比较线性表在顺序和链式两种存储结构下的特点,即其各自适用的场合。

小结:

顺序表和链表的比较

通过对它们的讨论可知它们各有优缺点,顺序存储有三个优点:

(1)方法简单,各种高级语言中都有数组,容易实现。

(2)不用为表示结点间的逻辑关系而增加额外的存储开销。

(3)顺序表具有按元素序号随机访问的特点。

但它也有两个缺点:

(1)在顺序表中做插入删除操作时,平均移动大约表中一半的元素,因此对n较大的顺序表效率低。

(2)需要预先分配足够大的存储空间,估计过大,可能会导致顺序表后部大量闲置;预先分配过小,又会造成溢出。

链表的优缺点恰好与顺序表相反。

在实际中怎样选取存储结构呢?

(1)基于存储的考虑

对线性表的长度或存储规模难以估计时,不宜采用顺序表;链表不用事先估计存储规模,但链表的存储密度较低,显然链式存储结构的存储密度是小于1的。

(2)基于运算的考虑

在顺序表中按序号访问ai的时间性能时O

(1),而链表中按序号访问的时间性能O(n),所以如果经常做的运算是按序号访问数据元素,显然顺序表优于链表;而在顺序表中做插入、删除时平均移动表中一半的元素,当数据元素的信息量较大且表较长时,这一点是不应忽视的;在链表中作插入、删除,虽然也要找插入位置,但操作主要是比较操作,从这个角度考虑显然后者优于前者。

(3)基于环境的考虑

顺序表容易实现,任何高级语言中都有数组类型,链表的操作是基于指针的,相对来讲前者简单些,也是用户考虑的一个因素。

总之,两种存储结构各有长短,选择那一种由实际问题中的主要因素决定。

通常“较稳定”的线性表选择顺序存储,而频繁做插入删除的即动态性较强的线性表宜选择链式存储。

练习题:

(一)选择题:

1.以下那一个术语与数据的存储结构无关?

(A)

A.队列B.哈希表

C.线索树D.双向链表

2、一个算法应该是(B)。

A.程序B.问题求解步骤的描述

C.要满足五个基本特性D.A和C.

3、数据结构中,与所使用的计算机无关的是数据的(C)

A.存储结构B.物理结构C.逻辑结构D.物理结构和存储结构

4.算法的计算量的大小称为计算的(B)。

A.效率B.复杂性 C.现实性 D.难度

5.下列说法,不正确的是(D)。

A.数据元素是数据的基本单位

B.数据项是数据中不可分割的最小可标识单位

C.数据可由若干个数据元素构成

D.数据项可由若干个数据元素构成

6.连续存储设计时,存储单元的地址(A)。

A.一定连续B.一定不连续

C.不一定连续D.部分连续,部分不连续

7.线性表(a1,a2,…,an)以链接方式存储时,访问第i位置元素的时间复杂性为(C)。

A.O(i)B.O

(1)C.O(n)D.O(i-1)

8.对于顺序存储的线性表,访问结点和增加、删除结点的时间复杂度为(C)。

A.O(n)O(n)B.O(n)O

(1)

C.O

(1)O(n)D.O

(1)O

(1)

9.设单链表中结点的结构为(data,link)。

已知指针q所指点是指针p所指结点的直接前驱,若在*q与*p之间插入结点*s,则应执行下列哪一个操作?

(B)。

A.s->link=p->link;p->link=s

B.q->link=s;s->link=p

C.p->link=s->link;s->link=p

D.p->link=s;s->link=q

10.在一个长度为n的顺序表的表尾插入一个新元素的渐进时间复杂度为(B)。

A.O(n)B.O

(1)

C.O(n2)D.O(log2n)

11.表长为n的顺序存储的线性表,当在任何位置上插入一个元素的概率相等时,插入一个元素所需移动元素的平均个数为(B)

A.nB.n/2

C.(n-1)/2D.(n+1)/2

12.循环链表的主要优点是(D)

A.不再需要头指针了。

B.已知某个结点的位置后,能很容易找到它的直接前驱结点。

C.在进行删除操作后,能保证链表不断开。

D.从表中任一结点出发都能遍历整个链表。

(二)应用题

1、按增长率由小至大排列以下7个函数。

答:

2、数据的存储结构由哪四种基本的存储方法实现,并做以简要说明?

答:

四种表示方法

(1)顺序存储方式。

数据元素顺序存放,每个存储结点只含一个元素。

存储位置反映数据元素间的逻辑关系。

存储密度大,但有些操作(如插入、删除)效率较差。

(2)链式存储方式。

每个存储结点除包含数据元素信息外还包含一组(至少一个)指针。

指针反映数据元素间的逻辑关系。

这种方式不要求存储空间连续,便于动态操作(如插入、删除等),但存储空间开销大(用于指针),另外不能折半查找等。

(3)索引存储方式。

除数据元素存储在一地址连续的内存空间外,尚需建立一个索引表,索引表中索引指示存储结点的存储位置(下标)或存储区间端点(下标),兼有静态和动态特性。

(4)散列存储方式。

通过散列函数和解决冲突的方法,将关键字散列在连续的有限的地址空间内,并将散列函数的值解释成关键字所在元素的存储地址,这种存储方式称为散列存储。

其特点是存取速度快,只能按关键字随机存取,不能顺序存取,也不能折半存取。

3.线性表有两种存储结构:

一是顺序表,二是链表。

试问:

(1)如果有n个线性表同时并存,并且在处理过程中各表的长度会动态变化,线性表的总数也会自动地改变。

在此情况下,应选用哪种存储结构?

为什么?

(2)若线性表的总数基本稳定,且很少进行插入和删除,但要求以最快的速度存取线性表中的元素,那么应采用哪种存储结构?

为什么?

(1)选链式存储结构。

它可动态申请内存空间,不受表长度(即表中元素个数)的影响,插入、删除时间复杂度为O

(1)。

(2)选顺序存储结构。

顺序表可以随机存取,时间复杂度为O

(1)。

(三)算法设计题

1.设计算法,求带表头的单循环链表的表长。

解:

intlength(LinklistL)

{

intI;

listnode*p;

I=0;

P=L;

while(p->next!

=L){

p=p->next;

I++;}

returnI;

}

2.已知单链表L,写一算法,删除其重复结点。

算法思路:

用指针p指向第一个数据结点,从它的后继结点开始到表的结束,找与其值相同的结点并删除之;p指向下一个;依此类推,p指向最后结点时算法结束。

算法如下:

解:

voidpur_LinkList(LinkListH)

{LNode*p,*q,*r;p=H->next;/*p指向第一个结点*/

if(p==NULL)return;

while(p->next)

{q=p;

while(q->next)/*从*p的后继开始找重复结点*/

{if(q->next->data==p->data)

{r=q->next;/*找到重复结点,用r指向,删除*r*/

q->next=r->next;

free(r);

}/*if*/

elseq=q->next;

}/*while(q->next)*/

p=p->next;/*p指向下一个,继续*/

}/*while(p->next)*/

}

该算法的时间性能为O(n2)。

3.已知指针la和lb分别指向两个无头结点的单链表中的首结点。

请编写函数完成从表la中删除自第i个元素开始的共len个元素并将它们插入到表lb中第j个元素之前,若lb中只有j-1个元素,则插在表尾。

函数原型如下:

intDeleteAndInsertSub(LinkList&la,LinkList&lb,inti,intj,intlen);

答:

intDeleteAndInsertSub(LinkList&la,LinkList&lb,inti,intj,intlen)

{

intk;

LinkListp,q,prev,s;

if(i<0||j<0||len<0)

return-1;

p=la;

k=1;

prev=NULL;

while(p&&k

{

prev=p;

p=p->next;

k++;

}

if(!

p)

return-1;

q=p;k=1;

while(q&&k

{

q=q->next;

k++;

}

if(!

q)

return-1;

if(!

prev)

la=q->next;

else

prev->next=q->next;

if(j==1)

{

q->next=lb;

lb=q;

}

else

{

s=lb;k=1;

while(s&&k

{

s=s->next;

k++;

}

if(!

s)

return-1;

q->next=s->next;

s->next=p;

return1;

}

}

4.写一算法,将一带有头结点的单链表就地逆置,即要求逆置在原链表上进行,不允许重新构造新链表。

 

函数原型如下:

voidLinkList_reverse(LinkList&L);

答:

voidLinkList_reverse(LinkList&L)

{

LinkListp,q,s;

p=L->next;q=p->next;s=q->next;p->next=NULL;

while(s->next)

{

q->next=p;p=q;

q=s;s=s->next;

}

q->next=p;s->next=q;L->next=s;

}

5.写一算法,将带有头结点的非空单链表中数据域值最小的那个结点移到链表的最前面。

要求:

不得额外申请新的链结点。

函数原型如下:

voiddelinsert(LinkList&L);

答:

voiddelinsert(LinkList&L)

{

p=L->next;//p是链表的工作指针

pre=L;//pre指向链表中数据域最小值结点的前驱

q=p;//q指向数据域最小值结点,初始假定是第一结点

while(p->next!

=NULL)

{

if(p->next->datadata)//找到新的最小值结点

{pre=p;q=p->next;}

p=p->next;

}

if(q!

=L->next)//若最小值是第一元素结点,则不需再操作

{

pre->next=q->next;//将最小值结点从链表上摘下

q->next=L->next;//将q结点插到链表最前面

L->next=q;

}

}

6.编写一个算法来交换单链表中指针P所指结点与其后继结点,HEAD是该链表的头指针,P指向该链表中某一结点。

答:

单链表中查找任何结点,都必须从头指针开始。

本题要求将指针p所指结点与其后继结点交换,这不仅要求知道p结点,还应知道p的前驱结点。

这样才能在p与其后继结点交换后,由原p结点的前驱来指向原p结点的后继结点。

LinkedListExchange(LinkedListHEAD,p)

∥HEAD是单链表头结点的指针,p是链表中的一个结点。

本算法将p所指结点与其后继结点交换。

{q=head->next;∥q是工作指针,指向链表中当前待处理结点。

pre=head;∥pre是前驱结点指针,指向q的前驱。

while(q!

=null&&q!

=p){pre=q;q=q->next;}∥未找到p结点,后移指针。

if(p->next==null)printf(“p无后继结点\n”);∥p是链表中最后一个结点,无后继。

Else∥处理p和后继结点交换

{q=p->next;∥暂存p的后继。

pre->next=q;∥p前驱结点的后继指向p的后继。

p->next=q->next;∥p的后继指向原p后继的后继。

q->next=p;∥原p后继的后继指针指向p。

}

}∥算法结束。

7.已知线性链表第一个链结点指针为list,请写一算法,将该链表分解为两个带有头结点的循环链表,并将两个循环链表的长度分别存放在各自头结点的数据域中。

其中,线性表中序号为偶数的元素分解到第一个循环链表中,序号为奇数的元素分解到第二个循环链表中。

答:

算法如下:

voidsplit(ListNode*List,ListNode*&list1,ListNode*&list2)

{

list1=(ListNode*)malloc(sizeof(ListNode));

list2=(ListNode*)malloc(sizeof(ListNode));

p=list;;

q=list1;

r=list2;

len1=0;

len2=0;

mark=1;

while(p!

=null)

{

if(mark=1)

{

q->next=p;

q=q->next;

len1++;

mark=2;

}

else

{

r->next=p;

r=r->next;

len2++;

mark=1;

}

}

list1->data=len1;

list2->data=len2;

q->next=list1;

r->next=list2;

}

8.设A和B是两个单链表,其表中元素递增有序。

试写一算法将A和B归并成一个按元素值递减有序的单链表C,并要求辅助空间为O

(1)。

答:

Linklistmerge(LinklistA,LinklistB)

{

LinklistC;

Listnode*p;

C=null;

while(A&&B)

if(A->data<=B->data)

{p=A->next;A->next=C;C=

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

当前位置:首页 > 工程科技 > 环境科学食品科学

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

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