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 }

浙公网安备 33010602011771号