快捷搜索:  汽车  科技

栈和队列及其应用(第五章栈和队列)

栈和队列及其应用(第五章栈和队列)③ S(TOP)=X,结束(X为新进栈的元素);② 置TOP=TOP 1(栈指针加1,指向进栈地址);计算机系统中,栈是一个具有以上属性的动态内存区域。程序可以将数据压入栈中,也可以将数据从栈顶弹出。压栈操作使得栈增长变大,而弹出操作使栈减短缩小。进栈(PUSH)算法:① 若TOP≥n时,则给出溢出信息,作出错处理(进栈前首先检查栈是否已满,满则溢出;不满则作②);

第五章 栈和队列5.1 栈5.1.2 栈概述

栈(stack)又名堆栈,它是一种运算受限的线性表。在计算机中栈被定义为一个特殊的容器。其限制是仅允许在表的一端进行插入和删除操作。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈(Push),它是把新元素存放到栈顶元素的上面,使之成为新的栈顶元素;也可以将已经压入到栈中的元素弹出,即从一个栈删除元素又称作出栈或退栈(pop),它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

【栈结构图】

栈和队列及其应用(第五章栈和队列)(1)

栈按照先进后出 (First In Last Out,FILO)的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针。

栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。允许进行插入和删除操作的一端称为栈顶(top),另一端为栈底(bottom);栈底固定,而栈顶浮动;栈中元素个数为零时称为空栈。插入一般称为进栈(push),删除则称为退栈(pop)。栈也称为后进先出表。

计算机系统中,栈是一个具有以上属性的动态内存区域。程序可以将数据压入栈中,也可以将数据从栈顶弹出。压栈操作使得栈增长变大,而弹出操作使栈减短缩小。

5.1.2 栈的表示和实现

进栈(PUSH)算法:

① 若TOP≥n时,则给出溢出信息,作出错处理(进栈前首先检查栈是否已满,满则溢出;不满则作②);

② 置TOP=TOP 1(栈指针加1,指向进栈地址);

③ S(TOP)=X,结束(X为新进栈的元素);

退栈(POP)算法:

① 若TOP≤0,则给出下溢信息,作出错处理(退栈前先检查是否已为空栈, 空则下溢;不空则作②);

② X=S(TOP),(退栈后的元素赋给X);

③ TOP=TOP-1,结束(栈指针减1,指向栈顶)。

定义stack的简单代码:

stack<int> myStack;

入栈:myStack.push(x);

出栈:myStack.pop();

栈顶元素:myStack.top();

判断栈的大小: myStack.size();

判断栈是否为空:myStack.empty();

【程序实现

#include <stdlib.h> #include <stdio.h> #define N 10 typedef struct { int data[N]; int top; } SqStack; //顺序栈类型别名 ​ //初始化栈 SqStack* initStack() { SqStack* s = (SqStack * )malloc(sizeof(SqStack)); s->top = -1; return s; } ​ //取栈顶元素 int getTop(SqStack * s int* e) { if (s->top == -1) { return -1; } *e = s->data[s->top]; return *e; } ​ //进栈 int Push(SqStack * s int e) { if (s->top == N - 1) { return -1; } s->top ; s->data[s->top] = e; return 1; } ​ //出栈 int Pop(SqStack * s int* e) { if (s->top == -1) { return -1; } *e = s->data[s->top]; s->top--; return 1; } ​ //销毁栈 void destroyStack(SqStack * s) { free(s); } ​ //测试栈的初始化、入栈、出栈、获取栈顶元素等功能 int main() { printf("初始化栈...\n"); SqStack* s = initStack(); printf("入栈中...\n"); Push(s 1); Push(s 2); Push(s 3); printf("入栈完成...\n"); printf("获取栈顶元素:\n"); int y; getTop(s &y); printf("y: %d\n" y); printf("出栈:\n"); int x; Pop(s &x); printf("x:%d\n" x); Pop(s &x); printf("x:%d\n" x); Pop(s &x); printf("x:%d\n" x); printf("销毁栈...\n"); destroyStack(s); return 0; }5.2 队列5.2.1 队列概述

与栈相反,队列(queue)是一种先进先出(first in first out,缩写为FIFO)的线性表。它只允许在表的一端进行插入元素,而在另一端删除元素。

在队列中,允许插入的一端叫做队尾(rear),允许删除的一端则称为队头(front)。

队列拥有两种表示和实现方式:

1、队列的链式表示和实现--链队列

2、队列的顺序表示和实现--循环队列

5.2.2 链队列—队列的链式表示和实现

用链表表示的队列简称为链队列。一个链队列需要两个分别指示队头和队尾的指针(分别称为头指针和尾指针)才能唯一确定。为操作方便,给链队列添加一个头结点,并令头指针指向头结点。由此,空的链队列的判断条件为头指针和尾指针均指向头结点。

【链队列结构图】

栈和队列及其应用(第五章栈和队列)(2)

【链队列操作示意图】 

栈和队列及其应用(第五章栈和队列)(3)

【程序实现】

