栈(链式栈)----C语言
链式栈:就是一种操作受限的单向链表,对单向链表还不了解的可先看一下之前的一篇关于单向链表的随笔,链表(单向链表的建立、删除、插入、打印),理解了单向链表后再来看链式栈就比较轻松了
链式栈的操作一般含有:出栈、入栈、栈的初始化、判断栈是否为空、清空栈,下面先上声明部分代码
1 #include <stdio.h>
2 #include <stdlib.h>
3 #define Empty 0 /* 栈空 */
4 #define Avail 1 /* 栈可用 */
5
6 typedef struct SNode
7 {
8 int data;
9 struct SNode *next;
10 }StackNode;
11 typedef struct LStack
12 {
13 StackNode *top; /* 栈顶指针 */
14 StackNode *bottom; /* 栈底指针 */
15 int height; /* 链式栈高度 */
16 }LinkStack;
17
18 LinkStack InitStack (LinkStack pStack); /* 栈顶指针、栈底指针、栈高度初始化*/
19 LinkStack Push (LinkStack pStack); /* 入栈 */
20 LinkStack Pop (LinkStack pStack); /* 出栈 */
21 int StackEmpty (LinkStack pStack); /* 判断栈是否为空 */
22 LinkStack DeletStack (LinkStack pStack);/* 清空栈 */
23 void DisplyStack (LinkStack pStack); /* 遍历栈----自顶至底*/
一、节点的声明
1 typedef struct SNode
2 {
3 int data;
4 struct SNode *next;
5 }StackNode;
链式栈节点的声明与单向链表的声明相同,都是由数据域和指针域组成,这里不再赘述
二、栈顶、栈底、栈高度的声明
1 typedef struct LStack
2 {
3 StackNode *top; /* 栈顶指针 */
4 StackNode *bottom; /* 栈底指针 */
5 int height; /* 链式栈高度 */
6 }LinkStack;
三、函数声明
1 LinkStack InitStack (LinkStack pStack); /* 栈顶指针、栈底指针、栈高度初始化*/
2 LinkStack Push (LinkStack pStack); /* 入栈 */
3 LinkStack Pop (LinkStack pStack); /* 出栈 */
4 int StackEmpty (LinkStack pStack); /* 判断栈是否为空 */
5 LinkStack DeletStack (LinkStack pStack);/* 清空栈 */
6 void DisplyStack (LinkStack pStack); /* 遍历栈----自顶至底*/
链式栈和单向链表的区别
上面已经提到的是链式栈是一种操作受限的单向链表(废话··),先来回顾一下单向链表的建立过程(不清楚单向链表的可以先之前的另一篇随笔链表(单向链表的建立、删除、插入、打印)),单向链表在添加新的节点的时候是将原链表最后一个节点的
指针域指向新建的节点,然后新建节点指针域置为NULL作为链表的最后一个节点,而链式栈在添加新的节点的时候操作就不太一样了,先来分析下栈的操作,栈只是栈顶来做插入和删除操作,那么栈顶放在链表的头部还是尾部呢?由于单向链表有头指针
而栈顶指针也是必须的,那么就把栈顶指针当作头指针来使用,比较好的办法是把栈顶放到单链表的头部。另外栈顶在头部了,那么单链表的头结点也就失去了意义,通常对于链式栈来说,是不需要头结点的,现在来说链式栈添加新节点的操作
链式栈:新一个节点->将新建节点的指针域指向原栈顶节点->将栈顶指针移动到新建节点
单向链表:新建一个节点->将原链表最后的一个节点的指针域指向新建节点->新建节点的指针域置为NULL作为新链表的最后一个节点
为了方便读者更加直观了解这个过程下面上图:
链式栈操作部分
一、入栈
1 /* Function: 入栈 */
2 LinkStack Push (LinkStack pStack)
3 {
4 int data;
5 StackNode *temp;
6
7 if ((temp = (StackNode *)malloc(sizeof(StackNode))) == NULL)
8 {
9 printf("内存空间不足\n");
10 return pStack;
11 }
12 if (StackEmpty(pStack) == Empty) /* 如果栈为空 */
13 {
14 pStack.top = pStack.bottom = temp; /* 栈顶、栈底指针都指向新建节点 */
15 temp->next = NULL; /* 节点指针域为空 */
16 printf("Please input data");
17 scanf("%d", &data);
18 pStack.top->data = data;
19 pStack.height++;
20
21 return pStack;
22 }
23 else /* 栈不为空 */
24 {
25 temp->next = pStack.top;/* 新建节点指向原来的栈顶 */
26 pStack.top = temp; /* 栈顶指针指向新建节点 */
27 printf("Please input data");
28 scanf("%d", &data);
29 pStack.top->data = data;
30 pStack.height++;
31
32 return pStack;
33 }
34 }
二、出栈
1 /* Function: 出栈 */
2 LinkStack Pop (LinkStack pStack)
3 {
4 StackNode *Second;
5
6
7 if (StackEmpty(pStack) == Empty) /* 判断栈是否为空 */
8 {
9 printf("栈为空,无法出栈\n");
10 return pStack;
11 }
12 if (pStack.top == pStack.bottom) /* 如果出栈的元素为最后一个元素 */
13 {
14 printf("出栈元素为%d\n", pStack.top->data);
15 free(pStack.top);
16 pStack.top = pStack.bottom = NULL; /* 栈顶、栈底都指针都置为空 */
17 pStack.height--;
18
19 return pStack;
20 }
21 printf("出栈元素为%d\n", pStack.top->data);
22 Second = pStack.top->next; /* 指向栈顶的前一个元素*/
23
24 free(pStack.top); /* 释放栈顶节点 */
25 pStack.top = Second;/* 将头指针移动到新的栈顶节点 */
26 pStack.height--;
27
28 return pStack;
29 }
出栈时需要判断三种情况,第一种情况:栈为空、第二种情况:栈中只有一个元素、第三种情况:栈中元素大于等于两个
三、判断栈是否为空
1 /* Function: 判断栈是否为空 */
2 int StackEmpty (LinkStack pStack)
3 {
4 if (pStack.top == NULL && pStack.bottom == NULL)
5 {
6 return Empty;
7 }
8 else
9 {
10 return Avail;
11 }
12 }
四、遍历栈
1 /* Function: 遍历栈 自顶到底*/
2 void DisplyStack (LinkStack pStack)
3 {
4 if (StackEmpty(pStack) == Empty)
5 {
6 printf("栈为空,无法遍历\n");
7 return ;
8 }
9 printf("栈中元素[");
10 while (pStack.top != NULL)
11 {
12 printf("%d->", pStack.top->data);
13 pStack.top = pStack.top->next;
14 }
15 printf("]\n");
16 }
五、清空栈
1 /* Function: 清空栈 */
2 LinkStack DeletStack (LinkStack pStack)
3 {
4 StackNode *del;
5
6 while (pStack.top != NULL)
7 {
8 del = pStack.top->next; /* 栈顶节点的前一个节点 */
9 free(pStack.top); /* 释放节点 */
10 pStack.top = del; /* 栈顶指针移动到新栈顶 */
11 }
12
13 return pStack;
14 }
六、初始化栈顶、栈底指针和栈高度
1 /* Function: 初始化栈顶、栈底、栈高度*/
2 LinkStack InitStack (LinkStack pStack)
3 {
4 pStack.top = pStack.bottom = NULL;
5 pStack.height = 0;
6
7 return pStack;
8 }
链式栈实现完整代码
1 #include <stdio.h>
2 #include <stdlib.h>
3 #define Empty 0 /* 栈空 */
4 #define Avail 1 /* 栈可用 */
5
6 typedef struct SNode
7 {
8 int data;
9 struct SNode *next;
10 }StackNode;
11 typedef struct LStack
12 {
13 StackNode *top; /* 栈顶指针 */
14 StackNode *bottom; /* 栈底指针 */
15 int height; /* 链式栈高度 */
16 }LinkStack;
17
18 LinkStack InitStack (LinkStack pStack); /* 栈顶指针、栈底指针、栈高度初始化*/
19 LinkStack Push (LinkStack pStack); /* 入栈 */
20 LinkStack Pop (LinkStack pStack); /* 出栈 */
21 int StackEmpty (LinkStack pStack); /* 判断栈是否为空 */
22 LinkStack DeletStack (LinkStack pStack);/* 清空栈 */
23 void DisplyStack (LinkStack pStack); /* 遍历栈----自顶至底*/
24
25 int main()
26 {
27 LinkStack p;
28 char ch;
29
30 p.height = 0; /* 栈高度初始化为零 */
31 p = InitStack (p); /* 栈初始化 */
32 printf("Do you want to push stack(Y/N)?");
33 scanf(" %c", &ch);
34 while (ch == 'Y' || ch == 'y')
35 {
36 p = Push(p); /* 入栈 */
37 DisplyStack(p); /* 遍历栈 */
38 printf("Do you want to push stack(Y/N)?");
39 scanf(" %c", &ch);
40 }
41 printf("Do you want to pop stack(Y/N)?");
42 scanf(" %c", &ch);
43 while (ch == 'Y' || ch == 'y')
44 {
45 p = Pop(p); /* 出栈 */
46 DisplyStack(p); /* 遍历栈 */
47 printf("Do you want to pop stack(Y/N)?");
48 scanf(" %c", &ch);
49 }
50
51 return 0;
52 }
53 /* Function: 初始化栈顶、栈底、栈高度*/
54 LinkStack InitStack (LinkStack pStack)
55 {
56 pStack.top = pStack.bottom = NULL;
57 pStack.height = 0;
58
59 return pStack;
60 }
61
62 /* Function: 判断栈是否为空 */
63 int StackEmpty (LinkStack pStack)
64 {
65 if (pStack.top == NULL && pStack.bottom == NULL)
66 {
67 return Empty;
68 }
69 else
70 {
71 return Avail;
72 }
73 }
74
75 /* Function: 入栈 */
76 LinkStack Push (LinkStack pStack)
77 {
78 int data;
79 StackNode *temp;
80
81 if ((temp = (StackNode *)malloc(sizeof(StackNode))) == NULL)
82 {
83 printf("内存空间不足\n");
84 return pStack;
85 }
86 if (StackEmpty(pStack) == Empty) /* 如果栈为空 */
87 {
88 pStack.top = pStack.bottom = temp; /* 栈顶、栈底指针都指向新建节点 */
89 temp->next = NULL; /* 节点指针域为空 */
90 printf("Please input data");
91 scanf("%d", &data);
92 pStack.top->data = data;
93 pStack.height++;
94
95 return pStack;
96 }
97 else /* 栈不为空 */
98 {
99 temp->next = pStack.top;/* 新建节点指向原来的栈顶 */
100 pStack.top = temp; /* 栈顶指针指向新建节点 */
101 printf("Please input data");
102 scanf("%d", &data);
103 pStack.top->data = data;
104 pStack.height++;
105
106 return pStack;
107 }
108 }
109
110 /* Function: 出栈 */
111 LinkStack Pop (LinkStack pStack)
112 {
113 StackNode *Second;
114
115
116 if (StackEmpty(pStack) == Empty) /* 判断栈是否为空 */
117 {
118 printf("栈为空,无法出栈\n");
119 return pStack;
120 }
121 if (pStack.top == pStack.bottom) /* 如果出栈的元素为最后一个元素 */
122 {
123 printf("出栈元素为%d\n", pStack.top->data);
124 free(pStack.top);
125 pStack.top = pStack.bottom = NULL; /* 栈顶、栈底都指针都置为空 */
126 pStack.height--;
127
128 return pStack;
129 }
130 printf("出栈元素为%d\n", pStack.top->data);
131 Second = pStack.top->next; /* 指向栈顶的前一个元素*/
132
133 free(pStack.top); /* 释放栈顶节点 */
134 pStack.top = Second;/* 将头指针移动到新的栈顶节点 */
135 pStack.height--;
136
137 return pStack;
138 }
139
140 /* Function: 遍历栈 自顶到底*/
141 void DisplyStack (LinkStack pStack)
142 {
143 if (StackEmpty(pStack) == Empty)
144 {
145 printf("栈为空,无法遍历\n");
146 return ;
147 }
148 printf("栈中元素[");
149 while (pStack.top != NULL)
150 {
151 printf("%d->", pStack.top->data);
152 pStack.top = pStack.top->next;
153 }
154 printf("]\n");
155 }
156
157 /* Function: 清空栈 */
158 LinkStack DeletStack (LinkStack pStack)
159 {
160 StackNode *del;
161
162 while (pStack.top != NULL)
163 {
164 del = pStack.top->next; /* 栈顶节点的前一个节点 */
165 free(pStack.top); /* 释放节点 */
166 pStack.top = del; /* 栈顶指针移动到新栈顶 */
167 }
168
169 return pStack;
170 }