数据结构、算法及线性表总结

数据结构、算法及线性表总结

本学期学习了数据结构这门课,为了能够理清学习历程,在此记录学习到的知识,以供参考。

一、本课程的思维导图(持续更新)

二、重要概念的笔记及个人解析

<font color=>第一章:绪论

1)数据结构的定义:数据结构是指所有数据元素以及数据元素之间的关系,可以看作是相互之间存在着某种特定关系的数据元素的集合(带结构的数据的集合)

2)逻辑结构的定义:逻辑结构是从数据元素的逻辑关系上描述数据的,它与数据的存储无关,是从具体问题中抽象出来的数学模型。(用来描述数据之间有怎样的关系,或哪种类型的关系)

3)逻辑结构的类型:逻辑结构是多样复杂的,现阶段我们接触到的有 集合线性结构树形结构以及图形结构。(目前学习到线性结构)

4)存储结构的定义:存储结构是数据元素及其关系在计算机存储器中的存储表示也称为物理结构,常用的有顺序存储链式存储索引存储哈希存储四中存储结构。

5)顺序存储结构:用该结构存储数据元素,所有数据元素在存储器中占有一整块存储空间,可将逻辑结构直接映射到存储结构。(优点:存储效率高,没有额外占用的空间,还可以实现对元素的随机存取。缺点:不便于数据修改,一个元素的变动就可能使其他一系列元素也要进行移动)

6)链式存储结构:每一个数据元素占用的只是一个内存节点,每个节点单独分配,地址也不一定连续,除了节点的指针域外,每个节点对其他节点的影响很小很小。(优点:便于修改数据,对数据的添加删改只需要对前后节点的指针域进行修改即可。缺点:在空间上所有的节点不占用一整块内存,存储空间利用率低,而且不能对链式结构的数据进行随机存取。)

7)索引存储结构:在存储数据时附加一张索引表,每个元素都有一个关键字和对应的存储地址。

8)哈希存储结构:根据元素的关键字通过哈希函数计算出一个值,将这个值作为该元素的存储地址。只要有关键字,就可以查到一个地址。(只存数据,不存数据的逻辑关系,只适合一些快速查找和插入的场合。)

9)数据类型:数据类型指在某种程序设计语言中已经实现的数据结构,也就是一种编程语言可以提供给你的它原本就有的数据类型(原子类型),也包括了用这些基本类型组合而成的一些类型(结构类型)。

10)抽象数据类型:用户不考虑计算机的具体存储结构和运算的具体实现算法,而是就事论事的抽象的逻辑数据结构及其运算。

11)算法的定义:算法是对特定问题求解步骤的一种描述,它是指令的有限序列。(面对一个问题时所给出的具体的解决方法)

12)算法分析:算法分析就是分析算法占用计算机资源的多少。(分析提供的解决方法是否合理,是否能高效低费、事半功倍地解决问题)

13)算法时间复杂度分析:从程序的运行时间上来判断算法的效率,通过计算一个算法中执行原操作的次数的多少来进行比较。

14)算法空间复杂度分析:空间复杂度是一个算法在运行过程中临时占用的存储空间的量度。

<font color=>第二章:线性表

1)线性表的定义:线性表是具有相同特性的数据元素的一个有限序列。

2)顺序表:线性表的顺序存储结构就称为顺序表占用一整块内存,直接按照逻辑顺序挨个存储。

3)链表:线性表的链式存储结构就称为链表,数据元素分开存储在一个个节点中,每个节点既包含数据元素(数据域),也包含逻辑关系(指针域)

4)链表与顺序表的比较:链表便于数据元素的添加与删改,方便省时。顺序表是线性表的直接映射,具有随机存取特性,查找数据时时间复杂度为O(1),另外,顺序表的存储密度比链表要高(存储密度=结点中数据元素所占的存储量/节点所占的存储量

5)单链表:

typedef struct LNode
{	ElemType data;//存放元素值
    struct LNode* next;//指向后继结点
}LinkNode;//单链表结点类型

6)双链表:

typedef struct DNode
{	ElemType data;//存放元素值
 	struct DNode* prior;//指向前驱结点
    struct DNode* next;//指向后继结点
}DLinkNode;//双链表的结点类型

7)循环链表:循环链表分循环单链表和循环双链表,循环单链表是指将单链表的尾结点next指针域指向头结点,整个单链表形成一个环。循环双链表是指将双链表的尾结点的next指针域指向头结点,将头节点的prior指针域指向尾结点,整个双链表形成一个环。

<font color=>第三章:栈和队列

1)栈的定义:栈是一种只能在一端进行插入或删除操作的线性表。(类似于一群人走进死胡同的情景)允许进行操作的一端叫做栈顶,另一端叫做栈底,栈里为空时称为空栈,对栈的插入操作称为进栈或入栈,删除操作称为出栈或退栈。遵循“先进后出”原则,即后入栈的先出去,所以栈也被称为后进先出表。

2)队列的定义:队列是一种仅允许在表的一端进行插入操作,另一端进行删除操作的线性表。(类似于排队的情景)进行插入的一端叫做队尾,进行删除的一端叫做队头,插入元素称为入队,删除元素称为出队,在队中,每一个元素都是按照入队的顺序出队的,谁先进谁就先出,所以队也被称为先进先出表。

<font color=>第四章:串

1)串的基本概念:串是由零个或多个字符组成的有限序列。(含零个字符的串称为空串)

2)顺序串:

