栈的深入讲解与运用

简介: 栈的深入讲解与运用

一,栈的定义与操作基础

       栈是一种尽可以在一端进行插入和删除运算的限定线性表,栈中能被插入的一端为栈顶,最底部的一端为栈底,如图:

        由图可知,栈其实就像一个管道,只能从后往前依次插入或取出,不能从其它位置进行操作,是一种具有限制操作的线性表。

       栈既然属于线性表,那么它也有属于自已的基础操作,而栈的基础操作如下:

    (1)向栈顶插入数据

    (2)从栈顶取出数据

    (3)删除栈顶元素

    (4)判断栈是否为空

       只要是属于栈结构,无论是什么栈类型,基本都需要这几种操作,而复杂的问题基本是以这几种基础算法为操作进行的。下面我会详细的跟大家介绍。

二,栈的顺序栈

       顺序栈跟顺序表的结构差不多,是以数组为形式构成的一种结构,也是栈的基本结构之一,

顺序栈的基本形式如下:

typedef int Datatype;

struct stack

{

   Datatype a[100];

   int top;//top作为栈顶指针,用来指向数据的位置

};

       其中,用结构体中的a数组来存放数据,整个框架就是一个顺序栈,由此课看出,顺序栈与顺序表几乎一样,只是顺序栈被限制了数据元素的位置。

       下面是顺序栈的基本操作算法,在以后的运用栈中可根据以下作为基础。

#include<stdio.h>

#include<stdlib.h>

#define max 100

typedef int type;

typedef struct set//顺序栈的结构式

{

   type a[max];

   int top;//栈顶指针

}stack;

stack* add(stack* s, type n)//顺序栈的入栈算法

{

   if (s->top == max)

   {

       puts("栈已满,不能添加");

       return 0;

   }

   else

       s->a[s->top++] = n;

   return s;

}

stack* spill(stack* s, type m)//顺序栈的溢出算法

{

   if (s->top == 0)

   {

       puts("顺序栈内无任何数据元素");

       return 0;

   }

   else

       s->top--;

   return s;

}

type take(stack* s)//取栈顶元素算法

{

   type n;

   if (s->top == 0)

   {

       puts("顺序栈无任何元素");

       return 0;

   }

   else

       n = s->a[s->top - 1];

   return n;

}

void determine(stack* s)//判断算法

{

   if (s->top == 0)

       puts("顺序栈为空栈");

   else

       puts("顺序栈不为空栈");

}

int main()

{

   stack* s;

   s = (stack*)malloc(sizeof(stack));//建立顺序栈s

   if (!s)

       puts("空间不足,建立失败");

   else

       s->top = 0;

   //入栈操作

   type n;

   scanf("%d", &n);

   s = add(s, n);

   //出栈操作

   type m;

   scanf("%d", &m);

   s = spill(s, m);

   //取栈顶元素操作

   type x;

   x = take(s);

   //判别是否空栈

   determine(s);

   return 0;

}

三,栈的链式栈

       栈的链式栈与链式表的关系跟栈的顺序栈与顺序表的关系相同,除了在元素位置上被限制外没有其它的异处,在这里就不做过多说明,而链式栈的基本结构如下:

typedef int Datatype;

struct stack

{

   Datatype a;

   struct stack* next;

};

       而链式栈的基本操作流程如下:

stack* push(stack* s, type x)//入栈算法

{

   stack* p;

   p = (stack*)malloc(sizeof(stack));

   p->data = x;

   p->next = s;

   s = p;

   return s;

}

stack* deletdata(stack* s)//出栈算法

{

   stack* p;

   p = (stack*)malloc(sizeof(stack));

   p = s;

   s = s->next;

   free(p);

   return s;

}

Datatype Gettopdata(stack* pa)//得到栈顶元素算法

{

   Datatype a;

   a = pa->data;

  //不能pa = pa->next进行查找;因为只是在子程序内部进行,出了子程序就销毁

   return a;

}

       要说明的是,链式栈不必设置头结点,因为链式栈在算法中操作是用地址进行的,在链式栈中很容易造成程序上的链接错误,并且栈顶的操作还比较频繁。

       ·由以上可知,链式栈的操作虽然比顺序栈稍微复杂一点,但链式栈中的元素变化数量较大,并链式栈一般也不会出现栈满情况,因此,在栈的结构中,链式栈是首选的存储方式。

