王道408数据结构个人产出

这周速通数据结构,以下是个人产出。

一、数据结构三要素 

包括逻辑结构,数据运算,存储结构。

1.逻辑结构

包括集合结构,线性结构,树形结构,图状结构。

集合结构:数据元素之间仅仅同属一个集合;

线性结构:数据元素之间是一对一的关系;

树形结构:数据元素之间是一对多的关系;

图状结构:多对多。

2.数据运算

基于特定的逻辑结构、实际需求来定义基本运算。

3.存储结构(物理结构)

顺序储存:逻辑上相邻的元素存储在物理位置相邻的存储单元中(邻接关系);

链式储存:元素逻辑相邻,物理位置不相邻。借用指针来表示逻辑关系;

索引存储:建立索引表来存放关键字,元素离散存放;

散列存储(哈希存储):根据关键字来计算地址。

所以,数据的存储结影响构内存分配的方便程度,从而影响数据运算的速度。因此,顺序存储的成本更高。

4.补充

数据类型:值的集合以及集合上的操作的总称

(1)原子类型:不可再分

(2)结构类型:能分解为若干分量,且各分量之间有一定的逻辑关系

抽象数据类型ADT:抽象数据组织以及相关操作,是对数据结构逻辑关系的描述。

二、算法

程序=算法+数据结构

算法是对特定问题求解步骤的描述。

1.算法的特性

有穷性:算法必须有穷,程序可以无穷。死循环不是算法!

确定性:相同输入得到相同输出。

可行性:通过基本元素实现有限次。

输入:0个或多个,取自于特定对象的集合。

输出:一个/多个。

2.什么是好算法?

正确求解问题,可读性(用好注释!!!),使之便于理解,健壮性(能应对非法数据,关注边缘问题),时间复杂度和空间复杂度低(省时省内存)。

3.时间复杂度

与机器性能,编程语言等等有关。

//以爱你一千遍和爱你三千遍为例
void loveyou(int n){//n为问题规模
  int i=1;//爱你的程度  <1>
  while(i<=n){        //<2>
     i++;//每次+1     //<3>
     printf("I Love You %d\n",i);//<4>
}
 printf("I Love You More Than %d\n",n);//<5>
}

根据语句频度,得:T(3000)=1+3001+2*3000+1,时间开销与问题规模的关系为

T(n)=3n+3

然而,当n足够大,只要考虑高阶的部分就行了。

(1)加法规则

多项相加,只保留最高阶的项,系数变为1。

(2)乘法规则

多项相乘,都保留。

口诀:从小到大为常对幂指阶。

只用考虑循环语句,顺序执行的代码是常数项。多层循环只需关注最深层循环。只需挑选循环中一个基本操作分析即可。要度量最坏和平均时间复杂度。算法的性能问题只能在问题规模很大时才能暴露出来。

4.空间复杂度

以下是几个关键点:

这是空间开销与问题规模的关系。

只需关注与储存空间的大小有关的变量。

函数递归调用也会带来内存空间的开销。(函数调用栈)

空间复杂度=递归调用的深度。

三.线性表

是具有相同数据类型的n个数据元素的有限序列,其中n为表长,用L命名线性表。

要注意的点:

n=0 空表

L=(a1,a2,...,ai,...an)

每个数据元素所占空间一样大。

ai是该元素的位序,a1是表头元素,an是表尾元素

直接前驱和直接后驱

基本操作:

初始化(&L):分配内存空间

销毁(&L):释放内存空间

插入(&L,i,e):在表L第i个位置插入指定元素i

删除(&L,i,&e):同插入

按值查找(L,e):查找具有给定关键字值的元素

按位查找(L,i):获取表L中第i个位置的元素的值

求表长(L):即元素的数据个数

输出(L):按前后顺序输出L所有元素值

判空操作(L):空表返回true

tips:创销,增删改查;将常用的操作/运算进行封装;注意什么时候传入参数的引用

1.顺序表

用顺序存储的方式实现线性表

如何知道数据元素的大小?c语言用sizeof(数据元素类型)实现

1.静态分配

用静态的数组存放数据元素,要初始化一个数据表,储存空间是静态的。

2.动态分配

c语言——malloc,free函数,动态申请和释放内存空间

