数据结构详解笔记:第三章 栈和队列

前言

本章主要详解了栈和队列以及特殊矩阵的压缩知识,其中包括栈的顺序存储和链式存储,队列的顺序存储以及链式存储,循环队列的顺序实现以及优化改进-双端队列,最后介绍了三种特殊矩阵的存储结构压缩算法。

总览:

在这里插入图片描述

①栈的逻辑结构

栈的概念:

​ 栈(stack)只允许在一端进行插入或者删除的线性表。

栈的基本操作:

Initstack(&S):初始化一个空栈S。

StackEmpty(S):判断一个栈是否为空,若栈为空则返回true,否则返回false。

Push(&s,x):进栈,若栈S未满,则将x加入使之成为新栈顶。

Pop(&s,&x):出栈,若栈非空,则弹出栈顶元素,并用×返回。

GetTop(s,&x):读栈顶元素,若栈非空则用x返回栈顶元素。

ClearStack(&S):销毁栈,并释放S占用的内存空间。

②栈的顺序存储结构

顺序栈的结构:

在这里插入图片描述

#define maxsize 10
typedef struct {
ElemType data[maxsize];//静态数组存放栈中元素
int top;//栈顶指针
}Sqstack;
顺序栈的基本操作:
栈的初始化
void InitStack(Sqstack &S){
    S.top == -1;//s.top=0位置在初始化时并没有值
}
void test_stack(){
    Sqstack s;
    InitStack(s);
}
判断栈空
bool StackEmpty(Sqstack S){
    if(S.top == -1)
        return true;//栈空
    else
        return false;//栈不空
}
进栈
bool Push(Sqstack &S,ElemType x){
    if(S.top==Maxsize-1){//栈满
        return false;
    }
    S.data[++S.top]=x;
    return true;
}
出栈
bool Pop(Sqstack &S,ElemType x){
    if(S.top==-1){//栈空
        return false;
    }
    x = S.data[S.top--];
    return true;
}
读出栈顶元素
bool GetTop(Sqstack S,ElemType &x){
    if(S.Top==-1){
        return false;
    }
    else{
        x=S.data[S.top];
        return true;
    }
}
栈的非连续输入和输出问题:

进栈序列:1,2,3…,n

在这里插入图片描述

(*)出栈序列中每一个元素后面所有比他小的元素组成一个递减序列。

合法出栈序列的个数:

在这里插入图片描述

合法出栈序列个数的公式如下:
f ( n ) = C 2 n n n + 1 \mathbf{f}\left( \mathbf{n} \right) =\frac{\mathbf{C}_{2\mathbf{n}}^{\mathbf{n}}}{\mathbf{n}+1} f(n)=n+1C2nn

共享栈

在这里插入图片描述

共享栈的概念

