(重点)链式栈

简介:
顺序栈的实现在于使用了数组这个基本数据结构,数组中的元素在内存中的存储位置是连续的,且编译器要求我们在编译期就要确定数组的大小,这样对内存的使用效率并不高,一来无法避免因数组空间用完而引起的溢出问题,二在系统将内存分配给数组后,则这些内存对于其他任务就不可用。
而对于链式栈而言,使用了链表来实现栈,链表中的元素存储在不连续的地址,由于是动态申请内存,所以我们可以以非常小的内存空间,另外当某个项目不使用时也可将内存返还给系统。

顺序栈是用顺序存储结构实现的栈,即利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时由于栈的操作的特殊性,还必须附设一个位置指针top(栈顶指针)来动态地指示栈顶元素在顺序栈中的位置。
图3.2给出了顺序栈的进栈和出栈过程。

链栈即采用链表作为存储结构实现的栈。为便于操作,我们采用带头结点的单链表实现栈。由于栈的插入和删除操作仅限制在表头位置进行,所以链表的表头指针就作为栈顶指针,如图3.4所示。

 

 
 

在图3.4中,top为栈顶指针,始终指向当前栈顶元素前面的头结点。若top->next=NULL,则代表栈空。采用链栈不必预先估计栈的最大容量,只要系统有可用空间,链栈就不会出现溢出。采用链栈时,栈的各种基本操作的实现与单链表的操作类似。对于链栈,在使用完毕时,应该释放其空间。

链栈的结构可用C语言定义如下:

typedef struct node

{

StackElementType  data;

              struct node       *next;

}LinkStackNode;

typedef  LinkStackNode  *LinkStack;

 

顺序栈是数组实现。链式栈是链表实现。 顺序栈内存空间是连续的。 链式栈内存空间是不连续的.

头文件:stack.h

复制代码
 1 //stack.h
 2 
 3 //定义函数结果状态代码  
 4 #define TRUE        1  
 5 #define FALSE       0  
 6 #define OK          1  
 7 #define ERROR       0  
 8 #define OVERFLOW    -1  
 9 #define UNDERFLOW   -2  
10 
11 //定义函数返回值类型  
12 typedef int  Status;  
13 //定义链式栈的数据元素的类型  
14 typedef int  ElemType;
15   
16 //定义链式栈的存储结构  
17 struct LNode{
18  ElemType data;  //数据域
19  struct LNode *next;    //指针域
20 };
21 
22 struct LStack{  
23     struct LNode    *top;       //栈顶指针   
24 };
25 
26 //声明链式栈的基本操作  
27 Status  InitStack(LStack &s);         //构造一个空栈
28 Status  DestroyStack(LStack &s);      //销毁一个栈
29 Status  StackEmpty(LStack s);         //判断是否为空栈
30 Status  StackLength(LStack s);        //返回栈的长度
31 Status  Push(LStack &s,ElemType e);   //元素入栈
32 Status  Pop(LStack &s,ElemType &e);   //元素出栈
33 Status  GetTop(LStack s,ElemType &e); //返回栈顶元素
34 Status  StackTraverse(LStack s);      //遍历栈
复制代码

 

实现函数:stack.cpp