c++——new,delete关键字


顺序表特点:

随机访问:data[i-1]  在O(1)时间内找到第i个元素

存储密度高:每个节点存放数据元素,有的还存放指针

拓展容量不方便:只能动态分配,时间复杂度高

插入删除不方便:移动大量元素

c语言中,结构体的比较不能直接用==

2.单链表

1.定义

链式存储,通过一组任意的存储单元来存储线性表中的数据元素

优点:不要求大片连续空间,改变容量方便

缺点:不能随机存取,耗费空间放指针

注意:结点,数据域,指针域

如何增加一个新节点?在内存中申请一个结点所需空间,用指针p指向这个节点

举例:

struct LNode{//定义单链表结点类型
    ElemType data;//每个节点存放一个数据元素
    struct LNode *next;//指针指向下一元素
};
struct LNode *p=(struct LNode*)malloc(sizeof(struct LNode));

typedef关键字——数据类型重命名

typedef<数据类型><别名>

LinkLIst与LNode等价

LinkList——强调这是一个单链表

LNode——强调这是一个结点

空表无节点,防止脏数据。

判断单列表是否为空:看L==Null

头结点:代表链表上头指针指向的第一个结点,不带有数据

最好带头结点

2.插入和删除

前插结点用O(1)

删除指定结点:需要修改前驱结点的next指针

1.传入头指针循环寻找p的前驱结点

2.结点前插的实现

指定节点是最后一个节点时,要特殊处理

3.单链表的查找

基于带头结点

单链表不具备随机查找的特性,只能依次扫描

4.单链表的建立

尾插法和头插法

初始化一个单链表,取一个数据元素插入表头或表尾

核心是初始化和指定结点的后插操作

L->next=NULL//头插法有这样一句

如果没有,就是野指针

3.双链表

1.双链表的遍历
//后向遍历
while(p!=NULL){
    p=p->next;//对结点p做相应处理
}
//前向遍历
while(p!=NULL){
    p->prior;//对结点p做相应处理
}

//前向遍历(跳过头结点)
while(p->prior!=NULL){
    P->prior;//对结点p做相应处理
}

2.循环链表

很多时候对链表的操作都是在头部或尾部

可以让L指向表尾元素

3.静态链表

用数组的方式实现的链表,容量固定不可变,不能随机存取,适用于数据元素数量固定不变的链表。

分配一整片连续的内存空间,各个节点集中安置。0号结点充当“头节点”,游标充当指针。

查找:从头节点出发,遍历。

插入位序为i的结点:

1.找一个空结点,存入数据元素;

2.从头结点出发找到i-1 的结点;

3.修改新结点的next;

4.修改i-1号结点的next。

4顺序表和链表的比较

逻辑结构都是线性结构,都属于线性表;

二者存储结构不同,顺序存储/链式存储(特点/优点/缺点);

基本操作实现效率不同(初始化/插入/删除/查找......)。

四.栈

1.基本概念

栈是一种只允许在一端进行插入或删除操作的线性表。

术语:空栈、栈顶、栈底

特点:后进先出(LIFO)

基本操作:

IintStack:初始化栈。构造空栈s,分配内存空间。

DestoryStack:销毁栈。销毁并释放栈S所占的内存空间。

Push:进栈。加入x成为新栈顶。

Pop:出栈。弹出栈顶元素并用x返回。

GetTop:读栈顶元素。访问栈顶元素,用x返回栈顶元素。

StackEmpty:判空。空则true。

2.顺序存储

栈顶指针:记录数组下标

判断栈空只需top==-1(0号栈栈顶指针初始时)

指针先加1,新元素入栈

S.top=S.top+1;
S.data[S.top]=x;
//这两句等价于
S.data[++S.top]=x;

注意:入栈错误写法为

S.data[S.top++]=x

出栈正好相反:栈顶元素先出栈,指针再减1.

x=S.data[S.top--];//正确写法
x=S.data[--S.top];//错误写法

读栈顶元素

x=S.data[S.top];

栈满的条件:top=MaxSize

顺序栈的特点:栈的大小不可改变。

解决办法:用链式存储/刚开始就分配一个较大的内存空间。但最优解还是共享栈。

