浅谈数据结构之链栈(四)

  栈的链式存储结构,我们一般简称为“链栈”。由于单链表有头指针,而栈顶指针也是必须要有的,所以我们通常把栈顶放在单链表的头部,有了栈顶在头部,单链表中比较常用的头结点就失去了意义。通常对于链栈来说,是不需要头结点的,也基本不存在栈满的情况,除非内存已经没有使用的空间了。但对于空栈来说,链表原定义是头指针指向“空”,那么链栈的“空”其实就是“top=NULL”的时候。

  链栈的进栈push和出栈pop操作都很简单,没有任何循环操作,时间复杂度均为O(1);顺序栈的时间复杂度和链栈是一样的,也为O(1)。对于空间性能,顺序栈需要事先确定一个固定的长度,可能存在内存空间浪费的问题,它的优势在于存取定位时很方便;而链栈要求每个元素都有指针域,这也增加了一些内存开销,但对于栈的长度无限制;所以如果栈的使用过程中元素变化不可预料,有时很小,有时非常大,那么最好用链栈;反之,如果元素变化在可控范围内,建议使用顺序栈会更好一些。对于链栈的操作,绝大部分与单链表类似,只是在插入与删除上特殊一些罢了,下面我们来看看链栈的操作,具体操作源代码如下所示:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3
  4 #define OK 1
  5 #define ERROR 0
  6 #define TRUE 1
  7 #define FALSE 0
  8
  9 #define MAXSIZE 100    /* 存储空间初始分配量 */
 10
 11 typedef int Status;
 12 typedef int SElemType; /* SElemType类型根据实际情况而定,这里假设为int */
 13
 14 /* 链栈结构 */
 15 typedef struct StackNode
 16 {
 17     SElemType data;
 18     struct StackNode *next;
 19 }StackNode,*LinkStackPtr;
 20
 21 typedef struct
 22 {
 23     LinkStackPtr top;
 24     int count;
 25 }LinkStack;
 26
 27 Status visit(SElemType c)
 28 {
 29     printf("%d ",c);
 30     return OK;
 31 }
 32
 33 /* 构造一个空栈S */
 34 Status InitStack(LinkStack *S)
 35 {
 36     S->top = (LinkStackPtr)malloc(sizeof(StackNode));
 37     if(!S->top)
 38         return ERROR;
 39     S->top=NULL;
 40     S->count=0;
 41
 42     return OK;
 43 }
 44
 45 /* 把S置为空栈 */
 46 Status ClearStack(LinkStack *S)
 47 {
 48     LinkStackPtr p,q;
 49     p=S->top;
 50     while(p)
 51     {
 52         q=p;
 53         p=p->next;
 54         free(q);
 55     }
 56     S->count=0;
 57
 58     return OK;
 59 }
 60
 61 /* 若栈S为空栈,则返回TRUE,否则返回FALSE */
 62 Status StackEmpty(LinkStack S)
 63 {
 64     if(S.count==0)
 65         return TRUE;
 66     else
 67         return FALSE;
 68 }
 69
 70 /* 返回S的元素个数,即栈的长度 */
 71 int StackLength(LinkStack S)
 72 {
 73     return S.count;
 74 }
 75
 76 /* 插入元素e为新的栈顶元素 */
 77 Status Push(LinkStack *S,SElemType e)
 78 {
 79     LinkStackPtr s=(LinkStackPtr)malloc(sizeof(StackNode));
 80     s->data=e;
 81     s->next=S->top;      /* 把当前的栈顶元素赋值给新结点的直接后继 */
 82     S->top=s;            /* 将新的结点s赋值给栈顶指针 */
 83     S->count++;
 84
 85     return OK;
 86 }
 87
 88 /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
 89 Status Pop(LinkStack *S,SElemType *e)
 90 {
 91     LinkStackPtr p;
 92     if(StackEmpty(*S))
 93         return ERROR;
 94     *e=S->top->data;
 95     p=S->top;               /* 将栈顶结点赋值给p,见图中③ */
 96     S->top=S->top->next;    /* 使得栈顶指针下移一位,指向后一结点,见图中④ */
 97         free(p);            /* 释放结点p */
 98     S->count--;
 99
100     return OK;
101 }
102
103 /* 从栈顶到栈底依次对栈中每个元素输出 */
104 Status StackTraverse(LinkStack S)
105 {
106     LinkStackPtr p;
107     p=S.top;
108     while(p)
109     {
110         visit(p->data);
111         p=p->next;
112     }
113     printf("\n");
114
115     return OK;
116 }
117
118 int main()
119 {
120     int j,e;
121     LinkStack s;
122
123     if(InitStack(&s)==OK)
124         for(j=1;j<=10;j++)
125             Push(&s,j);
126     printf("1.栈中元素依次为:");
127     StackTraverse(s);
128
129     Pop(&s,&e);
130     printf("2.弹出的栈顶元素 e=%d\n",e);
131     printf("3.弹出栈顶元素 e=%d 后,栈的长度为 %d\n",e,StackLength(s));
132
133     Pop(&s,&e);
134     printf("4.弹出的下一个栈顶元素 e=%d\n",e);
135     printf("5.栈中元素依次为:");
136     StackTraverse(s);
137
138     Push(&s,16);
139     printf("6.插入新栈顶元素 e=%d 后,栈的长度为 %d\n",16,StackLength(s));
140     printf("7.栈中元素依次为:");
141     StackTraverse(s);
142
143     ClearStack(&s);
144     printf("8.清空栈后,栈的长度为 %d\n",StackLength(s));
145
146     return 0;
147 }
时间: 2024-10-29 03:44:43

