C实现栈和队列

  这两天再学习了数据结构的栈和队列,思想很简单,可能是学习PHP那会没有直接使用栈和队列,写的太少,所以用具体代码实现的时候出现了各种错误,感觉还是C语言功底不行。栈和队列不论在面试中还是笔试中都很重要,下面就介绍一下这两天栈和队列的学习经验

一:栈的学习

基础东西:栈是在表尾进行插入和删除的线性表,由此可知表尾是栈顶,表头为栈底,没有任何元素的栈是空栈。根据栈的结构可以知道:栈修改是按后进先出的原则进行的(LIFO),基本操作有插入、删除、初始化、取栈顶元素,判断是否是空栈等等。

栈的表示和实现:和上一节介绍过的线性表相似栈有两种表示方法(顺序表示和链式表示)因为和线性表类似(特殊的线性表)我只介绍顺序栈的就可以了。

顺序栈:利用一组连续的地址来依次存储栈的各个元素(从栈底到栈顶),用top指针指示栈顶元素,base指针指示栈底元素,所以top=base可以作为空栈的判断。插入一个元素top++,出栈一个元素top--,所以非空栈的指针始终在栈顶元素的下一个位置

顺序栈的结构体表示:

1 //栈的顺序存储表示
2 typedef struct{
3     SElemType *base;//在栈构造之前和销毁后值是NULL
4     SElemType *top;
5     int stacksize; //已分配的存储空间
6 }SqStack;

  下面是我练习的代码,实现了栈的定义、栈的初始化、进栈操作、出栈操作、得到栈顶元素、遍历栈。需要注意的是出栈操作和得到栈顶元素的操作是有区别的,希望对大家栈的学习和回顾有所帮助。代码都是自己练习过的,可以直接运行

  1 /**
  2  * 栈
  3  * @author:zhaoyafei
  4  * @time:2015-6-16
  5  */
  6 #include <stdio.h>
  7 #include <stdlib.h>
  8 
  9 //预定义常量
 10 #define OK 1
 11 #define OVERFLOW -2
 12 #define ERROR 0
 13 
 14 #define STACK_INIT_SIZE 100 //存储空间的初始分配量
 15 #define STACKINCREMENT 10   //存储空间的分配增量stackincrement
 16 
 17 typedef int SElemType;
 18 
 19 //栈的顺序存储表示
 20 typedef struct{
 21     SElemType *base;//在栈构造之前和销毁后值是NULL
 22     SElemType *top;
 23     int stacksize; //已分配的存储空间
 24 }SqStack;
 25 
 26 //栈的初始化操作
 27 
 28 int InitStack(SqStack &S){
 29     S.base = (int *)malloc(STACK_INIT_SIZE * sizeof(SqStack));
 30     if(!S.base){
 31         exit(OVERFLOW);//分配空间失败
 32     }
 33     S.top = S.base;
 34     S.stacksize = STACK_INIT_SIZE;
 35     return OK;
 36 }
 37 
 38 //进栈操作
 39 int Push(SqStack &S, int e){
 40     if(S.top - S.base >= S.stacksize){//栈空间已经满
 41         S.base = (int *)realloc(S.base,(S.stacksize + STACKINCREMENT) * sizeof(SqStack));
 42         if(!S.base){
 43             exit(OVERFLOW);//分配失败
 44         }
 45         S.top = S.base + S.stacksize;
 46         S.stacksize += STACKINCREMENT;
 47     }
 48     *S.top++ = e;
 49     return OK;
 50 }
 51 
 52 //出栈
 53 int Pop(SqStack &S,int &e){
 54     if(S.top != S.base){
 55         e = * --S.top;
 56         return OK;
 57     }else{
 58         exit(OVERFLOW);
 59     }
 60 }
 61 
 62 //得到顶部元素
 63 void GetElem(SqStack S, int &e){
 64     if(S.top != S.base){
 65         e = * (S.top - 1);
 66     }else{
 67         exit(OVERFLOW);
 68     }
 69 }
 70 
 71 //打印出栈各个元素
 72 void PrintfStack(SqStack S){
 73     while(*(S.top-1) && S.top != S.base){//证明不是空栈,且有值
 74         S.top = S.top - 1;
 75         printf("%d ",*S.top);
 76     }
 77     printf("\n");
 78 }
 79 
 80 int main(){
 81     int e,i;
 82     int TextData[6] = {9,2,8,1,7,6};
 83     SqStack Sa,Sb;
 84     InitStack(Sa);//初始化栈Sa;
 85     for(i = 0; i < 6; i++){
 86         Push(Sa,TextData[i]);
 87     }
 88     printf("**************栈基本操作*************\n");
 89     //初始化数据
 90     printf("初始化后的Sa:");
 91     PrintfStack(Sa);
 92     
 93     //得到栈顶元素
 94     GetElem(Sa,e);
 95     printf("Sa栈顶元素是:%d\n",e);
 96 
 97     //初始化数据
 98     printf("顶部出栈后Sa:");
 99     Pop(Sa,e);
100     PrintfStack(Sa);    
101 }

