【三支火把】---队列和栈的C程序实现

这几天总结了C语言的队列,栈的实现方法,在此总结一下:
一、栈
首先从栈开始,诚然,相信学习过数据结构的你,肯定应该知道栈是什么东西了,如果不知道也没事每一句话我就可以帮你总结--数据
只在栈顶进行插入和删除操作,数据进出栈符合先进后出或者后进先出的原则。来贴个图片,你就知道了。

  再也没有比上述图片更能贴切的描述栈了,数据结构中的栈和程序运行压栈的栈还略有区别,在此先不说那么多,继续回归正题。栈的应用很多,你最可能会用到的一个就是10进制转换2进制数了,具体怎么应用,请亲爱的你动手试试哦!
接下来我就介绍栈的几种实现方法:
1.固定栈
  固定栈是最简单的一种了,要点就2个,一是注意栈满,二是注意要符合先进后出的原则。在这两点的基础上,就可以自己动手写一个栈空间实现
程序,这里我就介绍那么多了,因为这个实在是太简单了,代码中我也都作了详细地说明。

 1 # include "stdio.h"
 2 # include "stdlib.h"
 3
 4 # define MAX_STACK_SIZE 100 //定义栈空间的最大存储内存
 5 # define ERROR 1 //错误标志
 6 # define OK 0
 7
 8 typedef struct sqstack{ //封装一个结构体,包括定义的栈存储数组,栈顶和栈底标志
 9     int stack_array[MAX_STACK_SIZE];
10     int top;
11     int bottom;
12 }SqStack;
13
14 SqStack SqStack_Init(void) //初始化一个栈内存
15 {
16     static SqStack S;
17     S.top = S.bottom = 0;
18     return S;
19 }
20
21 int Push_Stack(SqStack *S) //压栈操作
22 {
23     int ele;
24     if(S->top == MAX_STACK_SIZE-1)
25     {
26         return ERROR;
27     }
28     scanf("%d",&ele);
29     S->stack_array[S->top] = ele;
30     S->top+=1;
31     return OK;
32 }
33
34 int Pop_Stack(SqStack *S) //出栈操作
35 {
36     if(S->top != 0)
37     S->top--;
38     printf("%d ",S->stack_array[S->top]);
39 }
40
41 int main(void)
42 {
43     int ele;
44     int i = 0;
45     SqStack MyStack = SqStack_Init();
46     while(1)
47     {
48         system("cls");
49         printf("***************静态栈空间模拟实现*******************\n") ;
50         printf("请输入元素!(元素进栈)");
51         for(i=0;i<3;i++) //压三次栈
52         Push_Stack(&MyStack);
53         printf("元素出栈\n");
54         for(i=0;i<3;i++) //出三次栈
55         Pop_Stack(&MyStack);
56         system("pause")    ;
57     }
58 return 0;
59        

2.动态链栈
这是完全采用链表的形式实现一个栈空间,稍微有点麻烦,你可以选择该栈没有上限,只要你一直输就一直开辟栈空间,
并且进行数据存储,不过这显然是不符合实际的,所以我加了个stack_size变量,为该栈设置了上限,具体的代码如下:

 1 # include"stdio.h"
 2 # include "stdlib.h"
 3
 4 # define Stack_Size 5
 5
 6 typedef struct stack{
 7     int ele;
 8     int stack_size;
 9     struct stack *next;
10 }Stack,* Pstack;
11
12 //动态链栈的实现,每个节点可以存储一个栈点元素, 因此首先需要一个数据区,然后就是一个指针区,首先是一个链表,其次才是一个栈
13 //且应该定义一个top和bottom指针,来指向栈底,和栈顶,这样才能辅助来进行完成链栈的实现。
14
15 Pstack Top;
16 Pstack Bottom;
17
18 void Creat_StackNode(void)    //创建一个栈底。并且定义这个栈底不允许释放。
19 {
20     Top = (Pstack)malloc(sizeof(Stack));
21     Bottom = Top;
22     scanf("%d",&Top->ele);   //写入栈底元素
23     Top->stack_size=0;
24     Top->next = NULL;
25     printf("栈底建立成功\n");
26 }
27
28 void PushStack(void)
29 {
30     Pstack pnew = (Pstack)malloc(sizeof(Stack));
31     pnew->next = Top;   //新建一个节点,指针指向前一个节点,其实这就是在连接一个链表,然后再让Top指向新建的节点。
32     scanf("%d",&pnew->ele);
33     pnew->stack_size=Top->stack_size + 1;
34     Top = pnew;
35 }
36
37 void PopStack(void)
38 {
39     Pstack ptemp = Top->next;      //这个其实跟链表的删除一样,因为你要释放掉这个节点,所以必须提前保存该节点的下一个指向,然后才能释放带该节点
40     printf("%d\n",Top->ele);      //将节点元素打印出来。
41     free(Top);                    //释放节点空间,也就是出栈,
42     Top = ptemp;                  //再将top指针指向新的栈顶 。
43 }
44
45 int main(void)
46 {
47     int sel;
48     int i = 0;
49     printf("创建链栈的头节点!");
50     Creat_StackNode();   //这个是链栈的最底部空间,不允许释放。
51     while(1)
52     {
53         printf("请选择是压栈还是出栈!(1.入   2.出)");
54         scanf("%d",&sel);
55         if(sel == 1)
56         {
57             if(Top->stack_size > Stack_Size-1)
58                 printf("栈内存已满了!") ;
59             else
60                 PushStack();   //将数据压入链栈
61         }
62         else if(sel == 2)
63         {
64             if(Top->stack_size == 0)
65             {
66                 printf("%d\n",Top->ele);
67                 printf("已经到达栈底,禁止继续弹出数据!    ") ;
68             }
69             else
70                 PopStack();        //将数据弹出栈
71         }
72         else
73         {
74             printf("选择输入错误,请重新输入:");
75             fflush(stdin) ;
76         }
77     }
78     return 0;
79 }

二、队列
队列和栈是近似的,也是一种存储空间吧,不过它的存储与栈刚好相反,符合先进先出的原则。队列的首尾成为队首和队尾
元素在队尾实现入队,在队首实现出队,详情请看下图--形象的比喻:水从水管的一端进入,另一端出去。。

              

队列的实现有以下三种,
1.静态队列
  类似上述静态栈的构建,不过这种的入队和出队都是向一个方向进行,在有限的空间内很容易造成空间的浪费因此用途并不广泛,再次我也就不举例了,太简单了。

2.静态循环队列
  这就是 一个很好的队列实现方式了,使用循环的方式,能够节省空间,因此,使用较为广泛,实现起来也略微有点麻烦,首先来看下循环队列的结构示意图,或许你会更理解:

              

具体的代码如下,供参考,代码中也有了十分详细的注释:

 1 # include "stdio.h"
 2
 3 # define QUEUE_SIZE 5
 4
 5 typedef struct  queue{
 6     int queue_array[QUEUE_SIZE];
 7     int front;
 8     int rear;
 9 }Queue,*Pqueue;
10 //由于队列无论是入队还是出队都是只能像一个方向增长的操作,因此单向静态队列的用途不是很大, 同场有用的是静态循环队列和动态队列。
11 //该部分介绍一个静态循环队列。
12 //静态循环队列,是一个将队头和队尾链接在一起的队列,队列空间能够循环使用,因此空间利用率高,使用比较广泛
13
14 Pqueue Init_Queue(void)      //初始化一个队列
15 {
16     static Queue queue;
17     queue.front  = 0;
18     queue.rear = 0;
19     return &queue;
20 }
21
22 /*接下来就是插入都列,和出队列了,这两个操作其实并不难,唯一的难点就在于临界状态的判断,有两个临界状态, 第一个就是队首不动,空间插入满,队尾追上了队首
23 另外一个难点就是出队列队首追上了队尾,表示队尾已经空。因此确定了两个判断条件是  (rear+1)%size ==  front.表示队列满了,如果,(front)%size == front
24 则表示队列已经空了,并且这其中,默认rear所指向向的空间一直为空*/
25 void InputQueue(Pqueue MyQueue)
26 {
27     if((MyQueue->rear+1)%QUEUE_SIZE == MyQueue->front)  //这一步骤的运算可以称得上是神来之笔
28     {
29         printf("队列已满,不允许插入!\n");
30         return;
31     }
32     else
33     {
34         scanf("%d",&MyQueue->queue_array[MyQueue->rear]);
35         MyQueue->rear = (MyQueue->rear+1)%QUEUE_SIZE;
36         printf("插入成功!\n");
37     }
38 }
39
40 void OutPutQueue(Pqueue MyQueue)
41 {
42     if(MyQueue->front==MyQueue->rear)
43     {
44         printf("队列已空,请勿继续进行删除操作!\n");
45         return;
46     }
47     else
48     {
49         printf("%d\n",MyQueue->queue_array[MyQueue->front]);
50         MyQueue->front = (MyQueue->front+1)%QUEUE_SIZE;
51         printf("删除成功!\n");
52     }
53 }
54
55 int main(void)
56 {
57     int i = 0;
58     int sel;
59     Pqueue MyQueue; MyQueue = Init_Queue();
60     while(1)
61     {
62         system("cls");
63         printf("请输入选择: 1.插入  2.删除!!!   ");
64         scanf("%d",&sel);
65
66         if(sel ==1)
67         {
68             InputQueue(MyQueue);
69             sel = 0;
70         }
71         else if(sel == 2)
72         {
73             OutPutQueue(MyQueue);
74             sel = 0;
75         }
76         system("pause");
77     }
78     return 0;
79 } 

3.链式队列

  队列的实现同样可以使用链的方式来构建完成,一旦牵扯到链,那么队列也就非常灵活了,不多啰嗦,直接看代码。

 1 # include "stdio.h"
 2 # include "stdlib.h"
 3
 4 typedef struct queue{ //封装一个队列节点的结构体
 5     int ele;
 6     struct queue *next;
 7 }Dqueue,*Pqueue;
 8
 9 Pqueue Rear; //定义队首指针和队尾指针。
10 Pqueue Front;
11
12 void Init_Queue(void) //初始化队的开始,该部分空间不允许释放,否则会丢失队列的指针。
13 {
14     Pqueue phead = (Pqueue)malloc(sizeof(Dqueue));
15     phead->next = NULL;
16     printf("请输入第一个队列元素:");
17     scanf("%d",&phead->ele);
18     Rear = phead; //开始时队首指针和队尾指针都指向该节点。
19     Front = phead;
20     printf("构建成功!\n");
21 }
22
23 void Input_Queue(void) //入队操作。
24 {
25     Pqueue pnew = (Pqueue)malloc(sizeof(Dqueue));
26     if(pnew == NULL)
27         printf("空间申请失败");
28     else
29     {
30         scanf("%d",&pnew->ele);
31         pnew->next = NULL; //入队操作时一个在头结点前插入的操作,对于新申请的堆空间必须要设置其指针域和数据域,缺一不可。
32         Rear->next = pnew; /*该步十分关键,!!!为何这么说,它指定了新创建的前一个节点的指向是新建的节点,也就确定一条由下向上的的
33         链式指向,因为这一步,Bottom指针才能一次向上访问节点,进行出队操作。*/
34         Rear = pnew;    //使队尾指针指向最末尾节点。
35         printf("入队成功\n");
36     }
37 }
38
39 void Output(void) //出队操作
40 {
41     Pqueue ptemp;
42     if(Front == Rear) //这就是队空标志,只允许弹出这个节点元素,不允许改变指针指向和释放改空间,否则队列指针将没有指向,还得重新构建
43     {
44         printf("%d",Front->ele);
45         printf("队列已经空,请禁止继续出队\n");
46     }
47     else
48     {
49         ptemp = Front->next; //同时这也是一个释放链式节点的操作,先让暂存指针保存,释放节点的指向,
50         printf("%d",Front->ele); //然后打印出释放节点的节点数值
51         free(Front); //释放该节点
52         Front = ptemp; //然后重新保存暂存指针,这样队首指针就向上移动一个节点。
53         printf("出队成功\n");
54     }
55 }
56
57 int main(void)
58 {
59     int sel;
60     Init_Queue();
61
62     while(1)
63     {
64         printf("请选择入队还是出队!1.入队 2.出队: ");
65         scanf("%d",&sel);
66         if(sel == 1)
67         {
68             Input_Queue();
69             sel = 0;
70         }
71         else if(sel == 2)
72         {
73             Output();
74             sel = 0;
75         }
76     }
77     return 0;
78 } 

  至此,栈和队列已经总结完毕,其实说难也不难,只是刚学的你,可能会稍微有点绕,希望能帮到诸位!

时间: 2024-08-04 03:10:32

【三支火把】---队列和栈的C程序实现的相关文章

C语言算法系列---1.队列和栈

写在前面:在家玩了好久,实在是不知道干嘛了,突然想找些事做,现在是时候做些什么了.这些东西不见得多高深,也可能很简单,但很基础,也无法忽视.同时,也是自己学习走过的一条路. 这是开头,就写写C的队列和栈的一些算法吧. 首先是栈的一些基础功能的实现,先贴代码: #include<stdlib.h> #include<stdio.h> typedef int SElemType; //声明栈元素类型为int typedef int Status; //函数返回值的类型为int #def

1.3 背包、队列和栈

知识点 背包:只进不出,迭代顺序不确定(即无先后顺序) 队列:先进先出 栈   :后进先出 两种基础数据结构:数组和链表 数据结构 优点 缺点 数组 通过索引可以访问任意元素 在初始化时就需要知道元素的数量 链表 使用的空间大小和元素数量成正比 需要通过引用访问任意元素 练习 1.3.1 为FixedCapacityStackOfStrings添加一个方法isFull().       /*其中注意N的含义,别和数组下标完全混淆*/ public class FixedCapacityStack

算法系列(六)数据结构之表队列和栈

在http://blog.csdn.net/robertcpp/article/details/51559333一文中,我们讲了排序,这一章来介绍一下基本数据结构:表.队列.栈和它们的简单实现 一.表ADT 1.数组实现顺序表 通过对数组操作,来直接对表进行增删查改操作,这种线性表查找某个位置的元素花费的时间为O(1),但是插入删除元素花费的时间为O(n),如果对表的操作更多的是访问操作,那么选择这种实现更为合适. 下面是一个简单实现 package com.algorithm.list; im

[LeetCode] 225. 用队列实现栈

1.单纯用list就可以实现,但并未用到队列相关知识. class MyStack: def __init__(self): """ Initialize your data structure here. """ self.stack = [] def push(self, x): """ Push element x onto stack. :type x: int :rtype: void "&quo

数据结构之队列and栈总结分析

一.前言: 数据结构中队列和栈也是常见的两个数据结构,队列和栈在实际使用场景上也是相辅相成的,下面简单总结一下,如有不对之处,多多指点交流,谢谢. 二.队列简介 队列顾名思义就是排队的意思,根据我们的实际生活不难理解,排队就是有先后顺序,先到先得,其实在程序数据结构中的队列其效果也是一样,及先进先出.    队列大概有如下一些特性: 1.操作灵活,在初始化时不需要指定其长度,其长度自动增加(默认长度为32) 注:在实际使用中,如果事先能够预估其长度,那么在初始化时指定长度,可以提高效率    

编程题目: 两个队列实现栈(Python)

感觉两个队列实现栈 比 两个栈实现队列 麻烦 1.栈为空:当两个队列都为空的时候,栈为空 2.入栈操作:当队列2为空的时候,将元素入队到队列1:当队列1位空的时候,将元素入队到队列2: 如果队列1 和 队列2 都为空的时候,那就选择入队到队列1. 3.出队操作:当两个队列都为空的时候,引发错误"栈为空": 当队列2位空的时候,如果队列1中只有一个元素,则直接将队列1中的元素出队: 如果队列1不止一个元素的时候,就将队列1的元素出队然后入队到队列2,知道队列1中只有一个元素,然后将队列1

剑指Offer面试题7(Java版):用两个栈实现队列与用两个队列实现栈

题目:用两个栈实现一个队列.队列的声明如下,请实现它的两个函数appendTail和deletedHead,分别完成在队列尾部插入节点和在队列头部删除节点的功能. 我们通过一个具体的例子来分析该队列插入和删除元素的过程.首先插入一个元素a,不妨先把它插入到stack1,此时stack1 中的元素有{a},stack2为空.再压入两个元素b和c,还是插入到stack1中,此时stack1中的元素有{a,b,c},其中c位于栈顶,而stack2仍然为空. 这个时候,我们试着删除从队列中删除一个元素.

数据结构(7)----栈与队列之栈的应用四则运算表达式求值

栈与队列之栈的应用四则运算表达式求值 栈在四则运算表达式求值的应用为逆波兰表达式(后缀表达式) 普通算式(中缀表达式):9 + (3 - 1) * 3 + 10 / 2     ---(1) 逆波兰表达式(后缀表达式):9 3 1 - 3 * + 10 2 /         ---(2) 1:逆波兰表达式的计算规则 从左到右遍历表达式的每个数字和符号,遇到数字就进栈,遇到符号,就将处于栈顶的两个数字出栈,进行运算,再把运算结果进栈,一直到最终获得结果.接下来我们以(2)式为例:

数组的队列和栈方法

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>数组的队列和栈方法</title></head><body><script>// 栈是一种LIFO(Last-In-First-Out后进先出)的数据结构,js中的push()和pop()类似栈的行为// 队列是一种FIFO(