来源:互联网 发布:3tier数据 编辑:程序博客网 时间:2024/05/24 05:47

一、什么是栈
栈是限定仅在表头进行插入和删除操作的线性表。要搞清楚这个概念,首先要明白”栈“原来的意思,如此才能把握本质。”栈“者,存储货物或供旅客住宿的地方,可引申为仓库、中转站,所以引入到计算机领域里,就是指数据暂时存储的地方,所以才有进栈、出栈的说法。

二、两种常用的栈
1、顺序栈
使用连续的内存空间模拟栈的空间,一般使用数组来实现,数组索引为0即为栈底,其次再定义一个变量储存栈顶位置即可,这种栈实现起来比较简单容易操作,适合初学者。

2、链式栈
使用零散的内存空间模拟栈的空间,一般使用链表1来实现,链表尾部即为栈底,链表头部即为栈顶。

三、栈的实现

代码节选自网络

#include<stdio.h>#include<stdlib.h>#include<malloc.h>//定义结点结构体typedef struct Node{ int data;    //内容 struct Node * pNext; //指向下一结点的指针} NODE, * PNODE;   //NODE等价于struct Node, PNODE等价于struct Node *//定义栈的结构体typedef struct Stack{ PNODE pTop;    //栈顶结点 PNODE pBottom;   //栈底结点} STACK, * PSTACK;   //STACK等价于struct Stack, PSTACK等价于struct Stack *//函数声明void initStack(PSTACK pStack);    //对栈进行初始化的函数void pushStack(PSTACK pStack, int val);  //入栈的函数bool popStack(PSTACK pStack, int * pVal);//出栈的函数,*pVal用来保存出栈的元素内容void traverseStack(PSTACK pStack);   //遍历栈的函数bool isEmpty(PSTACK pStack);    //判断栈是否为空的函数void clearStack(PSTACK pStack);   //清空栈的函数int main(void){ STACK stack;   //定义一个栈变量,STACK等价于struct Stack int val;    //用来保存出栈的内容 initStack(&stack);  //调用栈的初始化函数 pushStack(&stack, 10); //调用入栈的函数 pushStack(&stack, 20); pushStack(&stack, 30); pushStack(&stack, 50); traverseStack(&stack); //调用遍历栈的函数 //调用出栈的函数 if(popStack(&stack, &val))  printf("出栈成功,出栈的元素值为:%d\n", val); else  printf(" 出栈失败!"); //调用清空栈的函数 clearStack(&stack); traverseStack(&stack); //调用遍历栈的函数 system("pause"); return 0;}void initStack(PSTACK pStack){ //创建一个空结点,让pTop指向它 pStack->pTop = (PNODE)malloc(sizeof(NODE)); if(NULL != pStack->pTop) {  //将pBottom也指向空节点  pStack->pBottom = pStack->pTop;  //清空空结点的指针域  pStack->pTop->pNext = NULL; } else      //如果内存分配失败 {  printf("内存分配失败!程序退出!\n");  exit(-1); } return;}void pushStack(PSTACK pStack, int val){ //动态创建一个新结点 PNODE pNew = (PNODE)malloc(sizeof(NODE)); //设置新结点的数据域的值 pNew->data = val; //将新结点的指针域指向之前建的空节点 pNew->pNext = pStack->pTop;   //pStack->pTop不能换成pStack->pBottom //pTop指向新的结点 pStack->pTop = pNew; return;}bool popStack(PSTACK pStack, int * pVal){ if(isEmpty(pStack)) {  return false; } else {  //先保存栈顶元素的地址,然后将pTop指向下一元素,最后释放之前栈顶元素的内存  PNODE rNode = pStack->pTop;  *pVal = rNode->data;  pStack->pTop = rNode->pNext;  free(rNode);  rNode = NULL;  return true; }}void traverseStack(PSTACK pStack){ //将栈顶赋给一个临时结点,因为在遍历栈的时候不能销毁栈 PNODE pNode = pStack->pTop; //循环遍历栈,直到栈底 while(pStack->pBottom != pNode ) {  printf("%d  ", pNode->data);  pNode = pNode->pNext; } printf("\n"); return;}bool isEmpty(PSTACK pStack){ if(pStack->pTop == pStack->pBottom)  return true; else  return false;}void clearStack(PSTACK pStack){ //栈为空,则退出该函数 if(isEmpty(pStack)) {  return; } else {   //两个结点指针变量用来释放栈中元素的内存  PNODE p = pStack->pTop;  PNODE q = NULL;  //循环释放内存  while(p != pStack->pBottom)  {   q = p->pNext;   free(p);   p = q;  }  //将栈顶和栈底指向同一个指针域为空的结点  pStack->pTop = pStack->pBottom;  return; }}

四、栈的存储
1、栈的顺序存储结构
  栈的顺序存储结构需要使用一个数组和一个整型变量来实现。利用数组来顺序存储栈中的所有元素,利用整型变量来存储栈顶元素的下标位置,可这个变量称为栈顶指针。

const int MaxSize = 50;struct Stack{    ElemType stack[MaxSize];    int top;};

若要对存储栈的数组空间采用动态分配,则可定义如下:

struct Stack{    ElemType *stack;    int top;    int MaxSize;};

 top的值为-1表示栈空。

2、栈的链式存储结构
  栈的链式存储结构是通过由结点构成的单链表实现的,此时表头指针被称为栈顶指针,由栈顶指针指向的表头结点被称为栈顶结点,整个单链表被称为链栈。对链栈的插入和删除操作是在单链表的表头进行的。
当向一个链栈插入元素时,是把该元素插入到栈顶,即,使该元素结点的指针域指向原来的栈顶结点,而栈顶指针则修改为指向该元素结点,使该结点成为新的栈顶结点。

五、两栈的空间共享
当程序中同时使用两个栈时,可以将两个栈的栈底设在向量空间的两端,让两个栈各自向中间延伸。
当一个栈的元素较多,超过向量空间的一半时,只要另一个栈的元素不多,那么前者就可以占用后者的部分存储空间。只有当整个向量空间被两个栈占满(即两个栈顶相遇)时,才会发生上溢,因此两个栈共享一个长度为m的向量空间

六、栈的抽象数据类型

ADT 栈(stack)      Data          同线性表。元素具有相同的类型,相邻元素具有前驱和后堆关系。      Operation          InitStack ( *S ):初始化操作.建立一个空栈S。          DestroyStack ( *S ):若栈存在,則销毁它。          ClearStack (*S):将栈清空。          StackEmpty ( S ):若栈为空,返回true,否則返回 false。          GetTop (S,*e):若栈存在且非空,用e返回S的栈顶元素。          Push (*S,e):若栈S存在,插入新元素e到栈S中并成为栈頂元素。          Pop (*S,*e):删除栈S中栈顶元素,并用e返回其值。          StackLength (S):返回回栈S的元素个数。      endADT  

七、栈的应用
裴波那契数列的计算
四则运算表达式
后缀表达式的定义
递归
中缀转后缀

原创粉丝点击