一、栈的基本定义
1、栈是一种特殊的线性表,只能从固定的方向进出,而且栈进出的基本原则是:先进栈的元素后出栈。
2、栈顶栈底的定义:
栈顶:允许操作的一端。
栈底:不允许操作的一端。
二、栈的基本实现方式
1、使用顺序存储的方式实现栈
在这种方式下,我们采用顺序表的复用方法来实现栈的数据存储。
2、使用链式存储来实现栈
在这种方式下,我们采用单向链表的复用技术来实现链栈。
三、普通的顺序栈
1、首先定义的顺序栈中的数据节点的结构,主要包括两个部分,一部分是数据元素,另一部分是顺序栈的长度。
具体代码如下:
新建文件名:SeqList.h
typedef struct _tag_stack_
{
int a[20];
int top;
}Sqstack;
{
int a[20];
int top;
}Sqstack;
2、使用顺序栈之前要先初始化顺序栈。
主要是为顺序栈节点分配一个空间,然后将顺序栈的长度初始化为0。
Sqstack* InitStack ()
{
Sqstack *ret = NULL;
ret = (Sqstack*)malloc (sizeof(Sqstack));
if (ret)
{
/*将栈的长度初始化为0*/
ret -> top = 0;
}
return ret;
}
{
Sqstack *ret = NULL;
ret = (Sqstack*)malloc (sizeof(Sqstack));
if (ret)
{
/*将栈的长度初始化为0*/
ret -> top = 0;
}
return ret;
}
3、将元素压入栈,这里采用复用方式。
int Push(Sqstack *stack, int data)
{
/*这里有一个复用方式,也就是顺序栈的长度和数组的下标进行复用s*/
stack -> a[stack -> top] = data;
stack -> top++;
return 1;
}
{
/*这里有一个复用方式,也就是顺序栈的长度和数组的下标进行复用s*/
stack -> a[stack -> top] = data;
stack -> top++;
return 1;
}
4、将已经在栈中的元素进行打印,因为栈不是只是一种存储数据的结构,所以我们不经过弹出栈中的元素也是可以访问到栈中的元素的。
void Play (Sqstack *stack)
{
int i = 0;
if (stack -> top == 0)
{
printf ("It is empty\n");
}
/*stack -> top,栈的长度*/
else
{
for (i = 0; i < stack -> top; i++)
{
printf ("栈中的数据为:%d\n", stack -> a[i]);
}
}
}
{
int i = 0;
if (stack -> top == 0)
{
printf ("It is empty\n");
}
/*stack -> top,栈的长度*/
else
{
for (i = 0; i < stack -> top; i++)
{
printf ("栈中的数据为:%d\n", stack -> a[i]);
}
}
}
5、数据节点出栈
int Pop (Sqstack *stack, int *data)
{
if (stack -> top == 0)
{
printf ("the stack is empty\n");
printf ("弹出已经被改变了的u的值");
}
else
{
stack -> top--;
*data = stack -> a[stack -> top];
}
return 1;
}
{
if (stack -> top == 0)
{
printf ("the stack is empty\n");
printf ("弹出已经被改变了的u的值");
}
else
{
stack -> top--;
*data = stack -> a[stack -> top];
}
return 1;
}
6、测试部分代码如下:
a) 把1~5步骤按顺序组合成SeqList.h文件
b) 创建StackTest.cpp文件,代码如下:
#include <stdio.h>
#include <malloc.h>
#include "SeqList.h"
int main()
{
int h = 4;
int p = 0;
int i = 0;
int u = 3;
Sqstack* qq;
qq = InitStack();
for (i = 0; i < 5; i++)
{
Push (qq, i);
}
Play (qq);
/*弹出操作*/
Pop (qq, &u);
printf ("弹出的元素是:%d\n", u);
Pop (qq, &u);
printf ("弹出的元素是:%d\n", u);
Pop (qq, &u);
printf ("弹出的元素是:%d\n", u);
Pop (qq, &u);
printf ("弹出的元素是:%d\n", u);
Pop (qq, &u);
printf ("弹出的元素是:%d\n", u);
Pop (qq, &u);
printf ("%d\n", u);
return 1;
}
#include <malloc.h>
#include "SeqList.h"
int main()
{
int h = 4;
int p = 0;
int i = 0;
int u = 3;
Sqstack* qq;
qq = InitStack();
for (i = 0; i < 5; i++)
{
Push (qq, i);
}
Play (qq);
/*弹出操作*/
Pop (qq, &u);
printf ("弹出的元素是:%d\n", u);
Pop (qq, &u);
printf ("弹出的元素是:%d\n", u);
Pop (qq, &u);
printf ("弹出的元素是:%d\n", u);
Pop (qq, &u);
printf ("弹出的元素是:%d\n", u);
Pop (qq, &u);
printf ("弹出的元素是:%d\n", u);
Pop (qq, &u);
printf ("%d\n", u);
return 1;
}
c) 编译与执行:
编译:g++ StackTest.cpp -o StackTest
执行:./StackTest
7、虽然顺序栈实现了栈的基本功能,毕竟是顺序存储结构,而且占用的内存空间也必须是连续的,所以还是有一定的局限性的。
四、链式栈的实现
1、定义数据节点
数据节点用结构体来封装,这个结构体中包含了每一个next元素的信息和进栈元素的地址,虽然我们在创建链表的时候已经进行了一个结构体的定义,但是我们的栈成员并不适用于那套链表,所以这里进行重新定义。
typedef struct _tag_LinkStack_
{
LinkListNode header;
void *item;
}TLinkStackNode;
{
LinkListNode header;
void *item;
}TLinkStackNode;
2、销毁栈的函数
void LinkStack_Destroy(LinkStack* stack)
{
/*调用栈清空函数*/
LinkStack_Clear (stack);
/*调用链表销毁函数*/
LinkList_Destroy(stack);
}
{
/*调用栈清空函数*/
LinkStack_Clear (stack);
/*调用链表销毁函数*/
LinkList_Destroy(stack);
}
销毁栈的函数中主要调用了栈的清空函数和链表的销毁函数,销毁栈的前提首先要销清空栈中的每一个成员,然后在销毁栈的头。
3、栈的清空函数
void LinkStack_Clear(LinkStack* stack)
{
while (LinkStack_Size (stack) > 0)
{
LinkStack_Pop (stack);
}
}
{
while (LinkStack_Size (stack) > 0)
{
LinkStack_Pop (stack);
}
}
栈的清空函数中和链表的清空函数是有区别的,在栈的清空函数中我们主要是对栈中是否还存在元素进行了判定,如果还有元素就对将栈中的元素弹出,而链表的清空只是将链表头指向NULL,将链表长度置为0。
4、将元素压入栈的操作
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;
}
{
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;
}
在将元素压入栈的过程中,我们首先要为我们即将压入栈的元素开辟一块空间,因为是链式表,所以我们的空间不一定非要是连续的,这是采用malloc的方式。
然后进行安全性的检测,我们要判断开辟的空间是否成功,然后还要判断我们要插入的元素的地址是不是空。如果条件都成立那我们进行元素的进栈操作。
元素的进栈操作,我们将要插入的数据节点的地址赋给栈结构体的item,然后调用链表的插入函数操作,将这个栈的数据节点插入栈中,而且由于我们是把链表的头作为栈顶,所以我们插入栈元素的位置为0。
如果我们的安全性检测没有通过,那么我们就释放为了插入一个栈元素而释放的空间。
5、元素的出栈操作
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;
}
{
TLinkStackNode* node = (TLinkStackNode*)LinkList_Delete(stack, 0);
void * ret = NULL;
if (node != NULL)
{
ret = node->item;
free(node);
}
return ret;
}
元素的出栈操作中,首先通过调用链表的元素删除函数来删除我们要弹出栈的元素,因为栈永远都是从栈顶弹出元素,而我们进栈的方向也是从链表的0位置方向进栈的,所以我们只要删除链表中的第0个元素即可(所谓的链表第0个元素)。
然后我们判定要删除的元素是否为空,如果不为空,那么我们将返回我们要弹出栈的元素。
在将元素弹出栈以后我们就要释放为这个链表中的元素开辟的空间。而我们的链表操作的空间是在操作具体数据元素的时候才开辟空间,我们不使用链表的时候它是不占用空间的。
6、获取栈顶元素操作
void* LinkStack_Top(LinkStack* stack)
{
TLinkStackNode* node = (TLinkStackNode*)LinkList_Get(stack, 0);
void *ret = NULL;
if (node != NULL)
{
ret = node->item;
}
return ret;
}
{
TLinkStackNode* node = (TLinkStackNode*)LinkList_Get(stack, 0);
void *ret = NULL;
if (node != NULL)
{
ret = node->item;
}
return ret;
}
通过LinkList_Get函数可以获得固定位置的元素,由于我们进栈的时候就是从0位置,所以在我们获取栈顶元素的时候也是从0位置开始获取。
7、测试链式栈实现代码
a) 创建一个Stack.h
#ifndef Stack_H
#define Stack_H
typedef int Item;
typedef struct node * PNode;
typedef struct node
{
Item data;
PNode next;
}Node;
typedef struct stack *PStack;
typedef struct stack
{
Item size;
PNode top;
}Stack;
/***创建空栈,并返回栈顶***/
PStack Creat_Stack();
/***判断是否为空栈***/
int Is_Empty(PStack);
/***数据项入栈***/
PStack Push_Stack(PStack,Item);
/***计算栈的大小***/
int Size_Stack(PStack);
/***返回栈顶数据项***/
Item Get_Item_Stack(PStack);
/***数据项出栈***/
Item Pop_Stack(PStack);
/***清空链栈***/
void Clear_Stack(PStack);
/***遍历栈,并自栈顶输出数据项***/
void Traverse_Stack(PStack);
#endif
#define Stack_H
typedef int Item;
typedef struct node * PNode;
typedef struct node
{
Item data;
PNode next;
}Node;
typedef struct stack *PStack;
typedef struct stack
{
Item size;
PNode top;
}Stack;
/***创建空栈,并返回栈顶***/
PStack Creat_Stack();
/***判断是否为空栈***/
int Is_Empty(PStack);
/***数据项入栈***/
PStack Push_Stack(PStack,Item);
/***计算栈的大小***/
int Size_Stack(PStack);
/***返回栈顶数据项***/
Item Get_Item_Stack(PStack);
/***数据项出栈***/
Item Pop_Stack(PStack);
/***清空链栈***/
void Clear_Stack(PStack);
/***遍历栈,并自栈顶输出数据项***/
void Traverse_Stack(PStack);
#endif
b) 创建StackTest.cpp
#include<stdio.h>
#include<stdlib.h>
#include"Stack.h"
/***创建空栈,并返回栈顶***/
PStack Creat_Stack()
{
PStack P=(PStack)malloc(sizeof(Stack));
if(NULL!=P)
{
P->top=NULL;
P->size=0;
}
return P;
}
/***判断是否为空栈***/
int Is_Empty(PStack P)
{
if(0==P->size && NULL==P->top)
return 1;
else
return 0;
}
/***数据项入栈***/
PStack Push_Stack(PStack P,Item val)
{
PNode PNew=(PNode)malloc(sizeof(Node));
if(NULL==PNew)
{
printf("Malloc the PNew is failed.\n");
exit(1);
}
else
{
PNew->data=val;
PNew->next=P->top;
P->top=PNew;
P->size++;
}
return P;
}
/***计算栈的大小***/
int Size_Stack(PStack P)
{
/*int size=0;
PNode PCurrent=(PNode)malloc(sizeof(Node));
PCurrent=P->top;
while(NULL!=PCurrent)
{
size++;
PCurrent=PCurrent->next;
}
return size;*/
return P->size;
}
/***返回栈顶数据项***/
Item Get_Item_Stack(PStack P)
{
if(0!=P->top->data && Is_Empty(P)==0)
return P->top->data;
}
/***数据项出栈***/
Item Pop_Stack(PStack P)
{
Item data;
PNode temp=P->top;
if(NULL==temp)
{
printf("The stack is empty.\n");
exit(1);
}
data=temp->data;
P->top=temp->next;
P->size--;
free(temp);
return data;
}
/***清空链栈***/
void Clear_Stack(PStack P)
{
if(Is_Empty(P))
printf("The stack had empty.\n");
PNode PCurrent=P->top;
int i=P->size;
while(i--)
{
P->top=PCurrent->next;
P->size--;
free(PCurrent);
PCurrent=P->top;
}
}
/***遍历栈,并自栈顶输出数据项***/
void Traverse_Stack(PStack P)
{
PNode PCurrent = P->top;
int i = P->size;
printf("The data of stack are:");
while(i--)
{
printf("%d ",PCurrent->data);
PCurrent = PCurrent->next;
}
printf("\n");
}
int main()
{
int size=0;
int top_data,Pop_data;
PStack PS;
PS=Creat_Stack();
if(NULL!=PS)
printf("The stack is created.\n");
/***判断是否为空栈***/
if(Is_Empty(PS))
printf("The stack is empty.\n");
/***数据项入栈***/
Push_Stack(PS,2);
Push_Stack(PS,3);
Push_Stack(PS,5);
Traverse_Stack(PS);
/***计算栈的大小***/
size=Size_Stack(PS);
printf("The length of stack is: %d\n",size);
/***返回栈顶数据项***/
top_data=Get_Item_Stack(PS);
printf("The top of data is: %d\n",top_data);
/***数据项出栈***/
Pop_data=Pop_Stack(PS);
printf("The Pop of data is: %d\n",Pop_data);
Traverse_Stack(PS);
/***清空链栈***/
Clear_Stack(PS);
Traverse_Stack(PS);
return 0;
}
#include<stdlib.h>
#include"Stack.h"
/***创建空栈,并返回栈顶***/
PStack Creat_Stack()
{
PStack P=(PStack)malloc(sizeof(Stack));
if(NULL!=P)
{
P->top=NULL;
P->size=0;
}
return P;
}
/***判断是否为空栈***/
int Is_Empty(PStack P)
{
if(0==P->size && NULL==P->top)
return 1;
else
return 0;
}
/***数据项入栈***/
PStack Push_Stack(PStack P,Item val)
{
PNode PNew=(PNode)malloc(sizeof(Node));
if(NULL==PNew)
{
printf("Malloc the PNew is failed.\n");
exit(1);
}
else
{
PNew->data=val;
PNew->next=P->top;
P->top=PNew;
P->size++;
}
return P;
}
/***计算栈的大小***/
int Size_Stack(PStack P)
{
/*int size=0;
PNode PCurrent=(PNode)malloc(sizeof(Node));
PCurrent=P->top;
while(NULL!=PCurrent)
{
size++;
PCurrent=PCurrent->next;
}
return size;*/
return P->size;
}
/***返回栈顶数据项***/
Item Get_Item_Stack(PStack P)
{
if(0!=P->top->data && Is_Empty(P)==0)
return P->top->data;
}
/***数据项出栈***/
Item Pop_Stack(PStack P)
{
Item data;
PNode temp=P->top;
if(NULL==temp)
{
printf("The stack is empty.\n");
exit(1);
}
data=temp->data;
P->top=temp->next;
P->size--;
free(temp);
return data;
}
/***清空链栈***/
void Clear_Stack(PStack P)
{
if(Is_Empty(P))
printf("The stack had empty.\n");
PNode PCurrent=P->top;
int i=P->size;
while(i--)
{
P->top=PCurrent->next;
P->size--;
free(PCurrent);
PCurrent=P->top;
}
}
/***遍历栈,并自栈顶输出数据项***/
void Traverse_Stack(PStack P)
{
PNode PCurrent = P->top;
int i = P->size;
printf("The data of stack are:");
while(i--)
{
printf("%d ",PCurrent->data);
PCurrent = PCurrent->next;
}
printf("\n");
}
int main()
{
int size=0;
int top_data,Pop_data;
PStack PS;
PS=Creat_Stack();
if(NULL!=PS)
printf("The stack is created.\n");
/***判断是否为空栈***/
if(Is_Empty(PS))
printf("The stack is empty.\n");
/***数据项入栈***/
Push_Stack(PS,2);
Push_Stack(PS,3);
Push_Stack(PS,5);
Traverse_Stack(PS);
/***计算栈的大小***/
size=Size_Stack(PS);
printf("The length of stack is: %d\n",size);
/***返回栈顶数据项***/
top_data=Get_Item_Stack(PS);
printf("The top of data is: %d\n",top_data);
/***数据项出栈***/
Pop_data=Pop_Stack(PS);
printf("The Pop of data is: %d\n",Pop_data);
Traverse_Stack(PS);
/***清空链栈***/
Clear_Stack(PS);
Traverse_Stack(PS);
return 0;
}
数据结构运行环境:
采用linux机器,安装gcc和g++,能够编译执行c和c++代码
c语言编译和执行操作如下:
示例
编译:gcc Hello.c -o hello
执行:./hello
c++语言编译和执行操作如下:
示例
编译:g++ Hello.cpp -o hello
执行:./hello