第3章_堆栈和队列
来源:互联网 发布:音乐合成软件 编辑:程序博客网 时间:2024/06/15 23:15
堆栈和队列都是特殊的线性表。线性表、堆栈和队列三者的数据元素以及数据元素间的逻辑关系完全相同,差别是线性表的插入和删除操作不受限制,而堆栈只能在栈顶插入和删除,队列只能在队尾插入在队头删除。堆栈和队列都可以分别用顺序存储结构和链式存储结构。顺序队列通常采用顺序循环队列方法实现,因为顺序循环队列可以避免顺序队列的“假溢出”问题。
堆栈和队列在各种类型的软件中应用十分广泛,堆栈可以用来完成数据序列的特定转换,队列可以用作 数据元素序列的缓冲存储。
顺序堆栈
SeqStack.h
//顺序堆栈结构体定义typedef struct { DataType stack[MaxStackSize]; int top;}SeqStack;//1.初始化void StackInitiate(SeqStack*S){ S->top = 0;}//2.判断是否为空int StackNotEmpty(SeqStack S){ //判断顺序堆栈S非空否,非空返回1,否则返回0 if(S.top <= 0) return 0; else return 1;}//3.入栈int StackPush(SeqStack*S,DataType x){ //把数据元素值x压入顺序堆栈S,入栈成功返回1,否则返回0 if(S->top >= MaxStackSize) { printf("堆栈已满无法插入!\n"); return 0; } else { S->stack[S->top] = x; S->top++; return 1; }}//4.出栈int StackPop(SeqStack*S,DataType*d){ //弹出顺序堆栈S的栈顶数据元素值到参数d,出栈成功返回1,否则返回0 if(S->top <= 0) { printf("堆栈已空无数据元素出栈!\n"); return 0; } else { S->top--; *d = S->stack[S->top]; return 1; }}//5.取栈顶数据元素int StackTop(SeqStack S,DataType*d){ if(S.top <= 0) { printf("堆栈已空!\n"); return 0; } else { *d = S.stack[S.top - 1]; return 1; }}
main.c
#include<stdio.h> //该文件包含printf()函数#include<stdlib.h> //该文件包含exit()函数#define MaxStackSize 100 //定义MaxStackSize 为100typedef int DataType; //定义DataType为int数据类型#include "SeqStack.h"void main(void){ SeqStack myStack; int i,x; StackInitiate(&myStack); for(i = 0;i < 10; i++) { if(StackPush(&myStack,i + 1) == 0) //入栈10个数据元素 { printf("错误!\n"); return ; } } if(StackTop(myStack,&x) == 0) //取栈顶数据元素 { printf("错误!\n"); return ; } else { printf("当前栈顶数据元素为:%d\n",x); } printf("依次出栈的数据元素序列如下:\n"); while(StackNotEmpty(myStack)) { StackPop(&myStack,&x); printf("%d ",x); } printf("\n");}/*当前栈顶数据元素为:10依次出栈的数据元素序列如下:10 9 8 7 6 5 4 3 2 1Press any key to continue*/
链式堆栈
typedef struct snode{ DataType data; struct snode *next;}LSNode;//1.初始化void StackInitiate(LSNode** head){ if((*head = (LSNode*)malloc(sizeof(LSNode))) == NULL) exit(1); (*head)->next = NULL;}//2.判空int StackNotEmpty(LSNode*head){ //判断堆栈是否非空,非空返回1;空返回0 if(head->next == NULL) return 0; else return 1;}//3.入栈int StackPush(LSNode*head,DataType x){ //把数据元素x插入链式堆栈head的栈顶作为新的栈顶 LSNode*p; if((p = (LSNode*)malloc(sizeof(LSNode))) == NULL) { printf("内存空间不中无法插入!\n"); return 0; } p->data = x; p->next = head->next; //新结点链入栈顶 head->next = p; //新结点成为新的栈顶 return 1;}//4.出栈int StackPop(LSNode*head,DataType* d){ LSNode*p = head->next; if(p == NULL) { printf("堆栈已空出错!\n"); return 0; } head->next = p->next; //删除原栈顶结点 *d = p->data; //原栈顶结点元素赋予d free(p); //释放原栈顶结点内存空间 return 1;}//5.取栈顶数据元素int StackTop(LSNode*head,DataType*d){ //取栈顶元素并把栈顶元素由参数d带回 LSNode *p = head->next; if(p == NULL) { printf("堆栈已空出错!"); return 0; } *d = p->data; return 1;}//6.撤消动态申请空间void Destroy(LSNode*head){ LSNode*p,p1; p = head; while(p != NULL) { p1 = p; p = p->next; free(p1); }}
#include<string.h>#include<stdio.h> //该文件包含printf()函数#include<stdlib.h> //该文件包含exit()函数#define MaxStackSize 100typedef char DataType;#include "SeqStack.h"void ExpIsCorrect(char exp[],int n);void main(void){ char a[] = "(())abc{]()}"; //左右括号配对次序不正确 char b[] = "(()))abc{[]}"; //右括号多于左括号 char c[] = "(()()abc{[]}"; //左括号多于右括号 char d[] = "(())abc{[]}"; //左右括号配匹正确 int n1 = strlen(a); int n2 = strlen(b); int n3 = strlen(c); int n4 = strlen(d); ExpIsCorrect(a,n1); ExpIsCorrect(b,n2); ExpIsCorrect(c,n3); ExpIsCorrect(d,n4);}/************************************************************************//* 1.假设一个算术表达式的包含圆 括号、方括号和花括号三种类型的括号,编写一个判别表达式中括号是否正确配对的函数,并设遍地开花个测试主函数。算法思想:算术表达式中右括号和左括号匹配的次序正好符 合后到的括号要最先被匹配的“后进先出”堆栈操作特点,因此,可以借助一个堆栈来进行判断。括号匹配共有4种情况:a.左右括号配对次序不正确;b.右括号多于左括号c.左括号多于右括号d.左右括号匹配正确*//************************************************************************/void ExpIsCorrect(char exp[],int n){ //判断有n个字符的字符串exp左右括号是否配对正确 SeqStack myStack; //定义链式堆栈 int i; char c; StackInitiate(&myStack); for(i = 0;i < n; i++) { if((exp[i] == '(') || (exp[i] == '[') || (exp[i] == '{')) { StackPush(&myStack,exp[i]); } else if(exp[i] == ')' && StackNotEmpty(myStack) && StackTop(myStack,&c) && c == '(') { StackPop(&myStack,&c); //出栈 } else if(exp[i] == ')' && StackNotEmpty(myStack) && StackTop(myStack,&c) && c != '(') { printf("左右括号配对次序不正确!\n"); return ; } else if(exp[i] == ']' && StackNotEmpty(myStack) && StackTop(myStack,&c) && c == '[') { StackPop(&myStack,&c); } else if(exp[i] == ']' && StackNotEmpty(myStack) && StackTop(myStack,&c) && c != '[') { printf("左右括号配对次序不正确!\n"); return ; } else if(exp[i] == '}' && StackNotEmpty(myStack) && StackTop(myStack,&c) && c == '{') { StackPop(&myStack,&c); //出栈 } else if(exp[i] == '}' && StackNotEmpty(myStack) && StackTop(myStack,&c) && c != '{') { printf("左右括号配对次序不正确!\n"); return ; } else if(((exp[i] == ')') || (exp[i] == ']') || exp[i] == '}') && !StackNotEmpty(myStack)) { printf("右括号多于左括号!\n"); return ; } } if(StackNotEmpty(myStack)) { printf("左括号多于右括号!\n"); } else { printf("左右括号匹配正确!\n"); }}/*左右括号配对次序不正确!右括号多于左括号!左括号多于右括号!左右括号匹配正确!Press any key to continue*/
队列也是一种特殊的线性表,队列的数据元素以及数据元素间的逻辑关系与线性表完全相同,其差别是线性表允许在任意位置插入和删除,而队列只允许在其一端进行插入操作,在其另一端进行删除操作。队列中允许进行插入操作的一端称为队尾,允许进行删除操作的一端称为队头。队头和队尾分别由队头指示器(或称队头指针)和队尾指示器(或称队尾指针)指示。队列的插入操作通常称为入队列,队列的删除操作通常称为出队列。当队列中没有数据元素时称为空队列。
顺序队列
typedef struct { DataType queue[MaxQueueSize]; int rear; //队尾指针 int front; //队头指针 int count; //计数器} SeqCQueue;//1.初始化void QueueInitiate(SeqCQueue*Q) //初始化顺序循环队列Q{ Q->rear = 0; //定义初始队尾指针下标值 Q->front = 0; //定义初始队头指针下标值 Q->count = 0; //定义初始计数器值}//2.非空否int QueueNotEmpty(SeqCQueue Q){ //判断顺序循环队列Q非空否,非空时返回1,否则返回0 if(Q.count != 0) return 1; else return 0;}//3.入队列int QueueAppend(SeqCQueue*Q,DataType x){ //把数据元素值x插入顺序循环队列Q的队尾,成功返回1,失败则返回0 if(Q->count > 0 && Q->rear == Q->front) { printf("队列已满无法插入!\n"); return 0; } else { Q->queue[Q->rear] = x; Q->rear = (Q->rear + 1) % MaxQueueSize; Q->count++; return 1; }}//4.出队列int QueueDelete(SeqCQueue*Q,DataType *d){ //删除顺序循环队列Q的队头元素并赋给d,成功返回1,失败返回0 if(Q->count == 0) { printf("队列已空无数据元素出队列!\n"); return 0; } else { *d = Q->queue[Q->front]; Q->front = (Q->front + 1) % MaxQueueSize; Q->count--; return 1; }}//5.取队头元素int QueueGet(SeqCQueue Q,DataType*d){ //取顺序循环队列Q的当前队头元素并赋给d,成功返回1,失败返回0 if(Q.count == 0) { printf("队列已空无数据元素可取!\n"); return 0; } else { *d = Q.queue[Q.front]; return 1; }}
链式队列
typedef struct qnode { DataType data; struct qnode * next;}LQNode;typedef struct { LQNode* front; //队头指针 LQNode* rear; //队尾指针}LQueue;//1.初始化void QueueInitiate(LQueue*Q){ Q->rear = NULL; //定义初始队尾指针 Q->front = NULL; //定义初始队头指针}//2.非空否int QueueNotEmpty(LQueue Q){ //判断链式队列Q非空否,非空返回1,否则返回0 if(Q.front == NULL) return 0; else return 1;}//3.入队列int QueueAppend(LQueue*Q,DataType x){ //把数据元素值x插入链式队列Q的队尾,入队列成功返回1,否则返回0 LQNode*p; if((p = (LQNode*)malloc(sizeof(LQNode))) == NULL) { printf("内存空间不中!"); return 0; } p->data = x; p->next = NULL; if(Q->rear != NULL) Q->rear->next = p; Q->rear = p; if(Q->front == NULL) Q->front = p; return 1;}//4.出队列int QueueDelete(LQueue*Q,DataType*d){ //删除链式队列Q的队头数据元素值到d,出队列成功返回1,否则返回0 LQNode*p; if(Q->front == NULL) { printf("队列已空无数据元素出队列!\n"); return 0; } else { *d = Q->front->data; p = Q->front; Q->front = Q->front->next; if(Q->front == NULL) Q->rear = NULL; free(p); return 1; }}//5.取队头数据元素int QueueGet(LQueue Q,DataType*d){ //取链式队列Q的当前队头数据元素值到d,成功返回1,否则返回0 if(Q.front == NULL) { printf("队列已空无数据元素出队列!\n"); return 0; } *d = Q.front->data; return 1;}//6.撤消动态申请空间void Destroy(LQueue Q){ LQNode*p,*p1; p = Q.front; while(p != NULL) { p1 = p; p = p->next; free(p1); }}
队列应用
#include <stdio.h>#include <string.h>#define MaxQueueSize 100#define MaxStackSize 100typedef char DataType;#include "SeqQueue.h"#include "SeqStack.h"void HuiWen(char str[]);void main(void){ char str1[] = "ABCDEDCBA"; char str2[] = "ABCDEDCAB"; HuiWen(str1); HuiWen(str2);}/*ABCDEDCBA是回文!ABCDEDCAB不是回文!Press any key to continue*//************************************************************************//* 1.编程序判 断一个字符序列是否是回文。回文是指一个字符序列以中间字符为基准两边字符完全相同,如字符序列“ABCDEDCBA”就是回文,而字符序列“ABCDEDBAC”就不是回文。算法思想:设字符数组str中存放了要判断的字符串。把字符数组中的字符逐个分别存入队列和堆栈,然后逐个出队列和退栈并比较出队列的字符和退栈的字符是否相等,若全部相等则该字符序列是回文,否则就不是回文。*//************************************************************************/void HuiWen(char str[]){ SeqCQueue myQueue; SeqStack myStack; char x,y; int i,length; length = strlen(str); QueueInitiate(&myQueue); StackInitiate(&myStack); for(i = 0;i < length; i++) { QueueAppend(&myQueue,str[i]); StackPush(&myStack,str[i]); } while(QueueNotEmpty(myQueue) == 1 && StackNotEmpty(myStack) == 1) { if(QueueDelete(&myQueue,&x) == 1 && StackPop(&myStack,&y) == 1 && x != y) { printf("%s不是回文!\n",str); return ; } } if(QueueNotEmpty(myQueue) || StackNotEmpty(myStack)) { printf("%s不是回文!\n",str); } else printf("%s是回文!\n",str);}
优先级队列
优先级队列是带有优先级的队列。队列是数据元素的先进先出表,即最先进入队列的元素将最先被删除。但在有些软件系统中,有时也要求把进入队列中的元素分优先级,出队列时首先选择优先级最高的元素出队列(即优先级高的元素被先服务),对优先级相同的元素则按先进先出的原则出队列。显示,优先级队列和一般队列的主要区别是:优先级队列的出队列操作不是把队头元素出队列,而是把队列中优先级最高的数据元素出队列。
顺序优先级队列
typedef struct { int priority; ElemType elem;} DataType;typedef struct { DataType queue[MaxQueueSize]; int size;}SeqPQueue;//1.初始化void QueueInitiate(SeqPQueue*Q){ Q->size = 0; //定义初始元素个数}//2.空否int QueueNotEmpty(SeqPQueue Q){ //判断顺序优先队列Q非空否,非空返回1,否则返回0 if(Q.size <= 0) return 0; else return 1;}//3.入队int QueueAppend(SeqPQueue*Q,DataType x){ //把数据元素值x插入顺序优先队列Q的队尾,成功返回1,失败返回0 if(Q->size >= MaxQueueSize) { printf("队列已满无法插入!\n"); return 0; } else { Q->queue[Q->size] = x; Q->size++; return 1; }}//4.出队int QueueDelete(SeqPQueue*Q,DataType*d){ //删除顺序优先队列Q中优先级最高的元素并赋给d,成功返回1,失败返回0 DataType min; int minIndex,i; if(Q->size <= 0) { printf("队列已空无数据元素出队列!\n"); return 0; } else { min = Q->queue[0]; //初始选queue[0]为优先级最高的元素 minIndex = 0; //minIndex为优先级最高元素的下标 for(i = 1;i < Q->size; i++) { if(Q->queue[i].priority < min.priority) { min = Q->queue[i]; minIndex = i; } } *d = Q->queue[minIndex]; //找到优先级最高的元素 for(i = minIndex + 1; i < Q->size; i++) //数据元素依次前移 Q->queue[i - 1] = Q->queue[i]; Q->size--; //元素个数减1 return 1; }}int QueueGet(SeqPQueue*Q,DataType*d){ //取顺序优先队列Q中优先级最高的元素并赋给d,成功返回1,失败返回0 DataType min; int minIndex,i; if(Q->size <= 0) { printf("队列已空无数据元素可取!\n"); return 0; } else { min = Q->queue[0]; //初始选queue[0]为优先级最高的元素 minIndex = 0; //minIndex为优先级最高元素的下标 for(i = 1;i < Q->size; i++) { if(Q->queue[i].priority < min.priority) { min = Q->queue[i]; minIndex = i; } } *d = Q->queue[minIndex]; return 1; }}
优先级队列应用
#include <stdio.h>#include <stdlib.h>#define MaxQueueSize 100typedef int ElemType; //定义data域的数据类型为int#include "SeqPQueue.h" //包含顺序优先级队列/************************************************************************//* 1.设计一个程序,模仿操作系统的进程管理问题。进程服务按优先级高的先服务,优先级相同的先到先服务的原则管理。设文件task.dat中存放了仿真进程服务请求数据,其中第一列表示进程的任务号,第二列表示进程的优先级。文件task.dat中的仿真进程服务请求数据如下:1 302 203 404 205 0设计:文件task.dat中每一个进程服务的请求数据包含任务号和优先级两项。可直接用上述结构体DataType中的抽象数据类型ElemType为int数据类型。*//************************************************************************/void main(void){ SeqPQueue myPQueue; FILE * fp; DataType task; int i; if((fp = fopen("task.dat","r")) == NULL) { printf("不能打开文件task.dat!"); exit(0); } QueueInitiate(&myPQueue); //初始化顺序优先级队列 while(!feof(fp)) { fscanf(fp,"%d\t%d",&task.elem,&task.priority); QueueAppend(&myPQueue,task); //把数据入队列 } i = 1; printf("序号\t任务号\t优先级\n"); while(QueueNotEmpty(myPQueue)) //逐个出队 { QueueDelete(&myPQueue,&task); //出队 printf("%d\t%d\t%d\n",i,task.elem,task.priority); i++; }}/*序号 任务号 优先级1 5 02 2 203 4 204 1 305 3 40Press any key to continue*/
阅读全文
0 0
- 第3章_堆栈和队列
- 黑马程序员_堆栈和队列两种数据结构
- 黑马程序员_队列_堆栈
- 字符串堆栈和队列
- 堆栈和队列
- 数据结构-堆栈和队列
- 堆栈和队列
- 【数据结构】堆栈和队列
- js队列和堆栈
- 堆栈和队列
- 数据结构--堆栈和队列
- 队列和堆栈
- 数据结构堆栈和队列
- 数据结构堆栈和队列
- Go队列和堆栈
- PHP 堆栈和队列
- 堆栈和队列
- 数据结构-堆栈和队列
- Android任务栈和启动模式
- 【关于学习】
- Python中的文件IO操作(读写文件、追加文件)
- Qt中的事件处理
- [luogu1004]方格取数(dp,亚瑟)
- 第3章_堆栈和队列
- a
- 浮点数与十六进制的转换
- binary-tree-maximum-path-sum
- 阿里路由框架--ARouter 源码解析之初始化ARouter
- c/c++基础题(1)
- 页面乱码问题总结
- robotframework+jenkins运行报Build step 'Execute Windows batch command' marked build as failure解决方法
- Android-PickerView系列之介绍与使用篇(一)