#include <stdio.h> #include <stdlib.h> ​ #define OVERFLOW -2 #define ERROR 0 #define OK 1 ​ typedef int Status; ​ typedef int QElemType; ​ typedef struct QNode { QElemType data; struct QNode *next; }QNode *QueuePtr; ​ typedef struct { QueuePtr front; //队头指针 QueuePtr rear; //队尾指针 }LinkQueue; ​ /*********** 初始化队列 ***********/ Status InitQueue(LinkQueue * Q) { Q->front=Q->rear=(QueuePtr)malloc(sizeof(QNode)); if (!Q->front) exit(OVERFLOW); Q->front->next=NULL; return OK; } ​ /*********** 入队列 ***********/ Status EnQueue(LinkQueue *Q QElemType e) { //插入元素e为Q的新的队尾元素 QueuePtr p; p = (QueuePtr)malloc(sizeof(QNode)); if(!p) exit(OVERFLOW); p->data=e; p->next=NULL; Q->rear->next=p; Q->rear=p; return OK; } ​ /*********** 出队列 ***********/ Status DeQueue(LinkQueue *Q QElemType *e) { //若队列不空 则删除Q的头元素,用e返回其值,并返回OK。 QueuePtr p; if(Q->front==Q->rear) exit(ERROR); p=Q->front->next; *e=p->data; // 一定是*e Q->front->next=p->next; if(Q->rear==p) Q->rear=Q->front; free(p); return OK; } ​ /*********** 销毁队列Q ***********/ Status DestroyQueue(LinkQueue * Q){ while (Q->front) { Q->rear = Q->front->next; free(Q->front); Q->front = Q->rear; } return OK; } ​ int main() { LinkQueue *Q; QElemType e; /*********** 初始化队列 ***********/ InitQueue(Q); printf("请输入5个整数:"); for(int i=0; i<5; i ) { /*********** 入队列 ***********/ scanf("%d" &e); EnQueue(Q e); } printf("输出结果为:\n"); while (Q->front!=Q->rear) { /*********** 出队列 ***********/ DeQueue(Q &e); printf("%d " e); } printf("\n"); /*********** 销毁队列Q ***********/ DestroyQueue(Q); return 0; }5.2.3 循环队列—队列的顺序表示和实现

为充分利用向量空间,克服"假溢出"现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列称为循环队列(Circular Queue)。

循环队列就是将队列存储空间的最后一个位置绕到第一个位置,形成逻辑上的环状空间,供队列循环使用。在循环队列结构中,当存储空间的最后一个位置已被使用而再要进入队运算时,只需要存储空间的第一个位置空闲,便可将元素加入到第一个位置,即将存储空间的第一个位置作为队尾。循环队列可以更简单防止伪溢出的发生,但队列大小是固定的。

在循环队列中,当队列为空时,有front=rear,而当所有队列空间全占满时,也有front=rear。为了区别这两种情况,规定循环队列最多只能有MaxSize-1个队列元素,当循环队列中只剩下一个空存储单元时,队列就已经满了。因此,队列判空的条件时front=rear,而队列判满的条件时front=(rear 1)%MaxSize。

【循环队列结构图】

栈和队列及其应用(第五章栈和队列)(4)

【循环队列操作示意图】**

栈和队列及其应用(第五章栈和队列)(5)

【程序实现】**

#include<stdio.h> #include<stdlib.h> #include<iostream> using namespace std; ​ #define MAXQSIZE 100 #define OK 1 #define ERROR 0 #define OVERFLOW -1 #define False 0 #define True 1 ​ typedef int Status; typedef int QElemType; ​ typedef struct { QElemType *base; //存储空间的基地址 int front; //头指针 int rear; //尾指针 }SqQueue; ​ //循环队列的初始化 Status InitQueue(SqQueue &q) { q.base = new QElemType[MAXQSIZE]; //为队列分配一个最大容量为 MAXQSIZE 的数组空间 if(!q.base) exit(OVERFLOW); //存储分配失败 q.front = q.rear = 0; //头指针和尾指针置为零,队列为空 return OK; } ​ //求循环队列的长度 int QueueLength(SqQueue q) { return (q.rear - q.front MAXQSIZE) % MAXQSIZE; //返回Q的元素个数,即队列长度 } ​ //入队 Status EnQueue(SqQueue &q QElemType e)//插入元素 e 为Q的新的队尾元素 { if((q.rear 1) % MAXQSIZE == q.front) //尾指针在循环意义上加1后等于头指针,表明队满 return ERROR; q.base[q.rear] = e; //新元素插入队尾 q.rear = (q.rear 1) % MAXQSIZE; //队尾指针加1 return OK; } ​ //出队 Status DeQueue(SqQueue &q QElemType &e)//删除 q 的队头元素,用 e 返回其值 { if(q.front==q.rear) return ERROR; //队空 e = q.base[q.front]; //保存队头元素 q.front = (q.front 1) % MAXQSIZE;//队头指针加1 return OK; } ​ //取队头元素 QElemType GetHead(SqQueue q)//返回 的队头元素,不修改队头指针 { if(q.front != q.rear) //队列非空 return q.base[q.front];//返回队头元素的值,队头指针不变 return ERROR; } ​ //队列判满 bool FullQueue(SqQueue &q) { if(q.rear == (q.front 1) % MAXQSIZE) return 1; else return 0; } ​ //队列判空 bool EmptyQueue(SqQueue &q) { if(q.front==q.rear) return 1; else return 0; } ​ int main() { QElemType e; SqQueue q; InitQueue(q); int count = 0; printf("请输入要入队的元素个数:\n"); scanf("%d" &count); for (int i = 0; i < count; i ) { printf("请输入第%d个数: " i 1); int iNum = 0; scanf("%d" &iNum); EnQueue(q iNum); } printf("队列长度: %d\n" QueueLength(q)); printf("获取队列头元素: %d\n" GetHead(q)); printf("输出结果为:\n"); while (q.front != q.rear) { /*********** 出队列 ***********/ DeQueue(q e); printf("%d " e); } printf("\n"); if(FullQueue(q)) printf("队列已满\n"); if(EmptyQueue(q)) printf("队列为空\n"); return 0; }

猜您喜欢: