栈的定义及实现
栈的定义
栈是一种特殊的线性表
栈仅能在线性表的一端进行操作
栈顶(Top):允许操作的一端
栈底(Bottom):不允许操作的一端
栈的性质
栈的操作
栈的一些常用操作
创建栈
销毁栈
清空栈
进栈
出栈
获取栈顶元素
获取栈的大小
栈的顺序存储实现
顺序存储实现
下面的顺序栈是不能支持结构体的!
现在我们先来实现顺序栈,由于之前我们实现了顺序表,现在代码复用,用其来实现顺序栈。
eg:
SeqStack.h
#ifndef _SEQSTACK_H_ #define _SEQSTACK_H_ typedef void SeqStack; typedef void * Stack_element; SeqStack* SeqStack_Create(int capacity); void SeqStack_Destroy(SeqStack* stack); void SeqStack_Clear(SeqStack* stack); int SeqStack_Push(SeqStack* stack, Stack_element item); void* SeqStack_Pop(SeqStack* stack); void* SeqStack_Top(SeqStack* stack); int SeqStack_Size(SeqStack* stack); int SeqStack_Capacity(SeqStack* stack); #endif
SeqStack.c
1 #include "SeqStack.h" 2 #include "SeqList.h" 3 4 SeqStack* SeqStack_Create(int capacity) 5 { 6 return SeqList_Create(capacity); 7 } 8 9 void SeqStack_Destroy(SeqStack* stack) 10 { 11 SeqList_Destroy(stack); 12 } 13 14 void SeqStack_Clear(SeqStack* stack) 15 { 16 SeqList_Clear(stack); 17 } 18 19 int SeqStack_Push(SeqStack* stack, Stack_element item) 20 { 21 return SeqList_Insert(stack, item, SeqList_Length(stack));//压栈都是在尾部压入 22 } 23 24 void* SeqStack_Pop(SeqStack* stack) 25 { 26 return SeqList_Delete(stack, SeqList_Length(stack) - 1);//出栈是最后一个元素 27 } 28 29 void* SeqStack_Top(SeqStack* stack) 30 { 31 return SeqList_Get(stack, SeqList_Length(stack) - 1);//获取栈顶元素 32 } 33 34 int SeqStack_Size(SeqStack* stack) 35 { 36 return SeqList_Length(stack); 37 } 38 39 int SeqStack_Capacity(SeqStack* stack) 40 { 41 return SeqList_Capacity(stack); 42 }
SeqList.h (复用之前的代码)
1 #ifndef _SEQLIST_H_ 2 #define _SEQLIST_H_ 3 4 typedef void SeqList; 5 typedef void SeqListNode; 6 7 SeqList* SeqList_Create(int capacity); 8 9 void SeqList_Destroy(SeqList* list); 10 11 void SeqList_Clear(SeqList* list); 12 13 int SeqList_Length(SeqList* list); 14 15 int SeqList_Capacity(SeqList* list); 16 17 int SeqList_Insert(SeqList* list, SeqListNode* node, int pos); 18 19 SeqListNode* SeqList_Get(SeqList* list, int pos); 20 21 SeqListNode* SeqList_Delete(SeqList* list, int pos); 22 23 #endif
SeqList.c(复用之前的代码)
#include <stdio.h> #include <malloc.h> #include "SeqList.h" typedef unsigned int TSeqListNode; typedef struct _tag_SeqList { int capacity; int length; TSeqListNode* node; } TSeqList; SeqList* SeqList_Create(int capacity) // O(1) { TSeqList* ret = NULL; if( capacity >= 0 ) { ret = (TSeqList*)malloc(sizeof(TSeqList) + sizeof(TSeqListNode) * capacity); } if( ret != NULL ) { ret->capacity = capacity; ret->length = 0; ret->node = (TSeqListNode*)(ret + 1); } return ret; } void SeqList_Destroy(SeqList* list) // O(1) { free(list); } void SeqList_Clear(SeqList* list) // O(1) { TSeqList* sList = (TSeqList*)list; if( sList != NULL ) { sList->length = 0; } } int SeqList_Length(SeqList* list) // O(1) { TSeqList* sList = (TSeqList*)list; int ret = -1; if( sList != NULL ) { ret = sList->length; } return ret; } int SeqList_Capacity(SeqList* list) // O(1) { TSeqList* sList = (TSeqList*)list; int ret = -1; if( sList != NULL ) { ret = sList->capacity; } return ret; } int SeqList_Insert(SeqList* list, SeqListNode* node, int pos) // O(n) { TSeqList* sList = (TSeqList*)list; int ret = (sList != NULL); int i = 0; ret = ret && (sList->length + 1 <= sList->capacity); ret = ret && (0 <= pos); if( ret ) { if( pos >= sList->length ) { pos = sList->length; } for(i=sList->length; i>pos; i--) { sList->node[i] = sList->node[i-1]; } sList->node[i] = (TSeqListNode)node; sList->length++; } return ret; } SeqListNode* SeqList_Get(SeqList* list, int pos) // O(1) { TSeqList* sList = (TSeqList*)list; SeqListNode* ret = NULL; if( (sList != NULL) && (0 <= pos) && (pos < sList->length) ) { ret = (SeqListNode*)(sList->node[pos]); } return ret; } SeqListNode* SeqList_Delete(SeqList* list, int pos) // O(n) { TSeqList* sList = (TSeqList*)list; SeqListNode* ret = SeqList_Get(list, pos); int i = 0; if( ret != NULL ) { for(i=pos+1; i<sList->length; i++) { sList->node[i-1] = sList->node[i]; } sList->length--; } return ret; }
main.c:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include "SeqStack.h" 4 5 int main(int argc, char *argv[]) 6 { 7 SeqStack* stack = SeqStack_Create(20); 8 int a[10]; 9 int i = 0; 10 11 for(i=0; i<10; i++) 12 { 13 a[i] = i; 14 15 SeqStack_Push(stack, a + i); 16 } 17 18 printf("Top: %d\n", *(int*)SeqStack_Top(stack)); 19 printf("Capacity: %d\n", SeqStack_Capacity(stack)); 20 printf("Length: %d\n", SeqStack_Size(stack)); 21 22 while( SeqStack_Size(stack) > 0 ) 23 { 24 printf("Pop: %d\n", *(int*)SeqStack_Pop(stack)); 25 } 26 27 SeqStack_Destroy(stack); 28 29 return 0; 30 }
运行结果:
NOTE:由于线性表的实现利用了指针,而我们的编译器有可能是64bit也可能是32bit的,所以添加如下条件编译:
Seqlist.c中增加:
#include <stdio.h> #include <malloc.h> #include "SeqList.h" #define Compiler_64Bit //#define Compiler_32Bit #ifdef Compiler_32Bit typedef unsigned int TSeqListNode;//为了存放一个指针强制类型转化后的值 #endif #ifdef Compiler_64Bit typedef long long TSeqListNode;//为了存放一个指针强制类型转化后的值 #endif #if !defined(Compiler_32Bit) && !defined(Compiler_64Bit) #error "Compiler_32Bit or Compiler_64Bit not defined! see SeqList.c 6,7 line!\r\n" #endif
栈的链式实现:
链式栈是可以支持结构体的,但是要求和链式表一样需要包含特定的头,为了后续的例程复用,下面不使用结构体类型入栈操作。
eg:
LinkStack.h
#ifndef _LINKSTACK_H_ #define _LINKSTACK_H_ //抽象数据类型 typedef void LinkStack; //创建顺序栈 LinkStack* LinkStack_Create(); //销毁 void LinkStack_Destroy(LinkStack* stack); //清除 void LinkStack_Clear(LinkStack* stack); //压栈 int LinkStack_Push(LinkStack* stack, void* item); //出栈,弹出 void* LinkStack_Pop(LinkStack* stack); //栈顶 void* LinkStack_Top(LinkStack* stack); //栈大小 int LinkStack_Size(LinkStack* stack); #endif
创建链式栈:
这里复用了之前的顺序表的函数LinkList_Create();
typedef struct _tag_LinkListNode LinkListNode;
struct _tag_LinkListNode
{
LinkListNode* next;
};
typedef struct _tag_LinkList
{
LinkListNode header;
int length;
} TLinkList;
这里使用LinkListNode header;head结构体里面包含了一个指向自身结构类型的指针,这就是我们的指针域,用来寻找下家的。
链式表的源文件和头文件就不在贴出了,之前的随笔里面已经讲解和贴出了。
链式栈的头文件:
#ifndef _LINKSTACK_H_ #define _LINKSTACK_H_ typedef void LinkStack; LinkStack* LinkStack_Create(); void LinkStack_Destroy(LinkStack* stack); void LinkStack_Clear(LinkStack* stack); int LinkStack_Push(LinkStack* stack, void* item); void* LinkStack_Pop(LinkStack* stack); void* LinkStack_Top(LinkStack* stack); int LinkStack_Size(LinkStack* stack); #endif
源文件:
#include <stdio.h> #include <malloc.h> #include "LinkStack.h" #include "LinkList.h" typedef struct _tag_LinkStackNode { LinkListNode header; void* item; } TLinkStackNode; LinkStack* LinkStack_Create() { return LinkList_Create(); } void LinkStack_Destroy(LinkStack* stack) { LinkStack_Clear(stack); LinkList_Destroy(stack); } void LinkStack_Clear(LinkStack* stack) { while( LinkStack_Size(stack) > 0 ) { LinkStack_Pop(stack); } } int LinkStack_Push(LinkStack* stack, void* item) { TLinkStackNode* node = (TLinkStackNode*)malloc(sizeof(TLinkStackNode)); int ret = (node != NULL) && (item != NULL); if( ret ) { node->item = item; ret = LinkList_Insert(stack, (LinkListNode*)node, 0); } if( !ret ) { free(node); } return ret; } void* LinkStack_Pop(LinkStack* stack) { TLinkStackNode* node = (TLinkStackNode*)LinkList_Delete(stack, 0); void* ret = NULL; if( node != NULL ) { ret = node->item; free(node); } return ret; } void* LinkStack_Top(LinkStack* stack) { TLinkStackNode* node = (TLinkStackNode*)LinkList_Get(stack, 0); void* ret = NULL; if( node != NULL ) { ret = node->item; } return ret; } int LinkStack_Size(LinkStack* stack) { return LinkList_Length(stack); }
注意,上面的push操作时插入到链表首的,这样更快一些,不用循环到链表尾部。
链式栈的清除不能直接调用链式表的清除,否则产生内存泄露,这里主要是为了之后的栈的例子,所以使用基本类型元素入栈,如果实现成可以支持结构体入栈的形式,直接调用链式表的清除函数即可,这个留给大家练手,可参考链式表的实现。
链式栈的销毁是在调用了栈的清除函数之后再次调用链式表的销毁构成的,其他的复用没有什么变化。
main函数:
#include <stdio.h> #include <stdlib.h> #include "LinkStack.h" int main(int argc, char *argv[]) { LinkStack* stack = LinkStack_Create(); int a[10]; int i = 0; for(i=0; i<10; i++) { a[i] = i; LinkStack_Push(stack, a + i); } printf("Top: %d\n", *(int*)LinkStack_Top(stack)); printf("Length: %d\n", LinkStack_Size(stack)); while( LinkStack_Size(stack) > 0 ) { printf("Pop: %d\n", *(int*)LinkStack_Pop(stack)); } LinkStack_Destroy(stack); return 0; }
程序的输出结果和顺序栈是一致的。
欢迎加入作者的小圈子
扫描下方左边二维码加入QQ交流群,扫描下方右边二维码关注个人微信公众号并获取更多隐藏干货,QQ交流群:816747642 微信公众号:Crystal软件学堂
作者:Crystal软件学堂 bilibili视频教程地址:https://space.bilibili.com/5782182 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在转载文章页面给出原文连接。 如果你觉得文章对你有所帮助,烦请点个推荐,你的支持是我更文的动力。 文中若有错误,请您务必指出,感谢给予我建议并让我提高的你。 |