数据结构复习三:栈和队列

先简要介绍以下栈与队列
栈(stack)是一种后进先出(LIFO)的线性表,仅在表尾(即栈顶)进行插入或删除操作,像火车调度的头进尾出。

在这里插入图片描述
队列(queue)与栈相反,是一种先进先出(FIFO)的线性表,只允许在一端进行插入,而在另一端进行删除,允许插入的一端称为队尾,允许删除的一端则称为队头,就像日常生活中的排队。

在这里插入图片描述

栈的表示和操作的实现

基于已学的知识,我们可以利用顺序存储结构和链式存储结构两种存储结构来实现栈,分别叫做顺序栈、链栈。

顺序栈

顺序栈的数据域主要包括栈顶、栈底指针top、base以及栈的最大容量stacksize,涉及顺序空间上的增删找改等操作,要注意栈顶指针的正确移动;进行数据出栈操作时,数据并没有被删除,而是留在原来的空间,等下一次入栈操作时被覆盖。
具体算法实现略
下面主要看链栈:

链栈

存储结构:

typedef struct StackNode{
    char data;    
    struct StackNode *next;
    }StackNode,*LinkStack;

由于栈的主要操作是在栈顶进行插入和删除,显然以链表头部作为栈顶是最方便的,而且没必要像单链表一样为了操作方便附加一个头结点。

1、初始化
构造一个空栈,因为没有头结点,直接栈顶指针置空即可
2、入栈
算法步骤:
1、为入栈元素e分配空间,用指针p指向
2、将新结点数据域置为e
3、将新结点插入栈顶
4、修改栈顶指针为p
代码实现:

void Push(LinkStack &s,int e){
    LinkStack p=new StackNode;    
    p->data=e;
    p->next=s;    
    s=p;
    }

相当于把前面的元素都往栈里压
3、出栈
算法步骤:
1、判断是否栈空
2、将栈顶元素赋给e(不需要返回时可省略此步)
3、临时保存栈顶元素的空间,以备释放
4、修改栈顶指针,指向新的栈顶元素
5、释放原栈顶元素的空间
代码实现:

void Pop(LinkStack &s){
    if(!s){        
    cout<<"There's Nothing to Pop!\n";        
    return;        
    }    
    LinkStack p=s;    
    s=s->next;    
    delete p;
    }

这个比较好理解
4、取栈顶元素
直接返回栈顶指针s数据域,注意判断栈空

队列的表示和操作的实现

队列也有顺序和链式两种存储表示

顺序队列

存储结构是基地址base以及头尾指针front和rear(假装是指针,其实用作数组下标)
初始front=rear=0
进队rear++
出队front–
front始终指向队列头元素,rear始终指向队尾元素的下一个位置
头尾指针相同时队空
由于这种操作会造成“假溢出”(空间未占满,但rear已至base尾部,新元素无法入队)的问题,所以更提倡循环队列;用模运算来解决新增元素位置的问题。

如何区别循环队列满还是空?
1、牺牲一个元素空间,即队列空间大小为m时,有m-1个元素就认为队满,这样头尾指针相同时队空,而尾指针在循环意义上加1后等于头指针,则认为队满
此时队空条件:Q.front==Q.rear;
队满条件:(Q.rear+1)%maxqsize=Q.front
2、另设标志位区分队空还是队满

循环队列代码实现注意事项:
1、初始分配空间注意留出空间分配失败的出口
2、求长度时应使用(Q.rear-Q.front+maxqsize)%maxqsize,加上一个maxqsize防止出现负数

链队

存储结构:

typedef struct QNode{
    int data;    
    struct QNode *next;
    }QNode,*QueuePtr;
typedef struct{
    QueuePtr front;    
    QueuePtr rear;
}LinkQueue;

初始时队头front队尾rear指向共同结点,指针域置为空,后续元素入队后,rear始终指向队尾元素,出队时注意释放原队头元素所占空间。

————————————————————————————————————
注:本文所有内容均来源于《数据结构(C语言第二版)》(严蔚敏老师著)
图片来源于百度

发布了6 篇原创文章 · 获赞 0 · 访问量 137

猜你喜欢

转载自blog.csdn.net/Roy_F_M/article/details/103833289