大话数据结构-持续更新中

一、线性表

1、顺序存储结构

2、链式存储结构

(1)单链表

(2)静态链表

(3)循环链表

(4)双链表

二、栈和队列

1、栈:限定在表尾插入和删除的线性表。

2、队列:允许在一端插入、另一端删除的线性表

3、循环队列:头尾相接的队列,顺序存储结构。(入队出队不需要移动,两个指针front和rear的操作。)

(1)判断循环队列满的条件:(rear+1)%queueSize=front

(2)计算队列当前长度:(rear-front+queueSize)%queueSie

问题:循环队列面临数组溢出的问题。考虑不用担心长度的链式存储结构。

4、队列的链式存储结构和实现

队列的链式存储结构实际就是线性表的单链表,只能尾进头出。简称链队列。链队列保留一个节点作为front节点不动。

(1)链队列的入队:分配新节点-》新节点next指向NULL-》当前队尾的next指向新节点-》新节点标记为队尾

Status EnQueue(LinkQueue *Q, ElemType e)
{
    QueueNodePtr p = (QueueNodePtr)malloc(sizeof(QueueNode));
    if (p == NULL) return ERROR;
    
    p->data = e;
    p->next = NULL;
    // 追加到队尾
    *Q->rear->next = p;
    // 标记成队尾
    *Q->rear = p;
    
    return OK;
}

(2)链队列的出队:链队为空无法删除报错-》队头next节点(出队的元素)给到临时变量head-》head的next给队头next-》如果head是队尾(删除的是队尾节点),把rear置为和front相等

Status DeQueue(LinkQueue *Q, ElemType *e)
{
    if (QueueEmpty(*Q)) return ERROR;
    
    QueueNodePtr head;
    // 找到要删除的节点
    head = *Q->front->next;
    // 回调到函数外
    *e = head->data;
    // 更改头节点
    *Q->front->next = head->next;
    
    // 如果删到了队尾最后一个元素
    if (*Q->rear == head)
        *Q->rear = *Q->front;
    
    // 删除临时指针指向的头节点
    free(head);
    
    return OK;
}

时间:循环队列和链队列都是O(1)的复杂度,循环队列先申请好空间,使用期间不释放。链队列每次申请和释放有一些时间开销,入队和出队频繁两者还是有细微差异。
空间上:循环队列固定长度,存储元素个数和空间的浪费问题,链队列不存在此问题,虽然有指针域,有一些空间的开销但是可以接受,链队列更加灵活。
总结:长度可以确定用循环队列,无法确定长度用链队列。

回顾:栈和队列都是线性表,栈只允许在表尾插入删除。队列只允许在一端插入,另一端删除。

都可以用顺序存储的线性表实现但是有弊端。栈:如果两个相同数据类型的栈,可以用数组两端作为栈底让两个栈共享数据,可以最大化利用数组空间。队列:里面插入删除移动数据,引入循环队列,使得队尾和队头可以在数组中循环,解决了移动的时间损耗。使得复杂度从O(n)到O(1)。

也都能用链式存储结构实现。

三、串

1、串的定义

串(string)是零个或多个字符组成的有限序列,也叫字符串。

注意:空格串不是空串,空格串有长度。

子串:串中任意长度连续字符组成的子序列是该串的子串。反过来包含子串的串称为主串。子串在主串的位置就是子串第一个字符在主串的序号。

2、串的比较

原理:组成串的字符之间的编码来进行比较,字符编码就是字符在字符集中的序号。

编码:计算机常用字符使用标准的ASCII编码,7位二进制表示字符可以表示128个字符,特殊符号出现,128不够用,扩展为8位为一个字符,可以有256个字符,满足英语为主语言和特殊符号的输入、存储、输出。汉字就不够用了,全全世界有成千上百种语言和文字,256肯定不够。后来有了Unicode编码,常用16位(2个字节)二进制表示一个字符,共17个平面,开头是0x00--0x10,一个面是16位(65535个字符),所以可以容纳百万字符(不重复的字符)。和ASCII码兼容,两者前256个字符完全一样。

c语言串的长度+每个字符都相等两个串相等。例如:每个字符比较,比如happennnnn < happy,因为y>e。

3、串的抽象数据类型

串的逻辑结构和线性表很相似,不同之处在于串中的元素是字符。线性表更关注单个元素的操作,但是串更多的是:查找子串的位置,得到指定位置的子串,替换子串等。

一般不同语言有对串的内置方法操作。

4、串的存储结构

顺序存储结构

连续存储单元来存储串中的字符序列。分配固定长度的存储区,一般用定长数组定义。存在最大串长度,可以保存在数组下标0的位置,也可以在最后一个位置。有的编程语言加一个不计入总长的标记字符表示串值的终结,比如“\0”。有问题的是字符串操作中比如连接,新串插入,字符串替换,可能会超过最大长度。

链式存储结构

链式存储串值,一个节点对应一个字符造成空间浪费。因此一个节点放多个字符,最后一个节点未沾满用特殊字符#表示。一个节点放多少字符需要考虑,不能影响串的处理效率。总的来说不如顺序存储灵活,性能也不如顺序存储结构。

子串的操作叫做串的模式匹配,串的重要操作之一,两种串的匹配算法:

1、朴素的模式匹配算法(Brute-Force算法,简称BF算法)

遍历子串,第一个字符和主串匹配,相等则比较第二个字符,不相等用子串第一个字符和主串第二个比较,以此类推。

2、KMP匹配算法

常用于在一个文本串T内查找一个模式串S出现位置,这个算法由Donald Knuth、Vaughan Pratt、James H. Morris三人于1977年联合发,故叫做KMP算法。

算法思想:如果子串T的首字母不和自己后面子串的任意字符相等,子串T的前n个字符和父串S相等,那后面的n-1个字符和父串肯定不相等,所以再进行朴素匹配就是多余的。实际就是利用了已知信息:不匹配位置的前面的字符都是匹配的,加快匹配速度

朴素/暴力匹配算法这个过程中主串位的i值需要不断回溯判断,KMP匹配就是减少不必要的回溯。既然i不能变小,子串位j的值和主串没什么关系,如果子串T后面也有包含和首字符相等的字符或多个字符怎么办?所以关键取决于子串结构中是否有重复的问题

j值的多少取决于当前字符之前串的前后缀相似度。

当匹配到一个字符失配时,其实没必要考虑当前失配的字符,更何况我们每次失配时,都是看的失配字符的上一位字符对应的最大长度值。如此,便引出了next 数组。next数组,实际就是某个数组整体往右移动一位得到next数组,这个数组就是【最大长度】数组。

把next 数组跟之前求得的最大长度表对比后,不难发现,next 数组相当于“最大长度值” 整体向右移动一位,然后初始值赋为-1

如果把子串各位置j值变化定义为数组next,next的长度就是子串的长度。

next推导:

四、树

1、二叉树定义

2、二叉树性质

3、二叉树存储结构

5、遍历二叉树

五、图

1、图的定义

2、图的存储结构

3、图的遍历

4、最小生成树

5、最短路径

6、关键路径

六、查找

1、顺序表查找

2、有序表查找

3、先行索引查找

4、二叉排序树

5、平衡二叉树

6、多路查找树

7、hash表查找

8、hash表构造方法

9、hash表冲突处理

10、hash表查找实现

七、排序

1、基本概念和分类

2、冒泡

3、简单选择

4、直接插入

5、希尔排序

6、堆排序

7、归并

8、快速

9、

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值