浅谈数据结构之链栈(四)的相关文章

浅谈数据结构系列 栈和队列

计算机程序离不开算法和数据结构,在数据结构算法应用中,栈和队列应用你比较广泛,因为两者在数据存放和读取方面效率比较高,本章节重点讲解两者的基本概念和实现. 基本概念 栈:是一种先进后出,后进先出的数据结构,本质上是线性表,只是限制仅允许在表的一段进行插入和删除工作.此端为栈顶,这是在栈中应用很关键的概念.所有数据的处理都是在栈顶进行的,进栈时,栈中元素增加,栈顶上移一位,出栈时栈顶下移一位.应用中比如:洗碗,每次洗干净的碗放在上面-进栈,取碗,从顶上取出一个-出栈:装子弹-进栈,开枪-出栈. 队

浅谈数据结构之链队列(六)

前面我们讲了队列的顺序存储结构,现在我们来看看队列的链式存储结构.队列的链式存储其实就是线性表的单链表结构,只不过它是尾进头出而已,通常我们把它简称为链队列.为了操作上的方便,我们将队头指针front指向链队列的头结点,而队尾指针rear则指向终端结点.注意:当队列为空时,指针front和rear都指向头结点. 在这里,我们再介绍一下循环队列.循环队列是为了避免数组插入与删除数据时需要移动数据而引入的,我们一般把队列的这种头尾相接的顺序存储结构称为循环队列.对于循环队列和链队列相比较来说,循环队

浅谈数据结构-二叉树

浅谈数据结构-二叉树 二叉树是树的特殊一种,具有如下特点:1.每个结点最多有两颗子树,结点的度最大为2.2.左子树和右子树是有顺序的,次序不能颠倒.3.即使某结点只有一个子树,也要区分左右子树. 一.特殊的二叉树及特点 1.斜树 所有的结点都只有左子树(左斜树),或者只有右子树(右斜树).这就是斜树,应用较少 2.满二叉树 所有的分支结点都存在左子树和右子树,并且所有的叶子结点都在同一层上,这样就是满二叉树.就是完美圆满的意思,关键在于树的平衡. 根据满二叉树的定义,得到其特点为: 叶子只能出现