​ 将两个栈底设置在共享空间的两端,栈顶向空间中间延伸。(两个栈共享同一片空间。

判空:

0号栈top == -1
1号栈top == MaxSize

栈满:

top1-top0 == 1

优点:

存取时间复杂度仍为O(1),但空间利用更加有效。

③栈的链式存储结构

在这里插入图片描述

typedef struct linknode{
    Elemtype data;
    struct linkinode *next;
}*linstack;
//所有的操作都在表头进行;

链栈:所有的操作都在表头进行。

④队列的逻辑结构

在这里插入图片描述

队列的概念:

队列( Queue):只允许在表的一端进行插入,表的另一端进行删除操作的线性表。

队列的基本操作:

InitQueue(&Q):初始化队列,构造一个空队列Q。

QueueEmpty(Q):判队列空,若队列Q为空返回true,否则返回 False。

EnQueue(&Q, x):入队,若队列Q末满,则将x加入使之成为新的队尾。

DeQueue(&Q, &x):出队,若队列Q非空,则删除队头元素,并用x返回。

GetHead(&x):读队头元素,若队列Q非空则用回队头元素。
ClearQueue(&Q):锴毁队列,并释放队列Q占用的内存空间。

⑤队列的顺序存储

在这里插入图片描述

顺序队列的概念:

​ 采用顺序存储结构的队列。

#define Maxsize 50
typedef struct{
    ElemType data[Maxsize];
    int rear,front;
}SqQueue;

注意

front指向队头元素,rear指向队尾元素的下一位元素(或 front指向队头元素的前一位置,rear指向队尾元素)。

初始时,front == rear == 0

对空的条件:Q.rear == Q.front

队长的计算:Q.rear-Q.front

队满的条件:Q.rear-Q.front+1==Q.Maxsize。//该条件可以判断队满,但不可以提高队列的空间利用率!

注意:顺序队列中的rear和front下标只可以往后走,不可以回头,所以当rear达到栈尾的Maxsize时,只要有元素出栈(front++),实际的队列存储空间就在减少。

链队的实现:
链队的结构体:
typedef struct{
    LinkNode *front,*rear;
}LinkQueue;
链队的初始化操作:
//初始化队列(带头结点)
void InitQueue(LinkQueue &Q){
    //初始时front, rear都指向头结点
    Q.front=Q.rear=(LinkNode*)malloc(sizeof (LinkNode));
    Q.front->next=NULL;
}

void testLinkQueue(){
	 LinkQueue Q;//声明一个队列
     InitQueue(Q); //初始化队列
}    
链队的入队操作:
//新元素入队(带头结点)
void EnQueue(LinkQueue &Q, ElemType x){
    LinkNode *s=(LinkNode*)malloc(sizeof(LinkNode));
    s->data=x;
    s->next=NULL;
    Q.rear-next=s; //新结点插入到rear之后
    Q.rear=s;//修改表尾指针
}

⑥循环队列的存储结构

循环队列的概念:

在这里插入图片描述

把存储队列的顺序队列在逻辑上视为一个环。

front指针移动:Q.front =(Q.front+1)% MaxSize
rear指针移动:Q.rear =(Q.rear+1)% MaxSize
队列长度:(Q.rear+MaxSize-Q.front)% MaxSize

循环队列的基本操作:
循环队列的初始化:
void InitQueue(SqQueue &Q){
    Q.rear=Q.front=0;
}
循环队列的入队:
bool Enqueue(SqQueue &Q,Elemtype x){
    if(Q.rear+1)%MaxSize==Q.front{
        return false;//采用方法一进行判定队满
    }
    Q.data[Q.rear]=x;
    Q.rear=(Q.rear+1)%MaxSize;
    return 0;
}
循环队列的出队:
bool Dequeue(SqQueue &Q,Elemtype &x){
    if(Q.rear==Q.front){
        return false;
    }
    x=Q.data[Q.front];
    Q.front=( Q.front+1)%MaxSize;//指针后移
    return true;
}
循环队列的队头查找:
bool Dequeue(SqQueue &Q,Elemtype &x){
    if(Q.rear==Q.front){
        return false;
    }
    x=Q.data[Q.front];
    return true;
}
解决循环队列的队满和队空条件相同问题:

队空的条件:Q.rear==Q.front

队满的条件:Q.rear==Q.front

方法一:牺牲一个存储单元

在这里插入图片描述

队空条件:Q.front== Q.rear
队满条件:Q.front==(Q.rear + 1)%MaxSize

方法二:增加一个变量代表元素的个数

初始化:Q.size = 0//用于元素的计数

队空条件:Q.size==0

队满条件:Q.size==MaxSize

方法三:增加tag标识

每次删除操作成功时,都令tag=0;每次插入操作成功时,都令tag=1

初始化:tag=0

队空条件:Q.front=Q.rear&& tag==0

队满条件:Q.front=Q.rear&& tag==1

⑦双端队列的存储结构

双端队列的概念:

在这里插入图片描述

双端队列允许两端都可以进行入队以及出队操作的队列。

⑧栈和队列的应用

括号匹配:

在这里插入图片描述

算法思想

1)初始一个空栈,顺序读入括号。

2)若是右括号,则与栈顶元素进行匹配:

​ 若匹配,则弹出栈顶元素并进行下一个元素;

若不匹配,则该序列不合法。

3)若是左括号,则压入栈中。

4)若全部元素遍历完毕,栈中非空则序列不合法。

括号匹配的算法实现:
#define MaxSize 10//定义栈中元素的最大个数
typedef struct{
    char data[Maxsize];//静态数组存放栈中元素
    int top;//栈顶指针
}SqStack;