复制代码
  1 //stack.cpp
  2 
  3 #include"stack.h"
  4 #include<iostream>
  5 using namespace std;
  6 
  7 Status  InitStack(LStack &s)
  8 //操作结果:构造一个空栈S
  9 {
 10    struct LNode *p;
 11    p=(LNode *)malloc(sizeof(LNode));
 12    if(!p){
 13         cout<<"严重错误:链式栈初始分配头节点失败,程序退出";  
 14         exit(ERROR); 
 15    }
 16    s.top=p;
 17    p->next=NULL;
 18    return OK; 
 19  } 
 20 
 21 Status  DestroyStack(LStack &s)  
 22  //初始条件:栈s已存在  
 23  //操作结果:栈s被销毁  
 24 {  
 25     struct LNode *p;
 26     p=s.top;
 27     while(p){
 28         s.top=p->next;
 29         free(p);
 30         p=s.top;
 31     }    
 32     return OK;  
 33 } 
 34 
 35 Status  StackEmpty(LStack s)
 36 //初始条件:栈s已存在  
 37 //操作结果:若栈s为空栈,则返回TRUE,否则FALSE 
 38 {
 39    if(s.top->next==NULL) return TRUE;
 40    return FALSE;
 41  }
 42 
 43 Status  StackLength(LStack s)
 44 //初始条件:栈s已存在  
 45 //操作结果:返回s的元素个数,即栈的长度
 46 {
 47    int length=0;
 48    struct LNode *p;
 49    p=s.top;
 50    while(p->next){
 51    length++;
 52    p=p->next;
 53    }
 54    return length;
 55 } 
 56 
 57 Status Push(LStack &s,ElemType e)
 58 //初始条件:栈s已存在  
 59 //操作结果:插入元素e成为新的栈顶元素
 60 
 61 {  
 62    struct LNode *p;
 63    p=(LNode *)malloc(sizeof(LNode));
 64    if(!p)exit(OVERFLOW);
 65    s.top->data=e;
 66    p->next=s.top;
 67    s.top=p;
 68    return OK;
 69 }   
 70      
 71 Status  Pop(LStack &s,ElemType &e)
 72  //初始条件:栈s已存在且非空  
 73  //操作结果:删除s的栈顶元素,并且用e返回其值 
 74 
 75 {
 76     struct LNode *p;
 77     if(!(s.top->next))exit(UNDERFLOW);
 78     p=s.top;
 79     s.top=p->next;
 80     e=s.top->data;
 81     free(p);
 82     return OK; 
 83 }
 84 
 85 Status  GetTop(LStack s,ElemType &e)
 86  //初始条件:栈s已存在且非空  
 87 //操作结果:用e返回s的栈顶元素 
 88 {
 89      if(!(s.top->next))exit(ERROR);
 90      s.top=s.top->next;
 91      e=s.top->data;
 92      return OK;
 93 } 
 94 
 95 Status  StackTraverse(LStack s)
 96 //从栈顶开始依次输出
 97 {
 98      struct LNode *p;
 99      if(!(s.top->next))exit(ERROR);
100      p=s.top;
101      while(p->next){
102      p=p->next;
103      cout<<p->data<<endl;
104      }
105      return OK;
106 
107 }
复制代码

 

测试函数:test.cpp

复制代码
 1 //test.cpp
 2 
 3 #include"stack.h"
 4 #include<iostream>
 5 using namespace std;
 6 
 7 int main()
 8 {
 9  int e;
10  struct LStack s;
11  InitStack(s);
12  Push(s,4);
13  GetTop(s,e);
14  cout<<e<<endl;
15  Push(s,5);
16  Push(s,6);
17  Push(s,7);
18  Push(s,8);
19  Push(s,9);
20  GetTop(s,e);
21  cout<<e<<endl;
22  cout<<StackLength(s)<<endl;
23  Pop(s,e);
24  Pop(s,e);
25  Pop(s,e);
26  Pop(s,e);
27 
28  cout<<StackEmpty(s)<<endl;
29 
30  StackTraverse(s);
31 
32  return 0;
33 }
复制代码

 

方法二:

