数据结构重点知识汇总

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构重点知识汇总相关的知识,希望对你有一定的参考价值。

1 线性表的合并(编程题)

1.1 有序表的合并

算法步骤:

  1. 创建表长为m+n的空表LC。
  2. 指针pc初始化,指向LC的第一个元素。
  3. 指针pa和pb初始化,分别指向LA和LB的第一个元素。
  4. 当指针pa和pb均为到达相应表尾时,则依次比较pa和pb所指向的元素值,从LA或LB中摘取元素值较小的结点插入到LC的最后。
  5. 如果pb已到达LB的表尾,依次将LA的剩余元素查到LC的最后。
  6. 如果pa已到达LA的表尾,依次将LB的剩余元素查到LC的最后。

算法代码:

void MergeList_Sq(SqList LA,SqList LB,SqList &LC)
LC.length = LA.length+LB.length; // 新表长度为两表长度之和
LC.elem = new ElemType[LC.length]; // 为合并后的新表分配空间
pc = LC.elem; // 指针pc新表的第一个元素
pa = LA.elem; // 指针pa和pb的初值分别指向两个表的第一个元素
pb = LB.elem;
pa_last = LA.elem+LA.length-1; // 指针pa_last 指向LA的最后一个元素
pb_last = LB.elem+LB.length-1; // 指针pb_last 指向LB的最后一个元素
while((pa<=pa_last)&&(pb<=pb_last) // LA和LB均未达到表尾
if(*pa<=*pb)
*pc++ = *pa++; // 依次摘取两表中值较小的结点插入到LC的最后
else
*pc++ = *pb++;


while(pa<=pa_last) // LB到达表尾
*pc++ = *pa++;

while(pb<=pb_last) // LA到达表尾
*pc++ = *pb++;

1.2 链表的合并

算法步骤:

  1. 指针pa和pb初始化,分别指向LA和LB的第一个结点
  2. LC的结点取值为LA的头结点
  3. 指针pc初始化,指向LC的头结点
  4. 当指针pa和pb均未到达相应表尾,则依次比较pa和pb所指向的元素值,从LA或LB中摘取元素值较小的结点插入到LC的最后
  5. 将非空表的剩余段插入到pc所指结点后。
  6. 释放LB的头结点。

算法代码:

void MergeList_L(LinkList &LA,LinkList &LB,LinkList &LC)
pa = LA->next; pb=LB->next; // pa和pb的初值分别指向两个表的第一个结点
LC=LA; // 用LA的头结点作为LC的头结点
pc=LC; // pc的初值指向LC的头结点
while(pa&&pb)
if(pa->data<=pb->data)
pc->next = pa; // 将pa所指结点链接到pc所指结点之后
pc=pa; // pc指向pa
pa = pa->next; // pa指向下一结点
else
pc->next = pb; // 将pb所指结点链接到pc所指结点之后
pc = pb; // pc指向pb
pb = pb->next; // pb指向下一结点


pc->next = pa?pa:pb; // 将非空表的剩余段插入到pc所示结点之后
delete LB; // 释放LB的头结点

2 栈和队列

2.1 栈的基本操作

:限定仅在表尾进行插入和删除操作的线性表。

允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),不含任何数据元素的栈称为空栈。栈又被称为后进先出(Last In First Out)的线性表,简称LIFO结构

栈的插入操作,叫做进栈,也称压栈、入栈。

栈的删除操作,叫做出栈,有的也叫作弹栈。

2.1.1 入栈、进栈

单栈栈空条件:​S->top==-1​

单栈栈满条件:​S->top==MAXSIZE-1​

对于栈的插入,即进栈操作,其实就是做了如下处理:

Status Push(SqStack *S.SElemType e)
if(S -> top == MAXSIZE -1) // 栈满
return ERROR;

S->top++; // 栈顶指针加一
S->data[S->top] = e; // 将新插入元素复制给栈顶空间
return OK;

出栈操作pop,代码如下:

Status Pop(SqStack *S,SElemType *e)
if(S->top==-1) // 栈为空
return ERROR;

*e = S->data[S->top]; // 将要删除的栈顶元素复制给e
S->top--; // 栈顶指针减一
return OK;

2.1.2 共享栈(重要)

栈的顺序存储还是很方便的,因为它只准栈顶进出元素,所以不存在线性表插入和删除时需要移动元素的问题。不过它有一个很大的缺陷,就是必须事先确定数组存储空间大小,万—不够用了,就需要用编程手段来扩展数组的容量,非常麻烦。

共享栈就可以很好的解决这个问题。如果我们有两个相同类型的栈,我们为它们各自开辟了数组空间,极有可能是第—个栈已经满了,再进栈就溢出了,而另一个栈还有很多存储空间空闲,我们完全可以用—个数组来存储两个栈,充分利用这个数组占用的内存空间。

设置数组有两个端点,两个栈有两个栈底,让一个栈的栈底为数组的始端,即下标为0处,另—个栈为数组的末端,即下标为数组长度n-1处。这样两个栈如果增加元素,就是两端点向中间延伸。

栈空条件:​S->top=-1​​​或​​top[i]=bot[i]​

栈满条件:​S->top1+1=S->top2​

共享栈的结构定义:

typedef struct
SElemType data[MAXSIZE];
int top1; // 栈1栈顶指针
int top2; // 栈2栈顶指针
SqDoubleStack;

2.1.2.1 共享栈进栈

对于共享栈的push方法,除了要插入元素值参数外,还需要有一个参数判断是栈1还是栈2的栈号参数StackNumber。

Status Push(SqDoubleStack *S,SElemType e,int stackNumber)
if(S->top1+1=S->top2) // 栈满
return ERROR;