安卓开发_浅谈Android动画(四)

Property动画 概念:属性动画,即通过改变对象属性的动画. 特点:属性动画真正改变了一个UI控件,包括其事件触发焦点的位置 一.重要的动画类及属性值: 1.  ValueAnimator 基本属性动画类 方法 描述 setDuration(long duration) 设置动画持续时间的方法 setEvaluator(TypeEvaluator value) 设置插值计算的类型 setInterpolator(TimeInterpolator value) 设置时间插值器的类型 addUp

浅谈数据结构-树

树是一种数据结构,其中一个元素可以有两个或者多个数据元素,具有一对多的特点,用树结构来存储文件. 树的概念 结点的度:子结点的个数.例如结点1中有3个子结点,结点1的度是3. 树的度:树的度等于所有结点度中度最高的值.结点最高的度为3,树的度为3. 叶子结点:度为0的结点,即没有子结点的结点.例如:上图中3,5,6,7,9,10. 分支结点:除了叶子结点以外的结点,即度不为0的结点.例如:上面树的分支结点为1,2,4,8. 内部结点:除了根结点以及叶子结点或在分支结点的基础之上在去掉根结点.例如

浅谈数据结构之顺序栈(三)

栈:是限定仅在表尾进行插入与删除操作的线性表.我们把允许插入与删除的一端称为栈顶,另一端称为栈底,不含任何数据元素的称为空栈.栈的插入操作,叫作进栈,也叫压栈.入栈,类似于子弹入弹夹:栈的删除操作,叫作出栈,也叫弹栈,如同弹夹中的子弹出夹.注意:栈的定义中的"表尾"指的是"栈顶",而不是"栈底". 首先,栈是一个线性表,也就是说:栈具有线性结构,即前驱后继关系:只不过它是一个特殊的线性表而已,它的特殊之处在于限制了这个线性表的插入与删除位置,它始

浅谈数据结构之线性表顺序存储(一)

 首先,数据结构是由某一数据元素集合及该集合中所有数据元素之间的关系组成.具体来说,数据结构应当包含三方面的内容:(1).数据的逻辑结构:(2).数据的存储结构:(3).对数据所施加的操作.而数据的存储结构形式有两种:顺序存储与链式存储.在这里,先谈一谈线性表的顺序存储. 线性表:零个或多个数据元素的有限序列.第一,它是一个序列,也就是说,元素之间是有顺序的:第二,它是有限的,即元素个数是有限的.而线性表的顺序存储结构,说白了,就是在内存中找块地,通过占位的形式把一定的内存空间给占了,然后把相同

浅谈堆和栈的区别

笔者作为一个小白,对于堆和栈的概念,总是感觉很朦胧,他们认识我,而我只是偶尔见过,并没有深交 然而在计算机领域,堆栈是一个不容忽视的概念,堆栈是 两种数据结构.堆栈都是一种数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除.在单片机应用中,堆栈是个特殊的存储 区,主要功能是暂时存放数据和地址,通常用来保护断点和现场.要点:堆,队列优先,先进先出(FIFO—first in first out).栈,先进后出(FILO—First-In/Last-Out). 一般情况

浅谈数据结构-关键路径

上一章节讲解了拓扑排序问题,拓扑排序是解决一个工程能否顺序解决的问题,本质是一个广度层次遍历的过程,通过记录顶点入度问题,进行逐步输出的工作.在实际生活中,往往是求解工程完成需要最短时间问题.比如生活中生产一辆汽车,需要生产各种各样的零件,最终组装成车.例如生产轮子0.5天,发动机3天,底盘2天,其他部件2天,集中全部零件0.5天,组装需要2天.请问组装一辆汽车,最短需要多长时间.根据前面描述,我们构造这样的AOV网络图,一看便知. 通过网络中,我们很清晰的知道,关键路径是5.5,如果发动机提高