• 【C_Language】---队列和栈的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("***************静态栈空间模拟实现*******************
    ") ; 
    50         printf("请输入元素!(元素进栈)");
    51         for(i=0;i<3;i++) //压三次栈 
    52         Push_Stack(&MyStack);
    53         printf("元素出栈
    ");
    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("栈底建立成功
    "); 
    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
    ",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
    ",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("队列已满,不允许插入!
    "); 
    30         return;
    31     }
    32     else
    33     {
    34         scanf("%d",&MyQueue->queue_array[MyQueue->rear]);
    35         MyQueue->rear = (MyQueue->rear+1)%QUEUE_SIZE;
    36         printf("插入成功!
    "); 
    37     } 
    38 }
    39 
    40 void OutPutQueue(Pqueue MyQueue)
    41 {
    42     if(MyQueue->front==MyQueue->rear)
    43     {
    44         printf("队列已空,请勿继续进行删除操作!
    "); 
    45         return;
    46     }
    47     else
    48     {
    49         printf("%d
    ",MyQueue->queue_array[MyQueue->front]);
    50         MyQueue->front = (MyQueue->front+1)%QUEUE_SIZE;
    51         printf("删除成功!
    "); 
    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("构建成功!
    "); 
    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("入队成功
    "); 
    36     }
    37 }
    38 
    39 void Output(void) //出队操作
    40 {
    41     Pqueue ptemp;
    42     if(Front == Rear) //这就是队空标志,只允许弹出这个节点元素,不允许改变指针指向和释放改空间,否则队列指针将没有指向,还得重新构建
    43     { 
    44         printf("%d",Front->ele);
    45         printf("队列已经空,请禁止继续出队
    "); 
    46     }
    47     else
    48     {
    49         ptemp = Front->next; //同时这也是一个释放链式节点的操作,先让暂存指针保存,释放节点的指向, 
    50         printf("%d",Front->ele); //然后打印出释放节点的节点数值
    51         free(Front); //释放该节点
    52         Front = ptemp; //然后重新保存暂存指针,这样队首指针就向上移动一个节点。
    53         printf("出队成功
    "); 
    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 } 

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

     

     

     

     

     

     

  • 相关阅读:
    AtCoder Beginner Contest 199(Sponsored by Panasonic)
    牛客练习赛81
    Linux查看日志定位问题
    mysql慢查询诊断
    本地安装jenkins,github拉取Python代码,并执行python脚本
    Mac升级到big sur之后,根目录无法写入文件如何解决?
    mysql 查看当前事务
    MongonDb在thinkphp中常用的功能整理(模糊查询)
    PHP操作MongoDB之|增-删-改-查|
    将MySQL中数据导入到MongoDB中
  • 原文地址:https://www.cnblogs.com/szhb-5251/p/5701047.html
Copyright © 2020-2023  润新知