复制代码
  1 /*******************************************************************************
  2 /* <PRE>
  3 /* 版权所有    : -
  4 /* 模块名      : 栈和队列
  5 /* 文件名      : lstack.cpp
  6 /* 功能描述    : 链栈的表示与实现 
  7 /* 作者        : <xxx>
  8 /* 版本        : 1.0
  9 /* -----------------------------------------------------------------------------
 10 /* 备注        : -
 11 /* -----------------------------------------------------------------------------
 12 /* 修改记录    :
 13 /* 日 期        版本     修改人        修改内容
 14 /* 2011/01/01   1.0      <xxx>         创建
 15 /* </PRE>
 16 *******************************************************************************/
 17 #include "stdio.h" 
 18 #include "stdlib.h"
 19 
 20 /******************************************************************************
 21 /* 数据类型和常量定义
 22 /******************************************************************************/
 23 typedef int    Status;
 24 typedef int    SElemType;
 25 
 26 #define TRUE         1
 27 #define FALSE        0
 28 #define OK           1
 29 #define ERROR        0
 30 #define OVERFLOW    -2
 31 
 32 /******************************************************************************
 33 /* 数据结构声明
 34 /******************************************************************************/
 35 typedef struct SNode {
 36     SElemType data;
 37     struct SNode *next;
 38 }SNode;
 39 
 40 typedef struct LinkStack {
 41     SNode *base;
 42     SNode *top;
 43 }LinkStack;
 44 
 45 
 46 /*******************************************************************************
 47 /* <FUNC>
 48 /* 函数名   : InitStack
 49 /* 功能     : 构造空栈
 50 /* 参数     : -
 51 /* 返回值   : -
 52 /* 备注     : -
 53 /* 作者     : <xxx>
 54 /* </FUNC>
 55 *******************************************************************************/
 56 Status InitStack(LinkStack &S) {
 57     S.top = S.base = NULL;
 58     return OK;
 59 }
 60 
 61 /*******************************************************************************
 62 /* <FUNC>
 63 /* 函数名   : Push
 64 /* 功能     : 入栈
 65 /* 参数     : -
 66 /* 返回值   : -
 67 /* 备注     : 插入元素e为新的栈顶元素
 68 /* 作者     : <xxx>
 69 /* </FUNC>
 70 *******************************************************************************/
 71 Status Push(LinkStack &S, SElemType e) {
 72     SNode *p = (SNode *)malloc(sizeof(SNode));
 73     if (!p) exit(OVERFLOW);
 74     p->data = e;
 75     p->next = S.top;
 76     S.top = p;
 77     return OK;
 78 }
 79 
 80 /*******************************************************************************
 81 /* <FUNC>
 82 /* 函数名   : Push
 83 /* 功能     : 出栈
 84 /* 参数     : -
 85 /* 返回值   : -
 86 /* 备注     : 若栈不空, 则删除S的栈顶元素, 用e返回其值, 并返回OK; 否则返回ERROR
 87 /* 作者     : <xxx>
 88 /* </FUNC>
 89 *******************************************************************************/
 90 Status Pop(LinkStack &S, SElemType &e) {
 91     if (S.top == S.base)
 92         return ERROR;
 93     SNode *p = S.top;
 94     S.top = S.top->next;
 95     e = p->data;
 96     free(p);
 97     return OK;
 98 }
 99 
100 /*******************************************************************************
101 /* <FUNC>
102 /* 函数名   : StackEmpty
103 /* 功能     : 判断栈是否为空
104 /* 参数     : -
105 /* 返回值   : -
106 /* 备注     : 若栈空则返回TRUE; 否则返回FALSE
107 /* 作者     : <xxx>
108 /* </FUNC>
109 *******************************************************************************/
110 Status StackEmpty(LinkStack S)
111 {
112     if (S.base == S.top) return TRUE;
113     else return FALSE;
114 }
115 
116 
117 /*******************************************************************************
118 /* <FUNC>
119 /* 函数名   : main
120 /* 功能     : 测试函数
121 /* 参数     : -
122 /* 返回值   : -
123 /* 备注     : -
124 /* 作者     : <xxx>
125 /* </FUNC>
126 *******************************************************************************/
127 void main()
128 {
129     LinkStack S;  SElemType e;
130     InitStack(S);
131     Push(S, 10);
132     Push(S, 20);
133     if(OK == Pop(S, e)) printf("%d\n", e);
134     if(OK == Pop(S, e)) printf("%d\n", e);
135     if(OK == Pop(S, e)) printf("%d\n", e);
136 }
复制代码
目录
相关文章
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
1025 9
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
291 59
|
6月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
123 0
栈区的非法访问导致的死循环(x64)
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。
|
11月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
514 77
|
10月前
|
算法 调度 C++
STL——栈和队列和优先队列
通过以上对栈、队列和优先队列的详细解释和示例,希望能帮助读者更好地理解和应用这些重要的数据结构。
239 11
|
10月前
|
DataX
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
11月前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
424 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
11月前
|
存储 C语言 C++
【C++数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现链栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储整数,最大
225 9
|
11月前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
240 7

热门文章

最新文章