二:队列的学习:

队列和栈相反,是一种先进先出(FIFO)的线性表,只能在一端进行插入,一端进行删除

基础:在队列中,进行出入的一端称作队尾,允许删除的一端称作队首。和线性表差不多可以用顺序和链式表示。

双端队列:双端队列是限定插入和删除的操作在表的两端进行的线性表,用的不是很多。

循环队列:百度上解释:”将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量“,其实就是把队列首尾相连,但是要有一定的要求,不是想怎么连就怎么连。

下面给出链表的结构体:

 1 //单链队列
 2 typedef struct QNode{
 3     QElemType data;
 4     struct QNode *next;
 5 }QNode, *QueuePtr;
 6 
 7 typedef struct{
 8     QueuePtr front;
 9     QueuePtr rear;
10 }LinkQueue;
11 
12 //循环队列
13 typedef struct{
14     QElemType *base;
15     int front;
16     int rear;
17 }SqQueue;

  下面这段代码练习了队列的基本操作:队列结构体定义(比栈的稍微复杂一点)、在队尾插入新元素、删除队头元素、销毁队列、打印队列、循环队列的定义等等,这部分牵涉到好多的指针操作,如果有些困难可以在纸上划出队列的结构,列出指针的操作前后变化,就容易多了(个人感觉如果线性表学好了,这些操作根本不在话下)。需要注意循环队列操作中取余操作:(Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;

废话不多说,下面直接给出具体实现的代码:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 //头文件
  4 #define ERROR -1
  5 #define OK 2;
  6 #define TRUE 1;
  7 #define OVERFLOW -2;
  8 
  9 //最大队列长度
 10 #define MAXQSIZE 100
 11 
 12 typedef int Status;
 13 typedef int QElemType;
 14 
 15 //单链队列
 16 typedef struct QNode{
 17     QElemType data;
 18     struct QNode *next;
 19 }QNode, *QueuePtr;
 20 
 21 typedef struct{
 22     QueuePtr front;
 23     QueuePtr rear;
 24 }LinkQueue;
 25 
 26 //循环队列
 27 typedef struct{
 28     QElemType *base;
 29     int front;
 30     int rear;
 31 }SqQueue;
 32 
 33 //********************************队列的基本操作*****************************
 34 //初始化队列
 35 Status InitQueue(LinkQueue &Q){
 36     Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));//动态分配空间
 37     if(!Q.front){
 38         exit(ERROR);//分配空间失败
 39     }
 40     Q.front->next = NULL;
 41     return OK;
 42 }
 43 
 44 //在队尾插入新元素
 45 Status EnQueue(LinkQueue &Q, int e){
 46     QueuePtr p;
 47     p = (QueuePtr)malloc(sizeof(QNode));
 48     if(!p){
 49         exit(ERROR);//分配失败
 50     }
 51     p->data = e;
 52     p->next = NULL;
 53     Q.rear->next = p;
 54     Q.rear = p;
 55     return OK;
 56 }
 57 
 58 void DestroyQueue(LinkQueue &Q){
 59     if(Q.front != Q.rear){
 60         while(Q.front){
 61             Q.rear = Q.front->next;
 62             free(Q.front);
 63             Q.front = Q.rear;
 64         }
 65     }
 66 }
 67 
 68 //删除队头元素,并用e返回
 69 Status DeQueue(LinkQueue &Q, int &e){
 70     if(Q.front != Q.rear){//先判断队列是否为空
 71         QueuePtr p;
 72         e = Q.front->next->data;
 73         if(Q.front->next == Q.rear){//队列只有一个元素
 74             p = Q.rear;
 75             Q.rear = Q.front;
 76             Q.front->next = NULL;
 77         }else{
 78             p = Q.front->next;
 79             Q.front->next = p->next;
 80             p->next = NULL;
 81         }    
 82         free(p);
 83         return OK;
 84     }
 85 }
 86 
 87 //打印队列元素
 88 void PrintQueue(LinkQueue Q){
 89     if(Q.front != Q.rear){
 90         do{
 91             Q.front = Q.front->next;
 92             printf("%d ",Q.front->data);
 93         }while(Q.front->next);
 94     }
 95     printf("\n");
 96 }
 97 
 98 //********************************循环队列的基本操作*****************************
 99 //初始化队列