四,栈的综合运用

       讲解完栈的基础之后,接下来我们要考虑的这东西学完之后怎么用,在什么情况下运用。从以上对栈的认识上看,不难发现,凡问题求解具有后进先出的天然特性,其求解过程中必然需要利用栈。下面我来跟大家讲解几道例题,让大家学会如何更好的利用栈。

(1)链式栈的十进制的转换问题

#include<stdio.h>

#include<stdlib.h>

typedef struct set//建立链式栈

{

   int data;

   struct set* next;

}stack;

stack* reverse(stack* head)//逆序算法,将其全部逆序排列

{

   stack* p, * pa, * pp;

   pa = head;

   p = head->next;

   head->next = 0;

   while (p->next)

   {

       pp = p->next;

       p->next = pa;

       pa = p;

       p = pp;

   }

   return pa;

}

stack* change(int n, int m)

{

   int x = 0;

   stack* head = 0, * p = 0, * pa = 0;

   head = p = (stack*)malloc(sizeof(stack));

   do

   {

       x = n % m;

       p->data = x;

       pa = (stack*)malloc(sizeof(stack));

       p->next = pa;

       p = pa;

       n /= m;

   } while (n);

   p->next = 0;

   return reverse(head);

}

int main()

{

   int n, m;

   stack* p;

   scanf("%d%d", &n, &m);//n代表数,m代表转换的进制

   for (p = change(n, m);; p = p->next)

   {

       if (!p->next)

       {

           printf("%d", p->data);

           break;

       }

       else

           printf("%d->", p->data);

   }

   return 0;

}

(2)括号匹配问题

#include<stdio.h>

#include<stdlib.h>

typedef char type;

typedef struct note stack;

struct note

{

   type data;

   struct note* next;

};

stack* push(stack* s, type x)//入栈算法

{

   stack* p;

   p = (stack*)malloc(sizeof(stack));

   p->data = x;

   p->next = s;

   s = p;

   return s;

}

stack* deletdata(stack* s)//出栈算法

{

   stack* p;

   p = (stack*)malloc(sizeof(stack));

   p = s;

   s = s->next;

   free(p);

   return s;

}

int main()

{

   stack* s;

   type a[100];

   int i = 0;

   s = (stack*)malloc(sizeof(stack));//建立链式栈

   s->data = 0;

   fgets(a, 100, stdin);

   while (a[i])//下面程序反复调用算法

   {

       switch (a[i])

       {

       case '(':

       case '[':

       case '{':

           s = push(s, a[i]);

           break;

       case ')':

           if (s->data == '(')

               s = deletdata(s);

           else

           {

               puts("匹配失败");

               return 0;

           }

           break;

       case ']':

           if (s->data == '[')

               s = deletdata(s);

           else

           {

               puts("匹配失败");

               return 0;

           }

           break;

       case '}':

           if (s->data == '{')

               s = deletdata(s);

           else

           {

               puts("匹配失败");

               return 0;

           }

           break;

       }

       i++;

   }

   puts("匹配成功");

   return 0;

}

(3)用顺序栈来实现逆置单向链表

#include<stdio.h>

#include<stdlib.h>

#define max 100

typedef int Datatype;

typedef struct note//定义单向链式表

{

   Datatype a;

   struct note* next;

}link;

typedef struct set//定义顺序栈

{

   Datatype a[max];

   int Topdata;

}stack;

link* creat()//创建单链表

{

   link* p, * head, * pa;

   p = (link*)malloc(sizeof(link));

   head = pa = (link*)malloc(sizeof(link));

   pa->next = p;

   fscanf(stdin, "%d", &p->a);

   while (p->a)

   {

       pa = p;

       p = (link*)malloc(sizeof(link));

       fscanf(stdin, "%d", &p->a);

       pa->next = p;

   }

   pa->next = 0;

   return head;

}

void linkprint(link* head)//输出单向链表

{

   link* p;

   for (p = head->next; p; p = p->next)

   {

       if (!p->next)

           fprintf(stdout, "%d\n", p->a);

       else

           fprintf(stdout, "%d->", p->a);

   }

}

