数据结构_之顺序栈_链栈的原理和实现及栈的广泛应用
1.Stack基本概念
概念:
首先它是一个线性表,也就是说,栈元素具有线性关系,即前驱后继关系。只不过它是一种特殊的线性表而已。定义中说是在线性表的表尾进行插入和删除操作,这里表尾是指栈顶,而不是栈底。
注意:
栈是一种 特殊的线性表
栈仅能在线性表的一端进行操作
栈顶(Top):允许操作的一端
栈底(Bottom):不允许操作的一端
特性
它的特殊之处在于限制了这个线性表的插入和删除的位置,它始终只在栈顶进行。这也就使得:栈底是固定的,最先进栈的只能在栈底。
l操作
栈的插入操作,叫做进栈,也成压栈。类似子弹入弹夹(如下图所示)
栈的删除操作,叫做出栈,也有的叫做弾栈,退栈。如同弹夹中的子弹出夹(如下图所示)
2.栈的常用操作
l 创建栈
l 销毁栈
l 清空栈
l 进栈
l 出栈
l 获取栈顶元素
l 获取栈的大小
ADT 栈(stack) Data 通线性表。元素具有相同的类型,相邻的元素具有前驱和后继关系。 Operation // 初始化,建立一个空栈S InitStack(*S); // 若栈存在,则销毁它 DestroyStack(*S); // 将栈清空 ClearStack(*S); // 若栈为空则返回true,否则返回false StackEmpty(S); // 若栈存在且非空,用e返回S的栈顶元素 GetTop(S,*e); // 若栈S存在,插入新元素e到栈S中并成为其栈顶元素 Push(*S,e); // 删除栈S中的栈顶元素,并用e返回其值 Pop(*S, *e); // 返回栈S的元素个数 StackLength(S); endADT
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #ifndef _MY_STACK_H_ 2 #define _MY_STACK_H_ 3 4 typedef void Stack; 5 6 Stack* Stack_Create(); 7 8 void Stack_Destroy(Stack* stack); 9 10 void Stack_Clear(Stack* stack); 11 12 int Stack_Push(Stack* stack, void* item); 13 14 void* Stack_Pop(Stack* stack); 15 16 void* Stack_Top(Stack* stack); 17 18 int Stack_Size(Stack* stack); 19 20 #endif //_MY_STACK_H_
3.栈模型和链表模型关系分析
4.栈的顺序存储设计与实现
l 基本概念
栈的顺序存储结构简称顺序栈,它是运算受限制的顺序表。顺序栈的存储结构是:利用一组地址连续的的存储单元依次存放自栈底到栈顶的数据元素,同时附设指针top只是栈顶元素在顺序表中的位置。
l 设计与实现
(1)因为栈是一种特殊的线性表,所以栈的顺序存储可以通过顺序线性表来实现。
头文件:
#ifndef __MY_SEQLIST_H__ #define __MY_SEQLIST_H__ typedef void SeqList; typedef void SeqListNode; SeqList* SeqStack_Create(int capacity); void SeqStack _Destroy(SeqStack * list); void SeqStack _Clear(SeqStack * list); int SeqStack _Length(SeqStack * list); int SeqStack _Capacity(SeqStack * list); int SeqStack _Insert(SeqStack * list, SeqListNode* node, int pos); SeqListNode* SeqList_Get(SeqList* list, int pos); SeqListNode* SeqList_Delete(SeqList* list, int pos); #endif //__MY_SEQLIST_H__
案例详细代码:
seqlist.h
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #ifndef __MY_SEQLIST_H__ 2 #define __MY_SEQLIST_H__ 3 4 // #define ERR_BASE 0 5 // #define ERR_PARAM ERR_BASE -1; 6 7 typedef void SeqList; 8 typedef void SeqListNode; 9 10 SeqList* SeqList_Create(int capacity); 11 12 void SeqList_Destroy(SeqList* list); 13 14 void SeqList_Clear(SeqList* list); 15 16 int SeqList_Length(SeqList* list); 17 18 int SeqList_Capacity(SeqList* list); 19 20 int SeqList_Insert(SeqList* list, SeqListNode* node, int pos); 21 22 SeqListNode* SeqList_Get(SeqList* list, int pos); 23 24 SeqListNode* SeqList_Delete(SeqList* list, int pos); 25 26 27 #endif //__MY_SEQLIST_H__
seqstack.h
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 // seqstack.h 2 3 #ifndef _MY_SEQSTACK_H_ 4 #define _MY_SEQSTACK_H_ 5 6 typedef void SeqStack; 7 8 SeqStack* SeqStack_Create(int capacity); 9 10 void SeqStack_Destroy(SeqStack* stack); 11 12 void SeqStack_Clear(SeqStack* stack); 13 14 int SeqStack_Push(SeqStack* stack, void* item); 15 16 void* SeqStack_Pop(SeqStack* stack); 17 18 void* SeqStack_Top(SeqStack* stack); 19 20 int SeqStack_Size(SeqStack* stack); 21 22 int SeqStack_Capacity(SeqStack* stack); 23 24 #endif //_MY_SEQSTACK_H_
seqlist.c
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include "stdlib.h" 2 #include "stdio.h" 3 #include "string.h" 4 #include "seqlist.h" 5 6 typedef struct _tag_SeqList 7 { 8 int capacity; 9 int length; 10 unsigned int *node ; // unsigned int nodeAarry[100] 11 //void *node ; 12 }TSeqList; 13 14 //typdef的意思 把void 重新命名成SeqList 15 16 /* 17 void * SeqList_Create2(int capacity) 18 { 19 TSeqList *ret = NULL; 20 ret = (TSeqList *)malloc(sizeof(TSeqList)); 21 if (ret == NULL) 22 { 23 return NULL; 24 } 25 ret->capacity = capacity; 26 ret->node = (unsigned int *)malloc(sizeof(unsigned int ) * capacity); 27 if (ret->node == NULL) 28 { 29 return NULL; 30 } 31 ret->length = 0; 32 return ret; 33 } 34 */ 35 36 void * SeqList_Create(int capacity) 37 { 38 TSeqList *ret = NULL; 39 40 if (capacity <= 0) 41 { 42 return NULL; 43 } 44 ret = (TSeqList *)malloc(sizeof(TSeqList) + sizeof(unsigned int ) * capacity ); 45 if (ret == NULL) 46 { 47 return NULL; 48 } 49 ret->capacity = capacity; 50 ret->node = (unsigned int *)(ret + 1); 51 52 ret->length = 0; 53 return ret; 54 } 55 56 void SeqList_Destroy(SeqList* list) 57 { 58 if (list == NULL) 59 { 60 return ; 61 } 62 free(list); 63 return ; 64 } 65 66 void SeqList_Clear(SeqList* list) 67 { 68 TSeqList *tlist = NULL; 69 if (list == NULL) 70 { 71 return ; 72 } 73 tlist = (TSeqList *)list; 74 75 tlist->length = 0; 76 return ; 77 } 78 79 int SeqList_Length(SeqList* list) 80 { 81 TSeqList *tlist = list; 82 if (list == NULL) 83 { 84 return -1; 85 } 86 return tlist->length; 87 } 88 89 int SeqList_Capacity(SeqList* list) 90 { 91 TSeqList *tlist = list; 92 if (list == NULL) 93 { 94 return -1; 95 } 96 return tlist->capacity; 97 } 98 99 int SeqList_Insert(SeqList* list, SeqListNode* node, int pos) 100 { 101 int i = 0; 102 TSeqList *tlist = list; 103 104 if (list == NULL || node== NULL ) 105 { 106 return -1; 107 } 108 109 if (pos<0 || pos>=tlist->capacity ) 110 { 111 return -2; 112 } 113 114 //判断是否已经man 115 if (tlist->length >= tlist->capacity) 116 { 117 return -3; 118 } 119 120 //容错 121 if (pos > tlist->length) 122 { 123 pos = tlist->length; 124 } 125 126 //插入算法 有两步 127 //从插入的位置 后移元素 128 //注意length能表示出现在数组的最后元素位置 129 //最后元素的下标为 tlist->node[length-1]; 130 for (i=tlist->length; i>pos; i--) 131 { 132 tlist->node[i] = tlist->node[i-1]; 133 } 134 //在pos位置插入元素 135 tlist->node[pos] = (unsigned int)node; //20140514这个地方不能加 (unsigned int *) 136 //如果你加*,说明你对 unsigned int *node ; // unsigned int nodeAarry[100]还没有理解 137 tlist->length ++; 138 139 return 0; 140 } 141 142 SeqListNode* SeqList_Get(SeqList* list, int pos) 143 { 144 int i = 0; 145 TSeqList *tlist = list; 146 //if (list== NULL || pos<0 || pos>=tlist->length) 147 if (list== NULL || pos<0 || pos>tlist->length) 148 { 149 return NULL; 150 } 151 return (SeqListNode*)tlist->node[pos]; 152 } 153 154 SeqListNode* SeqList_Delete(SeqList* list, int pos) 155 { 156 int i = 0; 157 TSeqList *tlist = list; 158 SeqListNode* ret = NULL; 159 if (list == NULL || pos<0 || pos>tlist->length) 160 { 161 return NULL; 162 } 163 //缓存要删除的结点 164 ret = (SeqListNode*)tlist->node[pos]; 165 //对链表进行移动 166 for (i=pos+1; i<tlist->length; i++) 167 { 168 tlist->node[i-1] = tlist->node[i]; 169 } 170 tlist->length --; 171 return ret; 172 }
seqstack.c
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include "stdio.h" 2 #include "stdlib.h" 3 #include "string.h" 4 5 #include "seqstack.h" 6 #include "seqlist.h" //线性表的顺序存储头文件 7 8 9 SeqStack* SeqStack_Create(int capacity) 10 { 11 return SeqList_Create(capacity); 12 } 13 14 void SeqStack_Destroy(SeqStack* stack) 15 { 16 SeqList_Destroy(stack); 17 } 18 19 void SeqStack_Clear(SeqStack* stack) 20 { 21 SeqList_Clear(stack); 22 } 23 24 //往栈中放元素,相当于向线性表中放元素 25 int SeqStack_Push(SeqStack* stack, void* item) 26 { 27 return SeqList_Insert(stack, item, SeqList_Length(stack)); 28 } 29 30 //从栈中弹出元素,相当于从线性表中删除元素 31 void* SeqStack_Pop(SeqStack* stack) 32 { 33 return SeqList_Delete(stack, SeqList_Length(stack) -1); 34 } 35 36 void* SeqStack_Top(SeqStack* stack) 37 { 38 return SeqList_Get(stack, SeqList_Length(stack)-1);; 39 } 40 41 int SeqStack_Size(SeqStack* stack) 42 { 43 return SeqList_Length(stack); 44 } 45 46 int SeqStack_Capacity(SeqStack* stack) 47 { 48 return SeqList_Capacity(stack); 49 }
seqstack动态库集成测试.c
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include "stdio.h" 2 #include "stdlib.h" 3 #include "string.h" 4 #include "seqstack.h" 5 6 void main() 7 { 8 9 int a[20], i = 0; 10 int *pTmp = NULL; 11 SeqStack* stack = NULL; 12 13 stack = SeqStack_Create(20); 14 15 for (i=0; i<10; i++) 16 { 17 a[i] = i+1; 18 //SeqStack_Push(stack, &a[i]); 19 SeqStack_Push(stack, a+i); 20 } 21 22 pTmp = (int *)SeqStack_Top(stack); 23 printf("top:%d \n", *pTmp); 24 25 printf("capacity:%d \n", SeqStack_Capacity(stack)); 26 27 printf("size:%d \n", SeqStack_Size(stack)); 28 29 //元素出栈 30 while (SeqStack_Size(stack) > 0) 31 { 32 printf("pop:%d \n", *((int *)SeqStack_Pop(stack)) ); 33 } 34 35 SeqStack_Destroy(stack); 36 37 system("pause"); 38 }
(2)不通过线性表实现(版本1)
SqStack.h
#ifndef _SQSTACK_H #define _SQSTACK_H #define MAXSIZE 50 typedef struct _SQSTACK { int top; // 栈顶指针 unsigned int data[MAXSIZE]; }SqStack; // 初始化,建立一个空栈S void InitStack(SqStack *S); // 将栈清空 void ClearStack(SqStack *S); // 若栈为空则返回true,否则返回false int StackEmpty(SqStack S); // 若栈存在且非空,用e返回S的栈顶元素 void GetTop(SqStack S, void **e); // 若栈S存在,插入新元素e到栈S中并成为其栈顶元素 void Push(SqStack *S, void *e); // 删除栈S中的栈顶元素,并用e返回其值 void Pop(SqStack *S, void **e); // 返回栈S的元素个数 int StackLength(SqStack S); #endif // _SQSTACK_H
SqStack.c
#include "SqStack.h" #include <string.h> void InitStack(SqStack *S) { // 空栈 S->top = -1; memset(S->data, 0, sizeof(S->data)); } void ClearStack(SqStack *S) { S->top = -1; } int StackEmpty(SqStack S) { if (S.top == -1) { return 1; } return 0; } void GetTop(SqStack S, void **e) { // 栈为空 if (S.top == -1) { return; } *e = (void*)S.data[S.top]; } void Push(SqStack *S, void *e) { // 栈已经满了 if (S->top == MAXSIZE - 1) { return; } // 栈顶上移 S->top++; // 赋值 S->data[S->top] = (unsigned int)e; } void Pop(SqStack *S, void **e) { // 栈为空 if (S->top == -1) { return; } // 赋值 *e = S->data[S->top]; // 栈顶指针下移 S->top--; } int StackLength(SqStack S) { return S.top + 1; }
main.c
#include <stdio.h> #include <stdlib.h> #include "SqStack.h" typedef struct stu { int id; int age; }Student; void main() { Student stu[10]; // 定义栈变量 SqStack st; // 初始化栈 InitStack(&st); // 压栈 for (int i = 0; i < 10; ++i) { stu[i].id = i; stu[i].age = i + 20; // 压栈 Push(&st, (void*)&stu[i]); } printf("stack size = %d\n", StackLength(st)); // 出栈 while (StackEmpty(st) != 1) { Student* p; // 取栈顶元素 GetTop(st, (void**)&p); printf("stack top elem id = %d, age=%d\n", p->id, p->age); // 删除栈顶元素 Pop(&st, (void*)&p); printf("Delete stack elem id = %d, age=%d\n", p->id, p->age); } system("pause"); }
(3)不通过线性表实现(版本2)
SeqStack.h
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #ifndef SEQSTACK_H 2 #define SEQSTACK_H 3 4 #include<stdlib.h> 5 #include<stdio.h> 6 7 //数组去模拟栈的顺序存储 8 #define MAX_SIZE 1024 9 #define SEQSTACK_TRUE 1 10 #define SEQSTACK_FALSE 0 11 12 typedef struct SEQSTACK{ 13 void* data[MAX_SIZE]; 14 int size; 15 }SeqStack; 16 17 //初始化栈 18 SeqStack* Init_SeqStack(); 19 //入栈 20 void Push_SeqStack(SeqStack* stack,void* data); 21 //返回栈顶元素 22 void* Top_SeqStack(SeqStack* stack); 23 //出栈 24 void Pop_SeqStack(SeqStack* stack); 25 //判断是否为空 26 int IsEmpty(SeqStack* stack); 27 //返回栈中元素的个数 28 int Size_SeqStack(SeqStack* stack); 29 //清空栈 30 void Clear_SeqStack(SeqStack* stack); 31 //销毁 32 void FreeSpace_SeqStack(SeqStack* stack); 33 34 35 #endif
SeqStack.c
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include"SeqStack.h" 2 3 //初始化栈 4 SeqStack* Init_SeqStack(){ 5 6 SeqStack* stack = (SeqStack*)malloc(sizeof(SeqStack)); 7 for (int i = 0; i < MAX_SIZE;i++){ 8 stack->data[i] = NULL; 9 } 10 stack->size = 0; 11 12 return stack; 13 } 14 //入栈 15 void Push_SeqStack(SeqStack* stack, void* data){ 16 17 if (stack == NULL){ 18 return; 19 } 20 if (stack->size == MAX_SIZE){ 21 return; 22 } 23 if (data == NULL){ 24 return; 25 } 26 27 stack->data[stack->size] = data; 28 stack->size++; 29 } 30 //返回栈顶元素 31 void* Top_SeqStack(SeqStack* stack){ 32 if (stack == NULL){ 33 return NULL; 34 } 35 36 if (stack->size == 0){ 37 return NULL; 38 } 39 40 return stack->data[stack->size-1]; 41 } 42 //出栈 43 void Pop_SeqStack(SeqStack* stack){ 44 if (stack == NULL){ 45 return; 46 } 47 if (stack->size == 0){ 48 return; 49 } 50 stack->data[stack->size - 1] = NULL; 51 stack->size--; 52 } 53 //判断是否为空 54 int IsEmpty(SeqStack* stack){ 55 if (stack == NULL){ 56 return -1; 57 } 58 59 if (stack->size == 0){ 60 return SEQSTACK_TRUE; 61 } 62 63 return SEQSTACK_FALSE; 64 } 65 //返回栈中元素的个数 66 int Size_SeqStack(SeqStack* stack){ 67 return stack->size; 68 } 69 //清空栈 70 void Clear_SeqStack(SeqStack* stack){ 71 if (stack == NULL){ 72 return; 73 } 74 for (int i = 0; i < stack->size;i++){ 75 stack->data[i] = NULL; 76 } 77 stack->size = 0; 78 } 79 //销毁 80 void FreeSpace_SeqStack(SeqStack* stack){ 81 82 if (stack == NULL){ 83 return; 84 } 85 86 free(stack); 87 }
栈的顺序存储.c
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #define _CRT_SECURE_NO_WARNINGS 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5 #include "SeqStack.h" 6 7 typedef struct PERSON{ 8 char name[64]; 9 int age; 10 }Person; 11 12 int main(void){ 13 14 //创建栈 15 SeqStack* stack = Init_SeqStack(); 16 17 //创建数据 18 Person p1 = { "aaa", 10 }; 19 Person p2 = { "bbb", 20 }; 20 Person p3 = { "ccc", 30 }; 21 Person p4 = { "ddd", 40 }; 22 Person p5 = { "eee", 50 }; 23 24 //入栈 25 Push_SeqStack(stack, &p1); 26 Push_SeqStack(stack, &p2); 27 Push_SeqStack(stack, &p3); 28 Push_SeqStack(stack, &p4); 29 Push_SeqStack(stack, &p5); 30 31 //输出 32 while (Size_SeqStack(stack) > 0){ 33 //访问栈顶元素 34 Person* person = (Person*)Top_SeqStack(stack); 35 printf("Name:%s Age:%d\n",person->name,person->age); 36 //弹出栈顶元素 37 Pop_SeqStack(stack); 38 } 39 40 //释放内存 41 FreeSpace_SeqStack(stack); 42 43 system("pause"); 44 return 0; 45 }
5.栈的链式存储设计与实现
l 基本概念
栈的链式存储结构简称链栈。
思考如下问题:
栈只是栈顶来做插入和删除操作,栈顶放在链表的头部还是尾部呢?
由于单链表有头指针,而栈顶指针也是必须的,那干嘛不让他俩合二为一呢,所以比较好的办法就是把栈顶放在单链表的头部。另外都已经有了栈顶在头部了,单链表中比较常用的头结点也就失去了意义,通常对于链栈来说,是不需要头结点的。
l 设计与实现
链栈是一种特殊的线性表,链栈可以通过链式线性表来实现。
(1)链栈可以通过链式线性表来实现:
linklist.h
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #ifndef _MYLINKLIST_H_ 2 #define _MYLINKLIST_H_ 3 4 typedef void LinkList; 5 /* 6 typedef struct _tag_LinkListNode LinkListNode; 7 struct _tag_LinkListNode 8 { 9 LinkListNode* next; 10 }; 11 */ 12 typedef struct _tag_LinkListNode 13 { 14 struct _tag_LinkListNode* next; 15 }LinkListNode; 16 17 LinkList* LinkList_Create(); 18 19 void LinkList_Destroy(LinkList* list); 20 21 void LinkList_Clear(LinkList* list); 22 23 int LinkList_Length(LinkList* list); 24 25 int LinkList_Insert(LinkList* list, LinkListNode* node, int pos); 26 27 LinkListNode* LinkList_Get(LinkList* list, int pos); 28 29 LinkListNode* LinkList_Delete(LinkList* list, int pos); 30 31 #endif
linkstack.h
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #ifndef _MY_LINKSTACK_H_ 2 #define _MY_LINKSTACK_H_ 3 4 typedef void LinkStack; 5 6 LinkStack* LinkStack_Create(); 7 8 void LinkStack_Destroy(LinkStack* stack); 9 10 void LinkStack_Clear(LinkStack* stack); 11 12 int LinkStack_Push(LinkStack* stack, void* item); 13 14 void* LinkStack_Pop(LinkStack* stack); 15 16 void* LinkStack_Top(LinkStack* stack); 17 18 int LinkStack_Size(LinkStack* stack); 19 20 #endif //_MY_LINKSTACK_H_
linklist.c
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<stdio.h> 2 #include "stdlib.h" 3 #include "string.h" 4 5 #include "linklist.h" 6 7 typedef struct _tag_LinkList 8 { 9 //这个句柄里面,需要保存所有节点信息。需要有一个起始点 10 //就是带头节点的链表。。。 11 LinkListNode header; 12 int length; 13 }TLinkList; 14 15 LinkList* LinkList_Create() 16 { 17 TLinkList *ret = (TLinkList *)malloc(sizeof(TLinkList)); 18 if (ret == NULL) 19 { 20 return NULL; 21 } 22 //memset(ret, 0, sizeof(TLinkList)); 23 ret->header.next = NULL; 24 ret->length = 0; 25 return ret; 26 } 27 28 void LinkList_Destroy(LinkList* list) 29 { 30 if (list == NULL) 31 { 32 return ; 33 } 34 free(list); 35 return ; 36 } 37 38 void LinkList_Clear(LinkList* list) 39 { 40 41 TLinkList *tList =NULL; 42 43 if (list == NULL) 44 { 45 return ; 46 } 47 tList = (TLinkList *)list; 48 tList->length = 0; 49 tList->header.next = NULL; 50 return ; 51 } 52 53 int LinkList_Length(LinkList* list) 54 { 55 56 TLinkList *tList = (TLinkList *)list; 57 if (tList == NULL) 58 { 59 return -1; 60 } 61 62 return tList->length; 63 } 64 65 int LinkList_Insert(LinkList* list, LinkListNode* node, int pos) 66 { 67 int i = 0; 68 69 TLinkList *tList = NULL; 70 LinkListNode *current = NULL; 71 72 tList = (TLinkList *)list; 73 74 if (list==NULL || node==NULL) //modify by bombing 2014.06.26 75 { 76 return -1; 77 } 78 79 //准备环境让辅助指针变量 指向链表头节点 80 current = &tList->header; 81 for (i=0; i<pos &&(current->next!=NULL); i++) 82 { 83 current = current->next; 84 } 85 86 //让node节点链接后续链表 87 node->next = current->next ; 88 //让前边的链表。链接node 89 current->next = node; 90 tList->length ++; 91 return 0; 92 } 93 94 LinkListNode* LinkList_Get(LinkList* list, int pos) 95 { 96 97 int i = 0; 98 99 TLinkList *tList = NULL; 100 LinkListNode *current = NULL; 101 LinkListNode *ret = NULL; 102 tList = (TLinkList *)list; 103 104 if (list == NULL || pos <0 ||pos>=tList->length) 105 { 106 return NULL; 107 } 108 //准备环境让辅助指针变量 指向链表头节点 109 current = &tList->header; 110 for (i=0; i<pos &&(current->next!=NULL); i++) 111 { 112 current = current->next; 113 } 114 ret = current->next; 115 116 return ret; 117 } 118 119 LinkListNode* LinkList_Delete(LinkList* list, int pos) 120 { 121 int i = 0; 122 123 TLinkList *tList = NULL; 124 LinkListNode *current = NULL; 125 LinkListNode *ret = NULL; 126 tList = (TLinkList *)list; 127 128 if (list == NULL || pos <0 ||pos>=tList->length) 129 { 130 return NULL; 131 } 132 //准备环境让辅助指针变量 指向链表头节点 133 current = &tList->header; 134 for (i=0; i<pos &&(current->next!=NULL); i++) 135 { 136 current = current->next; 137 } 138 ret = current->next; 139 140 //删除算法 141 current->next =ret->next; 142 tList->length--; 143 144 return ret; 145 }
linkstack.c
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include "stdlib.h" 2 #include "stdio.h" 3 #include "string.h" 4 #include "linkstack.h" 5 #include "linklist.h" 6 7 typedef struct _tag_LinkStackNode 8 { 9 LinkListNode node; //占位结构。。。只要定义一个和node节大小一样的数据即可 10 void *item; 11 }TLinkStackNode; 12 13 //我要创建一个linkstack,准备用linklist去模拟实现 14 //相当于在 linkstack.c中写 linklist库的测试程序。。。。。。 15 LinkStack* LinkStack_Create() 16 { 17 //创建一个栈,通过线性表去模拟。。。(创建一个栈,相当于创建一个线性表) 18 return LinkList_Create(); 19 } 20 21 void LinkStack_Destroy(LinkStack* stack) 22 { 23 LinkStack_Clear(stack); //注意 destory的时候,需要把栈中的所有元素都清空 24 LinkList_Destroy(stack); 25 } 26 27 void LinkStack_Clear(LinkStack* stack) 28 { 29 //LinkList_Clear(stack); 30 while (LinkStack_Size(stack) > 0) 31 { 32 LinkStack_Pop(stack); //在这个函数里面有内存释放函数 33 } 34 return ; 35 } 36 37 //向栈中放元素,相当于 向线性表中插入一个元素 38 int LinkStack_Push(LinkStack* stack, void* item) 39 { 40 int ret = 0; 41 //需要item数据,转换成 linklist的业务节点 42 TLinkStackNode *pTe = (TLinkStackNode *)malloc(sizeof(TLinkStackNode)); 43 if (pTe == NULL) 44 { 45 return -1; 46 } 47 pTe->item = item; 48 49 //头插法 ,向线性表中插入元素,只不过是插入元素的时候,需要构造业务节点而已。。。。。。 50 ret = LinkList_Insert(stack, (LinkListNode *)(&pTe->node),0 ); 51 if (ret != 0) 52 { 53 free(pTe); 54 } 55 return ret; 56 } 57 58 void* LinkStack_Pop(LinkStack* stack) 59 { 60 void *myItem = NULL; 61 TLinkStackNode *pTmp = NULL; 62 pTmp = (TLinkStackNode *)LinkList_Delete(stack, 0); 63 if (pTmp == NULL) 64 { 65 return NULL; 66 } 67 myItem = pTmp->item; 68 69 //注意向线性表中,插入元素的时,打造节点,分配内存; 70 //弹出元素时,需要释放节点内存,不要忘记 71 72 if (pTmp != NULL) 73 { 74 free(pTmp); 75 } 76 return myItem; 77 } 78 79 void* LinkStack_Top(LinkStack* stack) 80 { 81 void *myItem = NULL; 82 TLinkStackNode *pTmp = NULL; 83 pTmp = (TLinkStackNode *)LinkList_Get(stack, 0); 84 if (pTmp == NULL) 85 { 86 return NULL; 87 } 88 myItem = pTmp->item; 89 return myItem; 90 } 91 92 int LinkStack_Size(LinkStack* stack) 93 { 94 return LinkList_Length(stack); 95 }
linkstack集成测试.c
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include "stdlib.h" 2 #include "stdio.h" 3 #include "string.h" 4 #include "linkstack.h" 5 6 void main() 7 { 8 int a[10], i; 9 LinkStack *stack = NULL; 10 11 stack = LinkStack_Create(); 12 13 for (i=0; i<10; i++) 14 { 15 a[i] = i+1; 16 LinkStack_Push(stack, &a[i]); 17 } 18 printf("top: %d \n", *((int *)LinkStack_Top(stack))); 19 printf("size: %d \n", LinkStack_Size(stack)); 20 21 //删除栈中所有元素 22 while (LinkStack_Size(stack) > 0) 23 { 24 printf("linkstack pop: %d \n", *((int*)LinkStack_Pop(stack)) ); 25 } 26 LinkStack_Destroy(stack); 27 28 system("pause"); 29 }
(2)不通过线性表实现(版本1)
LinkStack.h
#ifndef LINKSTACK_H #define LINKSTACK_H #include <stdlib.h> #include <stdio.h> //链式栈的结点 typedef struct LINKNODE{ struct LINKNODE* next; }LinkNode; //链式栈 typedef struct LINKSTACK{ LinkNode head; int size; }LinkStack; //初始化函数 LinkStack* Init_LinkStack(); //入栈 void Push_LinkStack(LinkStack* stack, LinkNode* data); //出栈 void Pop_LinkStack(LinkStack* stack); //返回栈顶元素 LinkNode* Top_LinkStack(LinkStack* stack); //返回栈元素的个数 int Size_LinkStack(LinkStack* stack); //清空栈 void Clear_LinkStack(LinkStack* stack); //销毁栈 void FreeSpace_LinkStack(LinkStack* stack); #endif
LinkStack.c
#include"LinkStack.h" //初始化函数 LinkStack* Init_LinkStack(){ LinkStack* stack = (LinkStack*)malloc(sizeof(LinkStack)); stack->head.next = NULL; stack->size = 0; return stack; } //入栈 void Push_LinkStack(LinkStack* stack, LinkNode* data){ if (stack == NULL){ return; } if (data == NULL){ return; } data->next = stack->head.next; stack->head.next = data; stack->size++; } //出栈 void Pop_LinkStack(LinkStack* stack){ if (stack == NULL){ return; } if (stack->size == 0){ return; } //第一个有效结点 LinkNode* pNext = stack->head.next; stack->head.next = pNext->next; stack->size--; } //返回栈顶元素 LinkNode* Top_LinkStack(LinkStack* stack){ if (stack == NULL){ return NULL; } if (stack->size == 0){ return NULL; } return stack->head.next; } //返回栈元素的个数 int Size_LinkStack(LinkStack* stack){ if (stack == NULL){ return -1; } return stack->size; } //清空栈 void Clear_LinkStack(LinkStack* stack){ if (stack == NULL){ return; } stack->head.next = NULL; stack->size = 0; } //销毁栈 void FreeSpace_LinkStack(LinkStack* stack){ if (stack == NULL){ return; } free(stack); }
栈的链式存储.c
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> #include "LinkStack.h" typedef struct PERSON{ LinkNode node; char name[64]; int age; }Person; int main(void){ //创建栈 LinkStack* stack = Init_LinkStack(); //创建数据 Person p1, p2, p3, p4, p5; strcpy(p1.name, "aaa"); strcpy(p2.name, "bbb"); strcpy(p3.name, "ccc"); strcpy(p4.name, "ddd"); strcpy(p5.name, "eee"); p1.age = 10; p2.age = 20; p3.age = 30; p4.age = 40; p5.age = 50; //入栈 Push_LinkStack(stack, (LinkNode*)&p1); Push_LinkStack(stack, (LinkNode*)&p2); Push_LinkStack(stack, (LinkNode*)&p3); Push_LinkStack(stack, (LinkNode*)&p4); Push_LinkStack(stack, (LinkNode*)&p5); //输出 while (Size_LinkStack(stack) > 0){ //取出栈顶元素 Person* p = (Person*)Top_LinkStack(stack); printf("Name:%s Age:%d\n",p->name,p->age); //弹出栈顶元素 Pop_LinkStack(stack); } //销毁栈 FreeSpace_LinkStack(stack); system("pause"); return 0; }
(3)不通过线性表实现(版本2)
LinkStack.h
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #ifndef _LINKSTACK_H 2 #define _LINKSTACK_H 3 4 // 定义小链表节点 5 typedef struct NODE 6 { 7 struct NODE* next; 8 }Node; 9 10 // 链表结构体 11 typedef struct 12 { 13 // 栈顶指针 14 Node *top; 15 // 长度 16 int length; 17 }LinkStack; 18 19 // 初始化,建立一个空栈S 20 void InitStack(LinkStack *S); 21 22 // 将栈清空 23 void ClearStack(LinkStack *S); 24 25 // 若栈为空则返回true,否则返回false 26 int StackEmpty(LinkStack S); 27 28 // 若栈存在且非空,用e返回S的栈顶元素 29 void GetTop(LinkStack S, Node **e); 30 31 // 若栈S存在,插入新元素e到栈S中并成为其栈顶元素 32 void Push(LinkStack *S, Node *e); 33 34 // 删除栈S中的栈顶元素,并用e返回其值 35 void Pop(LinkStack *S, Node **e); 36 37 // 返回栈S的元素个数 38 int StackLength(LinkStack S); 39 40 #endif // _LINKSTACK_H
LinkStack.c
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include "LinkStack.h" 2 #include <stdio.h> 3 4 void InitStack(LinkStack *S) 5 { 6 S->length = 0; 7 S->top = NULL; 8 } 9 10 void ClearStack(LinkStack *S) 11 { 12 while (S->length) 13 { 14 Node* p; 15 Pop(S, &p); 16 } 17 } 18 19 int StackEmpty(LinkStack S) 20 { 21 if (S.length == 0) 22 { 23 return 1; 24 } 25 return 0; 26 } 27 28 void GetTop(LinkStack S, Node **e) 29 { 30 // 空栈 31 if (S.length == 0) 32 { 33 return; 34 } 35 *e = S.top; 36 } 37 38 // 栈顶是链表头部 39 void Push(LinkStack *S, Node *e) 40 { 41 // 节点e插入到链表的头部 42 e->next = S->top; 43 // top指针指向第一个节点 44 S->top = e; 45 // 长度+1 46 S->length++; 47 } 48 49 void Pop(LinkStack *S, Node **e) 50 { 51 // 空栈 52 if (S->length == 0) 53 { 54 return; 55 } 56 // 删除第一个节点 57 Node* pDel = S->top; 58 // 赋值 59 *e = pDel; 60 // 栈顶指针后移 61 S->top = pDel->next; 62 // 长度减1 63 S->length--; 64 } 65 66 int StackLength(LinkStack S) 67 { 68 return S.length; 69 }
main.c
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include "LinkStack.h" 4 5 // 业务节点 6 typedef struct stu 7 { 8 // 包含链表节点 9 Node node; 10 int id; 11 int age; 12 }Student; 13 14 void main() 15 { 16 Student stu[10]; 17 // 链表结构变量 18 LinkStack st; 19 // 初始化栈 20 InitStack(&st); 21 // 初始化数组 22 for (int i = 0; i < sizeof(stu) / sizeof(Student); ++i) 23 { 24 stu[i].id = i; 25 stu[i].age = i + 20; 26 // 数据添加链表中 27 Push(&st, &stu[i].node); 28 29 30 printf("stack size = %d\n", StackLength(st)); 31 32 while (StackEmpty(st) != 1) 33 { 34 Node* p; 35 // 获取栈顶元素 36 GetTop(st, &p); 37 Student* pp = (Student*)p; 38 printf("elem id = %d, age=%d\n", pp->id, pp->age); 39 40 // 删除 41 Pop(&st, &p); 42 pp = (Student*)p; 43 printf("Delete elem id = %d, age=%d\n", pp->id, pp->age); 44 } 45 }
6.栈的应用
案例1:就近匹配
l 案例:
几乎所有的编译器都具有检测括号是否匹配的能力,那么如何实现编译器中的符号成对检测?如下字符串:
#include <stdio.h> int main() { int a[4][4]; int (*p)[4]; p = a[0]; return 0;}
l 算法思路
n 从第一个字符开始扫描
n 当遇见普通字符时忽略,
n 当遇见左符号时压入栈中
n 当遇见右符号时从栈中弹出栈顶符号,并进行匹配
n 匹配成功:继续读入下一个字符
n 匹配失败:立即停止,并报错
n 结束:
n 成功: 所有字符扫描完毕,且栈为空
n 失败:匹配失败或所有字符扫描完毕但栈非空
l 总结
n当需要检测成对出现但又互不相邻的事物时可以使用栈“后进先出”的特性
n 栈非常适合于需要“就近匹配”的场合
l 思考
计算机的本质工作就是做数学运算,那计算机可以读入字符串
“9 + (3 - 1) * 5 + 8 / 2”并计算值吗?
就近匹配.cpp
#include <iostream> #include <stack> using namespace std; // 判断左括号 bool isLeft(char c) { bool bl; switch (c) { case '[': case '(': case '{': case '<': bl = true; break; default: bl = false; break; } return bl; } bool isRight(char c) { bool bl; switch (c) { case ']': case ')': case '}': case '>': bl = true; break; default: bl = false; break; } return bl; } bool match(char left, char right) { bool bl; switch (left) { case '[': bl = right == ']'; break; case '(': bl = right == ')'; break; case '{': bl = right == '}'; break; case '<': bl = right == '>'; break; default: bl = false; break; } return bl; } void Jiujinpipei(const char* p) { int i = 0; stack<char> st; while (p[i] != '\0') { // 如果是左括号 if (isLeft(p[i])) { // 压栈 st.push(p[i]); } // 右括号 else if (isRight(p[i])) { if (!st.empty()) { // 栈顶符号 char top = st.top(); // 匹配 if (!match(top, p[i])) { cout << "匹配失败!" << endl; break; } st.pop(); } else { cout << "缺少左括号..." << endl; break; } } i++; } if (p[i] == '\0' && st.empty()) { cout << "匹配成功了...." << endl; } else { cout << "匹配失败!!!" << endl; } } void main() { // Jiujinpipei("#include <stdio.h> int main() int a[4][4]; int (*p)[4]; p = a[0]; return 0;}"); system("pause"); }
案例2:中缀表达式和后缀表达式
l 后缀表达式(由波兰科学家在20世纪50年代提出)
n 将运算符放在数字后面 ===》 符合计算机运算
n 我们习惯的数学表达式叫做中缀表达式===》符合人类思考习惯
l 实例
n 5 + 4 => 5 4 +
n 1 + 2 * 3 => 1 2 3 * +
n 8 + ( 3 – 1 ) * 5 => 8 3 1 – 5 * +
l 中缀转后缀算法:
遍历中缀表达式中的数字和符号:
n 对于数字:直接输出
n 对于符号:
u 左括号:进栈
u 运算符号:与栈顶符号进行优先级比较
-
- 若栈顶符号优先级低:此符号进栈
(默认栈顶若是左括号,左括号优先级最低)
-
- 若栈顶符号优先级不低:将栈顶符号弹出并输出,之后进栈
l 右括号:将栈顶符号弹出并输出,直到匹配左括号
遍历结束:将栈中的所有符号弹出并输出
l 中缀转后缀伪代码 priority
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
transform(exp) { 创建栈S; i= 0; while(exp[i] != ‘\0’) { if(exp[i] 为数字) { Output(exp[i]); } else if(exp[i] 为符号) { while(exp[i]优先级 <= 栈顶符号优先级) { output(栈顶符号); Pop(S); } Push(S, exp[i]); } else if(exp[i] 为左括号) { Push(S, exp[i]); } else if(exp[i] 为右括号) { while(栈顶符号不为左括号) { output(栈顶符号); Pop(S); } 从S中弹出左括号; } else { 报错,停止循环; } i++; } while(size(S) > 0 && exp[i] == ‘\0’) { output(栈顶符号); Pop(S); } }
l 动手练习
将我们喜欢的读的中缀表达式转换成计算机喜欢的后缀表达式
中缀表达式: 8 + ( 3 – 1 ) * 5
后缀表达式: 8 3 1 – 5 * +
中缀后缀表达式.cpp
#include <iostream> #include <stack> using namespace std; bool isNumber(char c) { return c >= '0' && c <= '9'; } bool isLeft(char c) { return c == '('; } bool isRight(char c) { return c == ')'; } bool isOperator(char c) { return c == '+' || c == '-' || c == '*' || c == '/'; } int priority(char c) { int ret = 0; switch (c) { case '+': case '-': ret = 1; break; case '*': case '/': ret = 2; break; default: break; } return ret; } void Transform(const char* p) { int i = 0; stack<char> st; while (p[i] != '\0') { // 数字 if (isNumber(p[i])) { // 直接输出 cout << p[i]; } // 左括号 else if (isLeft(p[i])) { // 进栈 st.push(p[i]); } // 运算符 else if (isOperator(p[i])) { // 优先级的比较 while (!st.empty() && priority(st.top()) >= priority(p[i])) { // 输出 cout << st.top(); st.pop(); } // 进栈 st.push(p[i]); } // 右括号 else if (isRight(p[i])) { // 如果不是左括号, 弹出并输出 while (!isLeft(st.top())) { cout << st.top(); st.pop(); } // 弹出左括号 st.pop(); } i++; } while (!st.empty()) { cout << st.top(); st.pop(); } } void main() { Transform("8+(3-1)*5"); system("pause"); }
案例3 计算机如何基于后缀表达式计算
l 思考
计算机是如何基于后缀表达式计算的?
例如:8 3 1 – 5 * +
l 计算规则
遍历后缀表达式中的数字和符号
n 对于数字:进栈
n 对于符号:
u 从栈中弹出右操作数
u 从栈中弹出左操作数
u 根据符号进行运算
u 将运算结果压入栈中
遍历结束:栈中的唯一数字为计算结果
l 代码实现(伪代码) express
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
compute(exp) { 创建栈; int i = 0; while( exp[i] != ‘\0’) { if(exp[i]为数字) { Push(S, exp[i]); } else if(exp[i]为符号) { 1. 从栈顶弹出右操作数; 2. 从栈中弹出左操作数; 3. 根据符号进行运算; 4. Push(stack, 结果); } else { 报错,停止循环; } i++; } if( Size(s) == 1 && exp[i] == ‘\0’) { 栈中唯一的数字为运算结果; } 返回结果; }
demo03_后缀计算.c
#include <stdio.h> #include "LinkStack.h" int isNumber3(char c) { return ('0' <= c) && (c <= '9'); } int isOperator3(char c) { return (c == '+') || (c == '-') || (c == '*') || (c == '/'); } int value(char c) { return (c - '0'); } int express(int left, int right, char op) { int ret = 0; switch(op) { case '+': ret = left + right; break; case '-': ret = left - right; break; case '*': ret = left * right; break; case '/': ret = left / right; break; default: break; } return ret; } int compute(const char* exp) { LinkStack* stack = LinkStack_Create(); int ret = 0; int i = 0; while( exp[i] != '\0' ) { if( isNumber3(exp[i]) ) { LinkStack_Push(stack, (void*)value(exp[i])); } else if( isOperator3(exp[i]) ) { int right = (int)LinkStack_Pop(stack); int left = (int)LinkStack_Pop(stack); int result = express(left, right, exp[i]); LinkStack_Push(stack, (void*)result); } else { printf("Invalid expression!"); break; } i++; } if( (LinkStack_Size(stack) == 1) && (exp[i] == '\0') ) { ret = (int)LinkStack_Pop(stack); } else { printf("Invalid expression!"); } LinkStack_Destroy(stack); return ret; } int main() { printf("8 + (3 - 1) * 5 = %d\n", compute("831-5*+")); system("pause"); return 0; }
综合成一个项目:
linklist.h
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #ifndef _MYLINKLIST_H_ 2 #define _MYLINKLIST_H_ 3 4 typedef void LinkList; 5 /* 6 typedef struct _tag_LinkListNode LinkListNode; 7 struct _tag_LinkListNode 8 { 9 LinkListNode* next; 10 }; 11 */ 12 typedef struct _tag_LinkListNode 13 { 14 struct _tag_LinkListNode* next; 15 }LinkListNode; 16 17 LinkList* LinkList_Create(); 18 19 void LinkList_Destroy(LinkList* list); 20 21 void LinkList_Clear(LinkList* list); 22 23 int LinkList_Length(LinkList* list); 24 25 int LinkList_Insert(LinkList* list, LinkListNode* node, int pos); 26 27 LinkListNode* LinkList_Get(LinkList* list, int pos); 28 29 LinkListNode* LinkList_Delete(LinkList* list, int pos); 30 31 #endif
linkstack.h
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #ifndef _MY_LINKSTACK_H_ 2 #define _MY_LINKSTACK_H_ 3 4 typedef void LinkStack; 5 6 LinkStack* LinkStack_Create(); 7 8 void LinkStack_Destroy(LinkStack* stack); 9 10 void LinkStack_Clear(LinkStack* stack); 11 12 int LinkStack_Push(LinkStack* stack, void* item); 13 14 void* LinkStack_Pop(LinkStack* stack); 15 16 void* LinkStack_Top(LinkStack* stack); 17 18 int LinkStack_Size(LinkStack* stack); 19 20 #endif //_MY_LINKSTACK_H_
linkstack.c
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include "stdlib.h" 2 #include "stdio.h" 3 #include "string.h" 4 #include "linkstack.h" 5 #include "linklist.h" 6 7 typedef struct _tag_LinkStackNode 8 { 9 LinkListNode node; //占位结构。。。只要定义一个和node节大小一样的数据即可 10 void *item; 11 }TLinkStackNode; 12 13 //我要创建一个linkstack,准备用linklist去模拟实现 14 //相当于在 linkstack.c中写 linklist库的测试程序。。。。。。 15 LinkStack* LinkStack_Create() 16 { 17 //创建一个栈,通过线性表去模拟。。。(创建一个栈,相当于创建一个线性表) 18 return LinkList_Create(); 19 } 20 21 void LinkStack_Destroy(LinkStack* stack) 22 { 23 LinkStack_Clear(stack); //注意 destory的时候,需要把栈中的所有元素都清空 24 LinkList_Destroy(stack); 25 } 26 27 void LinkStack_Clear(LinkStack* stack) 28 { 29 //LinkList_Clear(stack); 30 while (LinkStack_Size(stack) > 0) 31 { 32 LinkStack_Pop(stack); //在这个函数里面有内存释放函数 33 } 34 return ; 35 } 36 37 //向栈中放元素,相当于 向线性表中插入一个元素 38 int LinkStack_Push(LinkStack* stack, void* item) 39 { 40 int ret = 0; 41 //需要item数据,转换成 linklist的业务节点 42 TLinkStackNode *pTe = (TLinkStackNode *)malloc(sizeof(TLinkStackNode)); 43 if (pTe == NULL) 44 { 45 return -1; 46 } 47 pTe->item = item; 48 49 //头插法 ,向线性表中插入元素,只不过是插入元素的时候,需要构造业务节点而已。。。。。。 50 ret = LinkList_Insert(stack, (LinkListNode *)(&pTe->node),0 ); 51 if (ret != 0) 52 { 53 free(pTe); 54 } 55 return ret; 56 } 57 58 void* LinkStack_Pop(LinkStack* stack) 59 { 60 void *myItem = NULL; 61 TLinkStackNode *pTmp = NULL; 62 pTmp = (TLinkStackNode *)LinkList_Delete(stack, 0); 63 if (pTmp == NULL) 64 { 65 return NULL; 66 } 67 myItem = pTmp->item; 68 69 //注意向线性表中,插入元素的时,打造节点,分配内存; 70 //弹出元素时,需要释放节点内存,不要忘记 71 72 if (pTmp != NULL) 73 { 74 free(pTmp); 75 } 76 return myItem; 77 } 78 79 void* LinkStack_Top(LinkStack* stack) 80 { 81 void *myItem = NULL; 82 TLinkStackNode *pTmp = NULL; 83 pTmp = (TLinkStackNode *)LinkList_Get(stack, 0); 84 if (pTmp == NULL) 85 { 86 return NULL; 87 } 88 myItem = pTmp->item; 89 return myItem; 90 } 91 92 int LinkStack_Size(LinkStack* stack) 93 { 94 return LinkList_Length(stack); 95 }
栈的应用后缀表达式.c
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include "stdio.h" 2 #include "stdlib.h" 3 #include "linkstack.h" 4 5 int isLeft(char c) 6 { 7 int ret = 0; 8 9 switch(c) 10 { 11 case '<': 12 case '(': 13 case '[': 14 case '{': 15 case '\'': 16 case '\"': 17 ret = 1; 18 break; 19 default: 20 ret = 0; 21 break; 22 } 23 24 return ret; 25 } 26 27 int isRight(char c) 28 { 29 int ret = 0; 30 31 switch(c) 32 { 33 case '>': 34 case ')': 35 case ']': 36 case '}': 37 case '\'': 38 case '\"': 39 ret = 1; 40 break; 41 default: 42 ret = 0; 43 break; 44 } 45 46 return ret; 47 } 48 49 int match(char left, char right) 50 { 51 int ret = 0; 52 53 switch(left) 54 { 55 case '<': 56 ret = (right == '>'); 57 break; 58 case '(': 59 ret = (right == ')'); 60 break; 61 case '[': 62 ret = (right == ']'); 63 break; 64 case '{': 65 ret = (right == '}'); 66 break; 67 case '\'': 68 ret = (right == '\''); 69 break; 70 case '\"': 71 ret = (right == '\"'); 72 break; 73 default: 74 ret = 0; 75 break; 76 } 77 78 return ret; 79 } 80 //就近匹配原理 81 int scanner(const char* code) 82 { 83 LinkStack* stack = LinkStack_Create(); 84 int ret = 0; 85 int i = 0; 86 87 while( code[i] != '\0' ) 88 { 89 if( isLeft(code[i]) ) 90 { 91 LinkStack_Push(stack, (void*)(code + i)); //&code[i] 92 } 93 94 if( isRight(code[i]) ) 95 { 96 char* c = (char*)LinkStack_Pop(stack); 97 98 if( (c == NULL) || !match(*c, code[i]) ) 99 { 100 printf("%c does not match!\n", code[i]); 101 ret = 0; 102 break; 103 } 104 } 105 106 i++; 107 } 108 109 if( (LinkStack_Size(stack) == 0) && (code[i] == '\0') ) 110 { 111 printf("Succeed!\n"); 112 ret = 1; 113 } 114 else 115 { 116 printf("Invalid code!\n"); 117 ret = 0; 118 } 119 120 LinkStack_Destroy(stack); 121 122 return ret; 123 } 124 125 void main() 126 { 127 const char* code = "#include <stdio.h> int main() { int a[4][4]; int (*p)[4]; p = a[0]; return 0; "; 128 129 scanner(code); 130 system("pause"); 131 return ; 132 }
demo02_中缀转后缀.c
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include "stdio.h" 2 #include "stdlib.h" 3 #include "string.h" 4 #include "linkstack.h" 5 6 int isNumber(char c) 7 { 8 return ('0' <= c) && (c <= '9'); 9 } 10 11 int isOperator(char c) 12 { 13 return (c == '+') || (c == '-') || (c == '*') || (c == '/'); 14 } 15 16 int isLeft(char c) 17 { 18 return (c == '('); 19 } 20 21 int isRight(char c) 22 { 23 return (c == ')'); 24 } 25 26 int priority(char c) 27 { 28 int ret = 0; 29 30 if( (c == '+') || (c == '-') ) 31 { 32 ret = 1; 33 } 34 35 if( (c == '*') || (c == '/') ) 36 { 37 ret = 2; 38 } 39 40 return ret; 41 } 42 43 void output(char c) 44 { 45 if( c != '\0' ) 46 { 47 printf("%c", c); 48 } 49 } 50 51 void transform(const char* exp) 52 { 53 int i = 0; 54 LinkStack* stack = LinkStack_Create(); 55 56 while( exp[i] != '\0' ) 57 { 58 if( isNumber(exp[i]) ) 59 { 60 output(exp[i]); 61 } 62 else if( isOperator(exp[i]) ) 63 { 64 while( priority(exp[i]) <= priority((char)(int)LinkStack_Top(stack)) ) 65 { 66 output((char)(int)LinkStack_Pop(stack)); 67 } 68 69 LinkStack_Push(stack, (void*)(int)exp[i]); 70 } 71 else if( isLeft(exp[i]) ) 72 { 73 LinkStack_Push(stack, (void*)(int)exp[i]); 74 } 75 else if( isRight(exp[i]) ) 76 { 77 //char c = '\0'; 78 while( !isLeft((char)(int)LinkStack_Top(stack)) ) 79 { 80 output((char)(int)LinkStack_Pop(stack)); 81 } 82 83 LinkStack_Pop(stack); 84 } 85 else 86 { 87 printf("Invalid expression!"); 88 break; 89 } 90 91 i++; 92 } 93 94 while( (LinkStack_Size(stack) > 0) && (exp[i] == '\0') ) 95 { 96 output((char)(int)LinkStack_Pop(stack)); 97 } 98 99 LinkStack_Destroy(stack); 100 } 101 102 int main() 103 { 104 transform("8+(3-1)*5"); 105 106 printf("\n"); 107 system("pause"); 108 return 0; 109 }
demo03_后缀计算.c
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <stdio.h> 2 #include "LinkStack.h" 3 4 int isNumber3(char c) 5 { 6 return ('0' <= c) && (c <= '9'); 7 } 8 9 int isOperator3(char c) 10 { 11 return (c == '+') || (c == '-') || (c == '*') || (c == '/'); 12 } 13 14 int value(char c) 15 { 16 return (c - '0'); 17 } 18 19 int express(int left, int right, char op) 20 { 21 int ret = 0; 22 23 switch(op) 24 { 25 case '+': 26 ret = left + right; 27 break; 28 case '-': 29 ret = left - right; 30 break; 31 case '*': 32 ret = left * right; 33 break; 34 case '/': 35 ret = left / right; 36 break; 37 default: 38 break; 39 } 40 41 return ret; 42 } 43 44 int compute(const char* exp) 45 { 46 LinkStack* stack = LinkStack_Create(); 47 int ret = 0; 48 int i = 0; 49 50 while( exp[i] != '\0' ) 51 { 52 if( isNumber3(exp[i]) ) 53 { 54 LinkStack_Push(stack, (void*)value(exp[i])); 55 } 56 else if( isOperator3(exp[i]) ) 57 { 58 int right = (int)LinkStack_Pop(stack); 59 int left = (int)LinkStack_Pop(stack); 60 int result = express(left, right, exp[i]); 61 62 LinkStack_Push(stack, (void*)result); 63 } 64 else 65 { 66 printf("Invalid expression!"); 67 break; 68 } 69 70 i++; 71 } 72 73 if( (LinkStack_Size(stack) == 1) && (exp[i] == '\0') ) 74 { 75 ret = (int)LinkStack_Pop(stack); 76 } 77 else 78 { 79 printf("Invalid expression!"); 80 } 81 82 LinkStack_Destroy(stack); 83 84 return ret; 85 } 86 87 int main() 88 { 89 printf("8 + (3 - 1) * 5 = %d\n", compute("831-5*+")); 90 system("pause"); 91 return 0; 92 }
案例4:栈的应用之进制转换
资料来自互联网
以后带补充,如果有雷同,纯属巧合。。如果认为不错,请关注一下。