C实现栈和队列
2015-06-20 14:37
330 查看
这两天再学习了数据结构的栈和队列,思想很简单,可能是学习PHP那会没有直接使用栈和队列,写的太少,所以用具体代码实现的时候出现了各种错误,感觉还是C语言功底不行。栈和队列不论在面试中还是笔试中都很重要,下面就介绍一下这两天栈和队列的学习经验
一:栈的学习
基础东西:栈是在表尾进行插入和删除的线性表,由此可知表尾是栈顶,表头为栈底,没有任何元素的栈是空栈。根据栈的结构可以知道:栈修改是按后进先出的原则进行的(LIFO),基本操作有插入、删除、初始化、取栈顶元素,判断是否是空栈等等。
栈的表示和实现:和上一节介绍过的线性表相似栈有两种表示方法(顺序表示和链式表示)因为和线性表类似(特殊的线性表)我只介绍顺序栈的就可以了。
顺序栈:利用一组连续的地址来依次存储栈的各个元素(从栈底到栈顶),用top指针指示栈顶元素,base指针指示栈底元素,所以top=base可以作为空栈的判断。插入一个元素top++,出栈一个元素top--,所以非空栈的指针始终在栈顶元素的下一个位置
顺序栈的结构体表示:
下面是我练习的代码,实现了栈的定义、栈的初始化、进栈操作、出栈操作、得到栈顶元素、遍历栈。需要注意的是出栈操作和得到栈顶元素的操作是有区别的,希望对大家栈的学习和回顾有所帮助。代码都是自己练习过的,可以直接运行
二:队列的学习:
队列和栈相反,是一种先进先出(FIFO)的线性表,只能在一端进行插入,一端进行删除
基础:在队列中,进行出入的一端称作队尾,允许删除的一端称作队首。和线性表差不多可以用顺序和链式表示。
双端队列:双端队列是限定插入和删除的操作在表的两端进行的线性表,用的不是很多。
循环队列:百度上解释:”将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量“,其实就是把队列首尾相连,但是要有一定的要求,不是想怎么连就怎么连。
下面给出链表的结构体:
下面这段代码练习了队列的基本操作:队列结构体定义(比栈的稍微复杂一点)、在队尾插入新元素、删除队头元素、销毁队列、打印队列、循环队列的定义等等,这部分牵涉到好多的指针操作,如果有些困难可以在纸上划出队列的结构,列出指针的操作前后变化,就容易多了(个人感觉如果线性表学好了,这些操作根本不在话下)。需要注意循环队列操作中取余操作:(Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
废话不多说,下面直接给出具体实现的代码:
一:栈的学习
基础东西:栈是在表尾进行插入和删除的线性表,由此可知表尾是栈顶,表头为栈底,没有任何元素的栈是空栈。根据栈的结构可以知道:栈修改是按后进先出的原则进行的(LIFO),基本操作有插入、删除、初始化、取栈顶元素,判断是否是空栈等等。
栈的表示和实现:和上一节介绍过的线性表相似栈有两种表示方法(顺序表示和链式表示)因为和线性表类似(特殊的线性表)我只介绍顺序栈的就可以了。
顺序栈:利用一组连续的地址来依次存储栈的各个元素(从栈底到栈顶),用top指针指示栈顶元素,base指针指示栈底元素,所以top=base可以作为空栈的判断。插入一个元素top++,出栈一个元素top--,所以非空栈的指针始终在栈顶元素的下一个位置
顺序栈的结构体表示:
//栈的顺序存储表示 typedef struct{ SElemType *base;//在栈构造之前和销毁后值是NULL SElemType *top; int stacksize; //已分配的存储空间 }SqStack;
下面是我练习的代码,实现了栈的定义、栈的初始化、进栈操作、出栈操作、得到栈顶元素、遍历栈。需要注意的是出栈操作和得到栈顶元素的操作是有区别的,希望对大家栈的学习和回顾有所帮助。代码都是自己练习过的,可以直接运行
/** * 栈 * @author:zhaoyafei * @time:2015-6-16 */ #include <stdio.h> #include <stdlib.h> //预定义常量 #define OK 1 #define OVERFLOW -2 #define ERROR 0 #define STACK_INIT_SIZE 100 //存储空间的初始分配量 #define STACKINCREMENT 10 //存储空间的分配增量stackincrement typedef int SElemType; //栈的顺序存储表示 typedef struct{ SElemType *base;//在栈构造之前和销毁后值是NULL SElemType *top; int stacksize; //已分配的存储空间 }SqStack; //栈的初始化操作 int InitStack(SqStack &S){ S.base = (int *)malloc(STACK_INIT_SIZE * sizeof(SqStack)); if(!S.base){ exit(OVERFLOW);//分配空间失败 } S.top = S.base; S.stacksize = STACK_INIT_SIZE; return OK; } //进栈操作 int Push(SqStack &S, int e){ if(S.top - S.base >= S.stacksize){//栈空间已经满 S.base = (int *)realloc(S.base,(S.stacksize + STACKINCREMENT) * sizeof(SqStack)); if(!S.base){ exit(OVERFLOW);//分配失败 } S.top = S.base + S.stacksize; S.stacksize += STACKINCREMENT; } *S.top++ = e; return OK; } //出栈 int Pop(SqStack &S,int &e){ if(S.top != S.base){ e = * --S.top; return OK; }else{ exit(OVERFLOW); } } //得到顶部元素 void GetElem(SqStack S, int &e){ if(S.top != S.base){ e = * (S.top - 1); }else{ exit(OVERFLOW); } } //打印出栈各个元素 void PrintfStack(SqStack S){ while(*(S.top-1) && S.top != S.base){//证明不是空栈,且有值 S.top = S.top - 1; printf("%d ",*S.top); } printf("\n"); } int main(){ int e,i; int TextData[6] = {9,2,8,1,7,6}; SqStack Sa,Sb; InitStack(Sa);//初始化栈Sa; for(i = 0; i < 6; i++){ Push(Sa,TextData[i]); } printf("**************栈基本操作*************\n"); //初始化数据 printf("初始化后的Sa:"); PrintfStack(Sa); //得到栈顶元素 GetElem(Sa,e); printf("Sa栈顶元素是:%d\n",e); //初始化数据 printf("顶部出栈后Sa:"); Pop(Sa,e); PrintfStack(Sa); }
二:队列的学习:
队列和栈相反,是一种先进先出(FIFO)的线性表,只能在一端进行插入,一端进行删除
基础:在队列中,进行出入的一端称作队尾,允许删除的一端称作队首。和线性表差不多可以用顺序和链式表示。
双端队列:双端队列是限定插入和删除的操作在表的两端进行的线性表,用的不是很多。
循环队列:百度上解释:”将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量“,其实就是把队列首尾相连,但是要有一定的要求,不是想怎么连就怎么连。
下面给出链表的结构体:
//单链队列 typedef struct QNode{ QElemType data; struct QNode *next; }QNode, *QueuePtr; typedef struct{ QueuePtr front; QueuePtr rear; }LinkQueue; //循环队列 typedef struct{ QElemType *base; int front; int rear; }SqQueue;
下面这段代码练习了队列的基本操作:队列结构体定义(比栈的稍微复杂一点)、在队尾插入新元素、删除队头元素、销毁队列、打印队列、循环队列的定义等等,这部分牵涉到好多的指针操作,如果有些困难可以在纸上划出队列的结构,列出指针的操作前后变化,就容易多了(个人感觉如果线性表学好了,这些操作根本不在话下)。需要注意循环队列操作中取余操作:(Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
废话不多说,下面直接给出具体实现的代码:
#include <stdio.h> #include <stdlib.h> //头文件 #define ERROR -1 #define OK 2; #define TRUE 1; #define OVERFLOW -2; //最大队列长度 #define MAXQSIZE 100 typedef int Status; typedef int QElemType; //单链队列 typedef struct QNode{ QElemType data; struct QNode *next; }QNode, *QueuePtr; typedef struct{ QueuePtr front; QueuePtr rear; }LinkQueue; //循环队列 typedef struct{ QElemType *base; int front; int rear; }SqQueue; //********************************队列的基本操作***************************** //初始化队列 Status InitQueue(LinkQueue &Q){ Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));//动态分配空间 if(!Q.front){ exit(ERROR);//分配空间失败 } Q.front->next = NULL; return OK; } //在队尾插入新元素 Status EnQueue(LinkQueue &Q, int e){ QueuePtr p; p = (QueuePtr)malloc(sizeof(QNode)); if(!p){ exit(ERROR);//分配失败 } p->data = e; p->next = NULL; Q.rear->next = p; Q.rear = p; return OK; } void DestroyQueue(LinkQueue &Q){ if(Q.front != Q.rear){ while(Q.front){ Q.rear = Q.front->next; free(Q.front); Q.front = Q.rear; } } } //删除队头元素,并用e返回 Status DeQueue(LinkQueue &Q, int &e){ if(Q.front != Q.rear){//先判断队列是否为空 QueuePtr p; e = Q.front->next->data; if(Q.front->next == Q.rear){//队列只有一个元素 p = Q.rear; Q.rear = Q.front; Q.front->next = NULL; }else{ p = Q.front->next; Q.front->next = p->next; p->next = NULL; } free(p); return OK; } } //打印队列元素 void PrintQueue(LinkQueue Q){ if(Q.front != Q.rear){ do{ Q.front = Q.front->next; printf("%d ",Q.front->data); }while(Q.front->next); } printf("\n"); } //********************************循环队列的基本操作***************************** //初始化队列 Status InitQueueXh(SqQueue &Q){ Q.base = (int *)malloc(MAXQSIZE * sizeof(int));//动态分配空间 if(!Q.base){ exit(ERROR);//分配空间失败 } Q.front = Q.rear = 0; return OK; } //在队尾插入新元素 Status EnQueueXh(SqQueue &Q, int e){ if((Q.rear + 1) % MAXQSIZE == Q.front){ exit(ERROR);//队循环列已满 } Q.base[Q.rear] = e; Q.rear = (Q.rear + 1) % MAXQSIZE; return OK; } int DestroyQueueXh(SqQueue &Q){ return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE; } //删除队头元素,并用e返回 Status DeQueueXh(SqQueue &Q, int &e){ if(Q.front == Q.rear){//先判断队列是否为空 return false; } e = Q.base[Q.front]; Q.front = (Q.front + 1) % MAXQSIZE; return OK; } //打印队列元素 void PrintQueueXh(SqQueue Q){ if(Q.front != Q.rear){ do{ printf("%d ",Q.base[Q.front]); Q.front++; }while(Q.front != Q.rear); } printf("\n"); } //主方法 int main(){ int e, i; int Data[6] = {3,1,7,8,9,1}; printf("****************队列的基本操作**************\n"); //初始化队列 LinkQueue Qa, Qb; InitQueue(Qa); //初始化Qa for(i = 0; i < 6; i++){ EnQueue(Qa,Data[i]); } //打印Qa printf("Qa的各个元素:"); PrintQueue(Qa); //删除队首元素 DeQueue(Qa,e); printf("删除Qa的队首元素:%d\n",e); printf("删除首元素后的Qa: "); PrintQueue(Qa); printf("销毁后的Qa: "); DestroyQueue(Qa); PrintQueue(Qa); printf("**************循环队列的基本操作************\n"); //初始化队列 SqQueue QaXh, QbXh; InitQueueXh(QaXh); //初始化Qa for(i = 0; i < 6; i++){ EnQueueXh(QaXh,Data[i]); } //打印Qa printf("QaXh的各个元素:"); PrintQueueXh(QaXh); //删除队首元素 DeQueueXh(QaXh,e); printf("删除QaXh的队首元素:%d\n",e); printf("删除首元素后的QaXh: "); PrintQueueXh(QaXh); printf("得到QaXh的元素个数:%d\n",DestroyQueueXh(QaXh)); }
相关文章推荐
- POJ 1062 昂贵的婚礼(Dijkstra)
- Eclipse - Method NewStringUTF() could not be resolved
- 最小点覆盖问题详解
- 黑马程序员--java学习笔记第八天
- XMPP功能列表
- 《你的灯亮着吗》阅读笔记1
- bottle框架学习(二)之HTTP请求
- onTouch和onTouchEvent的区别
- OTL调用存储过程和函数
- wxWidgets开始编程
- 查询处理图解
- codeblocks工程下关于结构体的一个问题
- ffmpeg 从内存中读取数据(或将数据输出到内存)
- Linux字符设备驱动(一)
- java I/O 输入输出流详解
- excl筛选求和
- Tomcat启动报Error listenerStart错误
- Mac OS X 10.10.3对SSD开启Trim功能
- $('#checkbox').attr('checked'); 回报checked或undefined该解决方案
- Uva - 246 - 10-20-30