if(stackNumber==1) // 栈1元素进栈
S->data[++S->top1]=e; // 若是栈1则先top1+1后给数组元素赋值
else if(stackNumber==2) // 栈2元素进栈
S->data[--S->top2]=e; // 若是栈2则先top2-1后给数组元素赋值

2.1.2.2 共享栈出栈

对于共享栈的pop方法,参数就只是判断栈1栈2的参数stackNumber,代码如下:

Status Pop(SqDoubleStack *S,SElemType *e.int stackNumber)
if(stackNumber==1)
if(S->top1==-1) // 栈1是空栈
return ERROR;

*e = S->data[S->top--]; // 将栈1的栈顶元素出栈
else if(stackNumber==2)
if(S->top2==MAXSIZE) // 栈2是空栈
return ERROR;

*e = S->data[S->top2++] // 将栈2的栈顶元素出栈

2.2 表达式求值——中缀表达式转后缀表达式(编程题)

本内容分成两块:

  1. 将中缀表达式转化为后缀表达式(栈用来进出运算的符号)。
  2. 将后缀表达式进行运算得出结果(栈用来进出运算的数字)。
2.2.1 中缀表达式转后缀表达式

中缀表达式“9+(3+1)×3+10÷2”转化为后缀表达式“9 3 1 - 3*+10 2 / +”

方法:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的—部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级不高于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。

思路:

  1. 初始化一空栈,用来对符号进出栈使用。
  2. 第—个字符是数字9,输出9,后面是符号‘‘+’’ ,进栈。
  3. 第三个字符是”( “ ,依然是符号,因其只是左括号,还未配对,故进栈。
  4. 第四个字符是数字3,输出,总表达式为9 3,接着是“-”,进栈。
  5. 接下来是数字1,输出,总表达式为9 3 1,后面是符号“)” ,此时,我们需要去匹配此前的“( ”,所以栈顶依次出栈,并输出,直到“( ”出栈为止。此时左括号上方只有“-’’,因此输出“-”。总的输出表达式为9 3 1 -。
  6. 紧接着是符号”ד,因为此时的栈顶符号为“+”,优先级低于“×”, 因此不输出,“*”进栈。接着是数字3,输出,总的表达式为9 3 1 - 3。
  7. 之后是符号“+”,此时当前栈元素“*”,比这个“+”的优先级高,因此栈中元素出栈并输出(没有比“+”更低的优先级,所以全部出栈),总输出表达式为9 3 1 - 3 * +。然后将当前这个符号“+”进栈。也就是说,前6张图的栈底的“+”是指中缀表达式中开头的9后面那个‘‘+” ,而左图中的栈底(也是栈顶)的“+”是指“9+(3-1)×3+”中的最后—个“+”。
  8. 紧接着数字10,输出,总表达式变为9 3 1 - 3 * + 10 2。后是符号“÷“,所以“/”进栈。
  9. 最后一个数字2,输出,总的表达式为9 3 1 - 3 *+10 2。
  10. 因为巳经到最后,所以将栈中符号全部出栈并输出。最终输出的后缀表达式结果为9 3 1 - 3 *+10 2 / +。
2.2.2 后缀表达式计算

后缀表达式:9 3 1 - 3*+10 2 / +

  1. 初始化空栈,此栈用来对要运算的数字进出使用。
  2. 后缀表达式前三个都是数字,所以9、3、1进栈,如图所示。
  3. 接下来是“-”,所以将栈中的1出栈作为减数,3出栈被减数,并运算3-1得到2,再将2进栈,如图所示。
  4. 接着是数字3进栈,如图所示。
  5. 后面是“*”,也就意味着栈中的3和2出栈,2与3相乘得到6,并将6进栈。
  6. 下面是‘‘+” ,所以栈中6和9出栈,9与6相加,得到15,将15进栈。
  7. 接着是10与2两数字进栈。
  8. 接下来是符号‘‘/”,因此,栈顶的2与10出栈,10与2相除,得到5,将5进栈。
  9. 最后—个是符号“+”,所以15与5出栈,并相加,得到20,将20进栈 。
  10. 结果是20出栈,栈变为空。

3 串、数组和广义表

3.1 KMP模式匹配算法

3.1.1 算法原理

假设主串S=“abcdefab”,我们要匹配的子串T=”abcdex“,如果用朴素模式匹配算法,前5个字母,两个串完全相等,直到第6个字母,”f“与“x”不等,如图所示。

接下来按照朴素模式匹配算法,应该是按照上图的步骤2、3、4、5、6,即主串S中当时,首字符与子串T的首字符均不等。

仔细观察就会发现,对于要匹配的子串T来说,“abcdex”首字母“a”与后面串“bcdex”中任意一个字符都不相等。也就是说对于步骤1来说前五位字符分别相等,意味着子串T的首字符“a”不可能与S串的第2位到第5位字符相等。所以,在上图中,步骤2、3、4、5的判断都是多余的。

当我们知道T串中首字符“a”与T中后面的字符均不相等的前提下,T串后面的字符均不相等的前提下,T串的“a”与S串后面的“c”“d”“e”也都可以在步骤1之后就可以确定是不相等的,所以在朴素模式匹配算法中步骤2、3、4、5没有必要,只保留步骤1、6即可,如图所示。

保留步骤6中的判断是因为在步骤1中,虽然我们已经知道了JAVA重点知识汇总(包含Java基础JVMJava并发)

数据结构重点知识汇总

C#.NET重点知识点汇总

让你直接嗨的2W字JAVA重点知识汇总(包含Java基础JVMJava并发)

C#.NET重点知识点汇总

最全面的Python重点知识汇总