共享栈:设置2个栈顶指针。两个栈从两边向中间增长

栈满的条件:top0+1==top1

3.链式存储

链栈推荐用不带头结点

同链表

4.队列
5.基本概念

定义:在一段插入、另一端删除的线性表。

特点:先进先出(FIFO)

术语:队头、队尾、空队列

队头:允许删除的一端

只能从队尾入队,判断为空返回true。(同栈)

6.顺序存储

队列已满:Q.rear=(Q.rear+1)%MaxSize 

循环队列

取模运算将储存空间在逻辑上变成环状,所以队列已满的条件:对位指针的下一个位置是队头。

即(Q.rear+1)%MaxSize==Q.front

出队:只能让队头元素出队

先判断队空,队头指针后移

或者判断队列已满/已空:

int size=0//队列当前长度

插入成功size++,删除成功size--

其他出题办法:牺牲一个存储单元/增加辅助变量

7.链式存储

带头结点和不带头结点

链队列:链式存储实现的队列

入队(带头结点):malloc申请一个新结点,新节点next指针域设为NULL,将rear指向的结点的next指针域指向新结点s

入队(不带头结点):第一个元素入队需要特殊处理

出队(不带头结点):最后一个结点出队,修改rear指针。恢复空队。

8.双端队列

输入受限和输出受限

卡特兰数

在栈中合法的输出队列,在双端队列中必定合法

9.栈的应用

括号  

用注释的方式简要说明接口,扫描到左括号,入栈,扫描到右括号且当前栈空则匹配失败,若栈非空则弹出栈顶元素检查是否匹配。

用静态数组存放栈中元素可能会栈溢出so可用链栈。

表达式求值

分为:前缀(波兰),中缀,后缀(逆波兰)

组成:操作数,界限符,运算符

中缀:a+b;a+b-c;a+b-c*d

前缀:+ab;ab+c-或abc-+;ab+cd*-

后缀:ab+;-+abc;-+ab*cd

“左优先”原则(中转后)

中转右:右优先,先出栈是左操作数

​​​​​​递归

递归表达式(递归体),边界条件(递归出口)

如果递归层数太多可能会导致栈溢出,效率低,重复计算。

可以自定义栈。

10.压缩存储

特殊矩阵

对称矩阵:aij=aji  主对角线i=j  i<j上三角区  i>j下三角区

普通储存n*n二维数组

压缩存储策略:只存储主对角线+下三角区

按照行优先原则存入一维数组,数组大小为(1+n)*n/2

可以实现一个映射函数。

三角矩阵:行优先原则,最后一个位置存储常量c

三对角矩阵(带状矩阵):3(i-1)-1<=k<3i-1

稀疏矩阵:非零元素远远少于矩阵元素的个数

五.串

子串:串中任意个连续的字符组成的子序列

主串:包含子串的串

空串vs空格串

通常对子串增删改查,以子串为操作对象。

串的基本操作:赋值,复制,判空,求串长,清空,销毁,串链接,求子串,比较

注意:长串更大;S>T,返回值大于0,以此类推;串的数据对象限定为字符集;字符集编码。

1.顺序存储

静态数组来实现(定长);动态数组来实现(堆分配存储)【用完手动free】

2.链式存储

存储密度低so每个结点存多个字符

3.字符串的模式匹配

朴素模式匹配

将主串中所有长度为m的子串依次与模式串对比

主串指针i  模式串指针

i=i-j+2;

j=1;

最坏时间复杂度O(mn)

即暴力解法,遍历。

KMP算法

对朴素模式的优化

主串指针不回溯,只有模式串指针回溯

next数组是根据子串求出来的,当前面的字符串已知时若有重复的,从当前字符匹配即可。

求next数组:

next数组第1、2位分别为0、1,后面每一位根据前一位进行比较。后一位与前一位内容相等的话,next值加1,不等则继续寻找直到有相等的为止,如果没有相等 则为一。

next[1]=0表示模式串应右移一位,主串当前指针后移一位,在和模式串第一字符进行比较。

求next数组时间复杂度O(m)

KMP算法最坏时间复杂度O(m+n)。

六.树与二叉树

1.树基本概念

n个结点的有限集

空树n=0;根节点、分支节点、叶子结点、子树。

