数据结构之栈

栈模型

栈有时又叫做LIFO(先进后出)。

一般模型:存在某个元素位于栈顶,而该元素是唯一的可见元素。
栈可能是计算机科学中数组之后最基本的数据结构

栈的实现

栈的链表实现

1.#include <stdio.h>
2.#include <stdlib.h>
3.
4.struct Node;
5.typedef struct Node *PtrToNode;
6.typedef PtrToNode Stack;
7.
8.struct Node
9.{
10. int Element;
11. PtrToNode Next;
12.};
13.
14.int IsEmpty(Stack S)
15.{
16. return S->Next == NULL;
17.}
18.
19.//压入栈
20.void Push(int X, Stack S)
21.{
22. PtrToNode TmpCell;
23.
24. TmpCell = malloc(sizeof(struct Node));
25. if(TmpCell==NULL)
26. {
27. printf("空间不足");
28. }
29. else
30. {
31. TmpCell->Element = X;
32. TmpCell->Next = S->Next;
33. S->Next = TmpCell;
34. }
35.}
36.
37.//返回栈顶元素
38.int Top(Stack S)
39.{
40. if (!IsEmpty(S))
41. return S->Next->Element;
42. if ("栈空");
43. return 0;
44.}
45.//弹出
46.void Pop(Stack S)
47.{
48. PtrToNode Firstcell;
49. if (IsEmpty(S))
50. {
51. printf("栈空");
52. }
53. else
54. {
55. Firstcell = S->Next;
56. S->Next = S->Next->Next;
57. free(Firstcell);
58. }
59.}
60.
61.
62.void MakeEmpty(Stack S)
63.{
64. if(S==NULL)
65. {
66. printf("栈空");
67. }
68. else
69. {
70. while(!IsEmpty(S))
71. {
72. Pop(S);
73. }
74. }
75.}
76.//创建一个空栈
77.Stack CreateStack(void)
78.{
79. Stack S;
80.
81. S = malloc(sizeof(struct Node));
82. if (S == NULL)
83. printf("空间不足");
84. MakeEmpty(S);
85. return S;
86.}
优点:没有任何地方设计栈大小(空栈除外)
缺点:对malloc和free调用都是昂贵的。

栈的数组实现

每一个栈有一个TopOfStack,对于空栈它是-1。将X压入栈中,TopOfStack加1,置Stack[TopOfStack]=X,Stack代表具体的数组。

1.#include <stdio.h>
2.#include <stdlib.h>
3.
4.typedef struct StackRecord *Stack;
5.
6.#define EmptyTOS (-1)
7.#define MinStackSize (5)
8.
9.struct StackRecord
10.{
11. int CapaCity;
12. int TopOfStack;
13. int *Array;
14.};
15.
16.//创建一个空栈的例程
17.void MakeEmpty(Stack S)
18.{
19. S->TopOfStack = EmptyTOS;
20.}
21.
22.//栈的创建
23.Stack CreatStack(int MaxElements)
24.{
25. Stack S;
26. if(MaxElements<MinStackSize)
27. {
28. printf("Error");
29. }
30. //分配栈数组空间大小
31. S->Array = malloc(sizeof(int) * MaxElements);
32. if(S->Array==NULL)
33. {
34. printf("Error");
35. }
36. S->CapaCity = MaxElements;
37. MakeEmpty(S);
38. return S;
39.}
40.
41.
42.//释放栈的例程
43.void DisposeStack(Stack S)
44.{
45. if(S!=NULL)
46. {
47. free(S->Array);
48. free(S);
49. }
50.}
51.
52.//检测一个栈是否空栈
53.int IsEmpty(Stack S)
54.{
55. return S->TopOfStack == EmptyTOS;
56.}
57.
58.//进栈
59.void Push(int X,Stack S)
60.{
61. if( S==NULL)
62. {
63. printf("Error");
64. }
65. else
66. {
67. S->Array[++S->TopOfStack] = X;
68. }
69.
70.}
71.
72.//栈顶返回元素
73.int Top(Stack S)
74.{
75. if(!IsEmpty(S))
76. {
77. return S->Array[S->TopOfStack];
78. }
79. else
80. {
81. printf("Error");
82. }
83. return 0;
84.}
85.
86.//从栈顶弹出元素
87. void Pop(Stack S)
88.{
89. if(!IsEmpty(S))
90. {
91. printf("Error");
92. }
93. else
94. {
95. S->TopOfStack--;
96. }
97.}
98.
99. //返回并弹出元素
100.int TopAndPop(Stack S)
101.{
102. if(!IsEmpty(S))
103. {
104. return S->Array[S->TopOfStack--];
105. }
106. else
107. {
108. printf("Error");
109. }
110. return 0;
111.}

缺点:需要提前声明一个数组的大小

栈的应用

平衡符号

编译器检查对应的符号,比如([])。
做一个空栈,读入字符直到文件尾。如果字符式是一个开放符号,则将其推入栈中。如果字符是一个封闭符号,则当栈为空时报错。否则,将栈元素弹出。如果弹出符号不是对应的开放符号,则报错。在文件尾,如果栈非空则报错。

后缀表达式

又称逆波兰记法。
中缀到后缀的转换
a + b * c + ( d * e + f ) * g => a b c * + d e * f + g * +
1.char cArray[10];
2. char cRArray[10];
3. char a;
4. Stack S=CreatStack(10);//初始化栈
5. scanf_s("%c", &cArray[0]);
6. int i = 0, j = 0;
7. while(cArray[i]!='e')
8. {
9. i++;
10. scanf_s("%c", &cArray[i]);
11. }
12. i = 0;
13. for(int k=0;k<10;)
14. {
15. if(cArray[i]=='*'||cArray[i]=='+')//只做+和*的运算
16. {
17. if(cArray[i]=='+'&&GetStack(S)=='*')//当前元素+低于*优先级,将栈中元素都输出
18. {
19. for(;S->TopOfStack>-1;)
20. {
21. cRArray[k++] = GetStack(S);
22. BackStack(S);
23. }
24. }
25. else
26. {
27. InsertStack(S, cArray[i]);//插入栈
28. }
29. }
30. else
31. {
32. cRArray[k++] = cArray[i];//数字输出
33. }
34. i++;
35. }
36.
37. for(int l=0;l<10;l++)
38. {
39. printf("%c", cRArray[l]);
40. }
41. while(S->TopOfStack>=-1 )//输出栈尾剩余元素
42. {
43. printf("%c", GetStack(S));
44. BackStack(S);
45. }

函数调用

当系统调用函数的时候,需要存储重要信息,比如寄存器值,返回地址,他们都以抽象的方式置于一个堆顶部。然后控制转移到一个新函数,该函数自由的用它的一些值代替这些寄存器。这些工作可以一个栈完成。所存储的信息称为活动记录或栈帧。当前环境由栈顶描述。当存在太多同时运行着的函数时,用尽栈空间可能会发生。
尾递归
1.void PrintList(List L)
2.{
3. if(L!=NULL)
4. {
5. PrintElement(L->Element);
6. PrintList(L->Next);
7. }
8.}
在数据足够大的情况下,上面的函数就可能会用尽栈空间。
在不用存储每次递归调用值的情况下可以像下面这样避免。
1.void PrintList(List L)
2.{
3. top:
4. if(L!=NULL)
5. {
6. PrintElement(L->Element);
7. L=L->Next;
8. goto top;
9. }
10.}

 

 

posted on 2017-10-27 10:02  Mr.Tan&  阅读(477)  评论(0编辑  收藏  举报

导航