bool bracketCheck(char str1, int length) { 
    Sqtack S;
    InitStack(S); //初始化一个栈
    for (int i=0; iclength; i++){
        if (str[i]=s'('||str[i]='['||str[i]=='{'){  
            Push(S, str([i]);} //扫描到左括号,入栈}
          
        else{
            if (StackEmpty(S)) //扫描到右括号,且当前栈空
            return false; //匹配失败
           
           char topElem;
           Pop(S, topElem); //栈顶元素出栈
        if(str[i]==')' && topElem!='(')
              return false;
        if(str[i]==']' && topElem!='[')
              return false;
        if(str[i]=='}'&& topElem!='{')
              return false;
             }
}    
表达式求值:

在这里插入图片描述

中缀运算符转后缀的算法思想

若为数字:

直接加入后缀表达式。
若为运算符:
a.若为’(’,入栈。
b.若为)’,则依次把栈中的运算符加入后缀表达式,直到出现(,并从栈中删除(’。
c.若为’+’,’-’,’/’,’*’,
*栈空,入栈;
*栈顶元素为’(,入栈;
*高于栈顶元素优先级,入栈;
*否则,依次弹出栈顶运算符,直到优先级比它低的运算符或’)'为止。

d.遍历完成,若栈非空则依次弹出所有元素。

⑨特殊矩阵的压缩存储

特殊矩阵和压缩存储的概念:

压缩存储:指多个值相同的元素只分配一个存储空间,对零元素不分配存储空间

特殊矩阵:指具有许多相同矩阵元素或零元素,并且这些相同矩阵元素或零元素的分布有一定规律性的矩阵

特殊矩阵的压缩存储:找岀特殊矩阵中值相同的矩阵元素的分布规律,把那些呈现规律性分布、值相同的多个矩阵元素压缩存储到一个存储空间上

对称矩阵的压缩计算:

在这里插入图片描述

对称矩阵:若对一个n阶方阵A中的任意元素ai,j有ai,j=aj,i(1≤i,j≤n),则称其为对称矩阵。

按行优先

在这里插入图片描述

由数组下标:k=1+2+…+(-1)+j-1,得如下坐标计算公式:
数组下标 k = { i ( i − 1 ) / 2 + j − 1 , i ⩾ j j ( j − 1 ) / 2 + i − 1 , i < j \text{数组下标}\mathbf{k}=\begin{cases} \mathbf{i}\left( \mathbf{i}-1 \right) /2+\mathbf{j}-1,\mathbf{i}\geqslant \mathbf{j}\\ \mathbf{j}\left( \mathbf{j}-1 \right) /2+\mathbf{i}-1,\mathbf{i}<\mathbf{j}\\ \end{cases} 数组下标k={i(i1)/2+j1,ijj(j1)/2+i1,i<j

三角矩阵的压缩计算:

在这里插入图片描述

三角矩阵:

对一个n阶方阵Anxn中上(下)对角区元素均为同一常量,则称为下(上)三角矩阵。

下三角矩阵的下标计算公式:
数组下标 k = { i ( i − 1 ) / 2 + j − 1 , i ⩾ j n ( n + 1 ) / 2 , i < j \text{数组下标}\mathbf{k}=\begin{cases} \mathbf{i}\left( \mathbf{i}-1 \right) /2+\mathbf{j}-1,\mathbf{i}\geqslant \mathbf{j}\\ \mathbf{n}\left( \mathbf{n}+1 \right) /2,\mathbf{i}<\mathbf{j}\\ \end{cases} 数组下标k={i(i1)/2+j1,ijn(n+1)/2,i<j
上三角矩阵的计算公式,同理。

三对角矩阵的压缩计算:

在这里插入图片描述

三对角矩阵:若对个n阶方阵A中的任意元ai,j,当|i-j|>1有ai,j=0(1≤i,j≤n),则称为三对角矩阵

数组下标 k = 3 ∗ ( i − 1 ) − 1 + j − i + 1 + 1 − 1 = 2 i + j − 3 \text{数组下标}\mathbf{k}=3*\left( \mathbf{i}-1 \right) -1+\mathbf{j}-\mathbf{i}+1+1-1=2\mathbf{i}+\mathbf{j}-3 数组下标k=3(i1)1+ji+1+11=2i+j3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Super__Tiger

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

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

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

打赏作者

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

抵扣说明:

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

余额充值