100 Status InitQueueXh(SqQueue &Q){
101     Q.base = (int *)malloc(MAXQSIZE * sizeof(int));//动态分配空间
102     if(!Q.base){
103         exit(ERROR);//分配空间失败
104     }
105     Q.front = Q.rear = 0;
106     return OK;
107 }
108 
109 //在队尾插入新元素
110 Status EnQueueXh(SqQueue &Q, int e){
111     if((Q.rear + 1) % MAXQSIZE == Q.front){
112         exit(ERROR);//队循环列已满
113     }
114     Q.base[Q.rear] = e;
115     Q.rear = (Q.rear + 1) % MAXQSIZE;
116     return OK;
117 }
118 
119 int DestroyQueueXh(SqQueue &Q){
120     return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
121 }
122 
123 //删除队头元素,并用e返回
124 Status DeQueueXh(SqQueue &Q, int &e){
125     if(Q.front == Q.rear){//先判断队列是否为空
126         return false;
127     }
128     e = Q.base[Q.front];
129     Q.front = (Q.front + 1) % MAXQSIZE;
130     return OK;
131 }
132 
133 //打印队列元素
134 void PrintQueueXh(SqQueue Q){
135     if(Q.front != Q.rear){
136         do{
137             printf("%d ",Q.base[Q.front]);
138             Q.front++;
139         }while(Q.front != Q.rear);
140     }
141     printf("\n");
142 }
143 
144 //主方法
145 int main(){
146     int e, i;
147     int Data[6] = {3,1,7,8,9,1};
148 
149     printf("****************队列的基本操作**************\n");
150     //初始化队列
151     LinkQueue Qa, Qb;
152     InitQueue(Qa);
153     //初始化Qa
154     for(i = 0; i < 6; i++){
155         EnQueue(Qa,Data[i]);
156     }    
157     //打印Qa
158     printf("Qa的各个元素:");
159     PrintQueue(Qa);
160 
161     //删除队首元素
162     DeQueue(Qa,e);
163     printf("删除Qa的队首元素:%d\n",e);
164     printf("删除首元素后的Qa: ");
165     PrintQueue(Qa);
166     printf("销毁后的Qa: ");
167     DestroyQueue(Qa);
168     PrintQueue(Qa);
169 
170     printf("**************循环队列的基本操作************\n");
171     //初始化队列
172     SqQueue QaXh, QbXh;
173     InitQueueXh(QaXh);
174     //初始化Qa
175     for(i = 0; i < 6; i++){
176         EnQueueXh(QaXh,Data[i]);
177     }    
178     //打印Qa
179     printf("QaXh的各个元素:");
180     PrintQueueXh(QaXh);
181 
182     //删除队首元素
183     DeQueueXh(QaXh,e);
184     printf("删除QaXh的队首元素:%d\n",e);
185     printf("删除首元素后的QaXh: ");
186     PrintQueueXh(QaXh);
187     printf("得到QaXh的元素个数:%d\n",DestroyQueueXh(QaXh));
188 }
posted @ 2015-06-20 14:37  赵亚飞  阅读(4202)  评论(2编辑  收藏  举报