typedef struct
{	char data[MaxSize];//存放串字符
 	int length;//存放串长
}SqString;//顺序串类型

3)链串:

typedef struct
{	char data;//存放字符
 	struct snode* next;//指向下一个结点的指针
}LinkStrNode;//链串的结点类型

4)串的模式匹配:所谓串的模式匹配,就是找一个字符串中有没有一段我们想要的字符串片段,也就是在字符串S中去寻找有无字符串T的存在。为了解决这个问题,一般有两种方法,Brute-Force算法 和 KMP算法。第一个算法俗称暴力算法,就是从S串的开头开始,如果T与S的片段不一致,就把T向后移一个字符,再进行比较,直到在S中找到与T一样的字符片段为止。

5)KMP算法:KMP算法取消了主串指针的回溯,从而使算法效率有了某种程度的提高。(简单来说,就是以前比较S串与T串,如果不匹配,还要回到指针已经判断过的地方重新判断,而现在通过这个算法,我们的主串指针只对T串进行回溯,在S串上只会递进不会回到之前已经检测过的地方。)

6)next数组的意义和求值方法:当我们求出next数组后,我们就可以用它来消除主指针的回溯。我们假设S=“aaaaab”,T=“aaab”。我们从i=0,j=0,开始匹配,失配处为i=3,j=3。

a a a a a b
| | | ×
a a a b

我们看到在×号之前,模式串最大的相等的前缀和后缀有2个字符,而这个数+1即为next值 (加不加1看情况,加1是因为字符串的T[0]位置通常默认保存串的长度,所以从T[1]开始与S比较,在这个例子中明显从T[0]开始作比较,所以不用加1,next还是2)

这样的话我们通过计算就可以让T右滑(j-next[j])个位置,让S[i]和T[next[j]]进行比较,这样就可以不在S串上溯回主指针了,这里我们需要让T右滑1个位置(3-2=1),让S[3]和T[2]进行比较

a a a a a b
| | | ×
a a a b

这样以此类推,就可以利用next值来减少比较的次数

7)nextval数组求值:

用到nextval数组是因为next数组也有一些缺陷,比如面对上面的例子时(即同一个字符在同一个地点连续出现时),连next数组也不能很好的解决问题,于是我们引入nextval数组来应对这样的字符串。

nextval数组的求法:nextval数组的求值方法很简单,几乎是next数组一出来,nextval数组也就出来了。

排序 1 2 3 4 5 6 7
模式串 a b a a b c a
next 0 1 1 2 2 3 1
nextval 0 1 0 2 1 3 0

如图,我们先求得next数组的值,当我们求某一位的nextval值时,我们首先看它对应的next值,在查找next值对应的那一位字符的,如果两个字符不一样,则nextval=next,若一样,则看那一位字符A对应的next值所指向的那一位字符B,若字符A与B不相等,则所求的nextval等于A的next值,若A与B还是一样,则重复以上操作。

比如:求第六位c的nextval,看next值为3,在3上的字符为a,c与a不一样,next=nextval=3

再比如:求第5位b的nextval,看next值为2,在2上的字符为b,b与b一样,看3上的next值,next=1,在1上的字符为a,a与b不一样,nextval=处在2上的b的next值,nextval=1

三、疑难问题及解决方案

1)问题:二叉树的逻辑存储问题:在学习逻辑结构时,老师提到了一个二叉树是如何排序的?如何在线性存储中保存逻辑结构的问题,这个问题难住了我,既然二叉树是线性排列的,那如何保存一个二叉树内数据元素的关系呢?如何描述树形结构的元素的从属关系呢?这使我百思不得其解。

办法:在提出这个问题之后我上网查找了关于二叉树的排序的方法,发现其实二叉树在线性表中是从根开始按照从上往下、从左往右的顺序保存到线性表中的,而要想表示表中数据的逻辑关系,就要知道一个节点的左子树所在的位置序号是节点位置序号的2倍,右子树所在的位置序号是节点位置的序号的2倍加1,再深入下去,我发现其实是否用二叉树来存储数据元素也是要分情况的,如果有的数据某些分叉根本就没有东西,那么二叉树这样的存储结构就会浪费计算机的存储资源。

2)问题:在学习 栈和队列 章节时,对环形队列的理解不够深刻,老师发的题目很多我都做错了,总是不知道如何判断一个循环队列是否为空,对这一类问题很是头疼。

办法:不管概念懂没懂,在课程的后半段先牢记老师说的话,下课后在去翻书,认真的阅读这一段的知识点,在经过一段时间的学习后,终于将这个难点攻克,理解了假溢出的概念(队满条件设置不合理导致当rear=MaxSize-1成立后队中仍可能有空位置),也明白了何时循环队列为空(q->rear==q->front)

1)问题:在学习 串 章节的KMP算法时,我对这个算法的理解非常困难,书上的解释我也难以吸收,这也使得之后的求next数组和nextval数组对我来说也变成了一件很难的事,有时候我都快放弃学习KMP算法了。

办法:某一天在浏览B站时,我突发奇想的搜索了KMP算法,结果发现了一个叫做《「天勤公开课」KMP算法易懂版》的视频,里面对KMP算法的讲解非常的简单易懂,通过对视频内容的反复学习,我终于理解了KMP算法和next数组、nextval数组的求法,这也是我能写出KMP算法总结的原因。

posted @ 2020-03-28 18:53  勤政  阅读(350)  评论(0编辑  收藏  举报