void push(stack* pa, Datatype a)

{

   pa->Topdata++;

   pa->a[pa->Topdata - 1] = a;

}

Datatype Gettopdata(stack* pa)

{

   return pa->a[--pa->Topdata];

}

void stackprint(stack* pa)

{

   int i;

   for (i = pa->Topdata; i; i--)

   {

       if (i == 1)

           fprintf(stdout, "%d\n", pa->a[i - 1]);

       else

           fprintf(stdout, "%d->", pa->a[i - 1]);

   }

}

int main()

{

   link* p, * s;

   s = creat();

   fprintf(stdout, "单向链表的数据域: ");

   linkprint(s);

   stack* pa;

   pa = (stack*)malloc(sizeof(stack));

   pa->Topdata = 0;

   //然后用栈实现逆置,首先将数据放入顺序栈中

   for (p = s->next; p; p = p->next)

       push(pa, p->a);

   fprintf(stdout, "此时栈中的元素: ");

   stackprint(pa);//输出栈中的元素,检查是否将单链表中的数据元素放到了栈中

  //然后出栈从前到后的顺序放入链表中,即实现逆置运算

   for (p = s->next; p; p = p->next)

       p->a = Gettopdata(pa);

   fprintf(stdout, "用栈逆置后的链表: ");

   linkprint(s);

   return 0;

}

(4)用链式栈来实现逆置单向链表

#include<stdio.h>
#include<stdlib.h>
#define max 100
typedef int Datatype;
typedef struct note
//定义单向链式表

{
   Datatype a;
   struct note* next;
}link;
typedef struct set
//定义顺序栈

{
   Datatype data;
   struct set* next;
}stack;
link* creat()
//创建单链表

{
   link* p, * head, * pa;
   p = (link*)malloc(sizeof(link));
   head = pa = (link*)malloc(sizeof(link));
   pa->next = p;
   fscanf(stdin, "%d", &p->a);
   while (p->a)
   {
       pa = p;
       p = (link*)malloc(sizeof(link));
       fscanf(stdin, "%d", &p->a);
       pa->next = p;
   }
   pa->next = 0;
   return head;
}
void linkprint(link* head)
//输出单向链表

{
   link* p;
   for (p = head->next; p; p = p->next)
   {
       if (!p->next)
           fprintf(stdout, "%d\n", p->a);
       else
           fprintf(stdout, "%d->", p->a);
   }
}
stack* push(stack* pa, Datatype a)
{
   stack* p;
   p = (stack*)malloc(sizeof(stack));
   p->data = a;
   p->next = pa;
   return p;
}
void stackprint(stack* pa)
{
   stack* p;
   for (p = pa; p->next; p = p->next)
   {
       if (!p->next->next)
           printf("%d\n", p->data);
       else
           printf("%d->", p->data);
   }
}
Datatype Gettopdata(stack* pa)
{
 
 //不能pa = pa->next进行查找;因为只是在子程序内部进行,出了子程序就销毁

   return pa->data;
}
int main()
{
   link* p, * s;
   s = creat();
   fprintf(stdout, "单向链表的数据域: ");
   linkprint(s);
   stack* pa;
   pa = (stack*)malloc(sizeof(stack));
//建立链式栈

   pa->next = 0;
   for (p = s->next; p; p = p->next)
//将数据放入链式栈中

       pa = push(pa, p->a);
   fprintf(stdout, "此时栈中的元素: ");
   stackprint(pa);

   for (p = s->next; p; p = p->next)
   {
       p->a = Gettopdata(pa);
       pa = pa->next;
   }
   fprintf(stdout, "用栈逆置后的链表: ");
   linkprint(s);
   return 0;
}

       由以上栈的综合运用我们不难发现,无论是多么复杂的栈问题,基本都需要反复运用栈的基本算法,因此,无论是顺序栈还是链式栈,这些基本的运算都必须完全掌握,笔者建议学者们在下多次练习这些基础操作。

相关文章
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
166 9
|
1月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
30 1
|
19天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
42 5
|
1月前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
1月前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
1月前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
51 4
|
2月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
44 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
1月前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
27天前
|
算法
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
43 0
|
2月前
初步认识栈和队列
初步认识栈和队列
61 10