棧的定義
棧是一種特殊的線性表
棧僅能在線性表的一端進行操作
棧頂(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; }
程序的輸出結果和順序棧是一致的。