结点树=所有结点度数和+1;度为m的树第i层最多有m的i-1次方个结点。

2.二叉树

n个结点的有限集

每个结点不存在度数大于2的结点;二叉树可以是空集,根可以有空的左子树和空右子树;二叉树有左右之分次序不能颠倒。

二叉树和树是2个概念

特殊的二叉树:满二叉树、完全二叉树、二叉排序树、平衡二叉树。

3.二叉树存储方式

顺序存储:

要将二叉树的结点编号和完全二叉树对应起来。

链式存储:

找到指定结点p的左/右,和父结点;只能从根节点开始遍历。

n个结点的二叉链表共有n+1个空链域。

4.二叉树的遍历

先序遍历:二叉树为空,不用操作;二叉树非空,访问根节点再先序遍历左子树右子树

中序遍历:二叉树为空,不用操作;非空,先序遍历左子树,访问空节点,先序遍历右子树

后序遍历:二叉树为空,不用操作;非空,先序遍历左子树,先序遍历右子树,访问空节点

5.线索二叉树

在二叉树的结点加上线索。

先序线索二叉树:线索指向先序前驱、先序后继;后序线索二叉树:线索指向后序前驱、后序后继。

二叉树的线索化:中序、先序、后续。

6.树的存储结构

顺序存储:每个结点中保存指向双亲的指针。

数据域和双亲域

链式存储+顺序存储:n个头结点组成一个线性表,并用顺序表存储。

7.树和森林的遍历

树:

先根遍历:先访问根结点,再依次遍历

后根遍历:先对每个子树后根遍历,再返回根结点

层序遍历:若树非空,根结点入队;队列非空,队头元素出队并访问,该元素的孩子依次入队

直至队尾为空。

森林:

先序遍历等同于先根遍历

中序遍历等同于后根遍历

8.哈夫曼树

带权路径最短的树

注意:哈夫曼树的构造和哈度曼编码。

七.图

非线性结构,顶点之间关系任意,顶点前驱后继个数没有限制,任意两个顶点之间都可能相关。

1.存储结构

邻接矩阵

邻接表

十字链表(存储有向图)

邻接多重表(存储无向图)

四种比较

2.图的遍历

从任意指定顶点出发按规则访问所有顶点,每个顶点只被访问一次。

分类:深度优先遍历/广度优先遍历

八.查找

查找表:由同一类型的数据元素构成的集合。

对查找表进行的经常操作为:查找、检索、增加、删除。

静态查找表:对查找表只进行前两种操作。

动态查找表:不仅限于前两种操作。

关键字:数据元素中某个数据项的值,用以标识一个数据元素,如果是唯一标识,则称为主关键字。
查找是否成功:根据给定的值,在查找表中确定一个其关键字等于给定值的元素,如果表中存在这样元素,则称查找成功。

分类:折半查找/索引查找

九.排序

重新排列表中的元素,使表中元素满足按关键字有序的过程(关键字可以相同)

评价指标:时间复杂度、空问复杂度;

稳定性:关键字相同的元素在排序之后相对位置不变,称为稳定的;

分类:

内部排序:数据都在内存一一关注如何使时间、空间复杂度更低;

外部排序:数据太多,无法全部放入内存。

几种排序(这里比较粗糙):

直接插入排序/折半插入排序/希尔排序;

冒泡排序/快速排序;

简单选择排序/堆排序;

归并排序/基数排序。


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
王道408数据结构的应用题是指在408考试中出现的与数据结构相关的实际应用题目。在这些题目中,可能会涉及到顺序查找、折半查找、分块查找等算法。王道书中给出了这些算法的代码实现,但对于考408的同学来说,掌握这些代码并不是必须的,因为408的代码题没有像自主命题那样深入和难度那么大。对于线性表的顺序表示、串以及栈和队列的实现,也不需要手写实现,可以使用标准库来解决问题。只有在题目要求你手动实现栈和队列等数据结构时,才需要进行手写实现。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [408王道数据结构强化——应用题](https://blog.csdn.net/JiangNan_1002/article/details/125828454)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [【23考研】计算机408数据结构代码题强化阶段划重点(王道书)](https://blog.csdn.net/qq_50710984/article/details/125583743)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天枢白泽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值