• C实现栈和队列


    C实现栈和队列

    这两天再学习了数据结构的栈和队列,思想很简单,可能是学习PHP那会没有直接使用栈和队列,写的太少,所以用具体代码实现的时候出现了各种错误,感觉还是C语言功底不行。栈和队列不论在面试中还是笔试中都很重要,下面就介绍一下这两天栈和队列的学习经验

    一:栈的学习

    基础东西:栈是在表尾进行插入和删除的线性表,由此可知表尾是栈顶,表头为栈底,没有任何元素的栈是空栈。根据栈的结构可以知道:栈修改是按后进先出的原则进行的(LIFO),基本操作有插入、删除、初始化、取栈顶元素,判断是否是空栈等等。

    栈的表示和实现:和上一节介绍过的线性表相似栈有两种表示方法(顺序表示和链式表示)因为和线性表类似(特殊的线性表)我只介绍顺序栈的就可以了。

    顺序栈:利用一组连续的地址来依次存储栈的各个元素(从栈底到栈顶),用top指针指示栈顶元素,base指针指示栈底元素,所以top=base可以作为空栈的判断。插入一个元素top++,出栈一个元素top--,所以非空栈的指针始终在栈顶元素的下一个位置

    顺序栈的结构体表示:

    1 //栈的顺序存储表示
    2 typedef struct{
    3     SElemType *base;//在栈构造之前和销毁后值是NULL
    4     SElemType *top;
    5     int stacksize; //已分配的存储空间
    6 }SqStack;

      下面是我练习的代码,实现了栈的定义、栈的初始化、进栈操作、出栈操作、得到栈顶元素、遍历栈。需要注意的是出栈操作和得到栈顶元素的操作是有区别的,希望对大家栈的学习和回顾有所帮助。代码都是自己练习过的,可以直接运行

    复制代码
      1 /**
      2  * 栈
      3  * @author:zhaoyafei
      4  * @time:2015-6-16
      5  */
      6 #include <stdio.h>
      7 #include <stdlib.h>
      8 
      9 //预定义常量
     10 #define OK 1
     11 #define OVERFLOW -2
     12 #define ERROR 0
     13 
     14 #define STACK_INIT_SIZE 100 //存储空间的初始分配量
     15 #define STACKINCREMENT 10   //存储空间的分配增量stackincrement
     16 
     17 typedef int SElemType;
     18 
     19 //栈的顺序存储表示
     20 typedef struct{
     21     SElemType *base;//在栈构造之前和销毁后值是NULL
     22     SElemType *top;
     23     int stacksize; //已分配的存储空间
     24 }SqStack;
     25 
     26 //栈的初始化操作
     27 
     28 int InitStack(SqStack &S){
     29     S.base = (int *)malloc(STACK_INIT_SIZE * sizeof(SqStack));
     30     if(!S.base){
     31         exit(OVERFLOW);//分配空间失败
     32     }
     33     S.top = S.base;
     34     S.stacksize = STACK_INIT_SIZE;
     35     return OK;
     36 }
     37 
     38 //进栈操作
     39 int Push(SqStack &S, int e){
     40     if(S.top - S.base >= S.stacksize){//栈空间已经满
     41         S.base = (int *)realloc(S.base,(S.stacksize + STACKINCREMENT) * sizeof(SqStack));
     42         if(!S.base){
     43             exit(OVERFLOW);//分配失败
     44         }
     45         S.top = S.base + S.stacksize;
     46         S.stacksize += STACKINCREMENT;
     47     }
     48     *S.top++ = e;
     49     return OK;
     50 }
     51 
     52 //出栈
     53 int Pop(SqStack &S,int &e){
     54     if(S.top != S.base){
     55         e = * --S.top;
     56         return OK;
     57     }else{
     58         exit(OVERFLOW);
     59     }
     60 }
     61 
     62 //得到顶部元素
     63 void GetElem(SqStack S, int &e){
     64     if(S.top != S.base){
     65         e = * (S.top - 1);
     66     }else{
     67         exit(OVERFLOW);
     68     }
     69 }
     70 
     71 //打印出栈各个元素
     72 void PrintfStack(SqStack S){
     73     while(*(S.top-1) && S.top != S.base){//证明不是空栈,且有值
     74         S.top = S.top - 1;
     75         printf("%d ",*S.top);
     76     }
     77     printf("
    ");
     78 }
     79 
     80 int main(){
     81     int e,i;
     82     int TextData[6] = {9,2,8,1,7,6};
     83     SqStack Sa,Sb;
     84     InitStack(Sa);//初始化栈Sa;
     85     for(i = 0; i < 6; i++){
     86         Push(Sa,TextData[i]);
     87     }
     88     printf("**************栈基本操作*************
    ");
     89     //初始化数据
     90     printf("初始化后的Sa:");
     91     PrintfStack(Sa);
     92     
     93     //得到栈顶元素
     94     GetElem(Sa,e);
     95     printf("Sa栈顶元素是:%d
    ",e);
     96 
     97     //初始化数据
     98     printf("顶部出栈后Sa:");
     99     Pop(Sa,e);
    100     PrintfStack(Sa);    
    101 }
    复制代码

    二:队列的学习:

    队列和栈相反,是一种先进先出(FIFO)的线性表,只能在一端进行插入,一端进行删除

    基础:在队列中,进行出入的一端称作队尾,允许删除的一端称作队首。和线性表差不多可以用顺序和链式表示。

    双端队列:双端队列是限定插入和删除的操作在表的两端进行的线性表,用的不是很多。

    循环队列:百度上解释:”将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量“,其实就是把队列首尾相连,但是要有一定的要求,不是想怎么连就怎么连。

    下面给出链表的结构体:

    复制代码
     1 //单链队列
     2 typedef struct QNode{
     3     QElemType data;
     4     struct QNode *next;
     5 }QNode, *QueuePtr;
     6 
     7 typedef struct{
     8     QueuePtr front;
     9     QueuePtr rear;
    10 }LinkQueue;
    11 
    12 //循环队列
    13 typedef struct{
    14     QElemType *base;
    15     int front;
    16     int rear;
    17 }SqQueue;
    复制代码

      下面这段代码练习了队列的基本操作:队列结构体定义(比栈的稍微复杂一点)、在队尾插入新元素、删除队头元素、销毁队列、打印队列、循环队列的定义等等,这部分牵涉到好多的指针操作,如果有些困难可以在纸上划出队列的结构,列出指针的操作前后变化,就容易多了(个人感觉如果线性表学好了,这些操作根本不在话下)。需要注意循环队列操作中取余操作:(Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;

    废话不多说,下面直接给出具体实现的代码:

    复制代码
      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 //头文件
      4 #define ERROR -1
      5 #define OK 2;
      6 #define TRUE 1;
      7 #define OVERFLOW -2;
      8 
      9 //最大队列长度
     10 #define MAXQSIZE 100
     11 
     12 typedef int Status;
     13 typedef int QElemType;
     14 
     15 //单链队列
     16 typedef struct QNode{
     17     QElemType data;
     18     struct QNode *next;
     19 }QNode, *QueuePtr;
     20 
     21 typedef struct{
     22     QueuePtr front;
     23     QueuePtr rear;
     24 }LinkQueue;
     25 
     26 //循环队列
     27 typedef struct{
     28     QElemType *base;
     29     int front;
     30     int rear;
     31 }SqQueue;
     32 
     33 //********************************队列的基本操作*****************************
     34 //初始化队列
     35 Status InitQueue(LinkQueue &Q){
     36     Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));//动态分配空间
     37     if(!Q.front){
     38         exit(ERROR);//分配空间失败
     39     }
     40     Q.front->next = NULL;
     41     return OK;
     42 }
     43 
     44 //在队尾插入新元素
     45 Status EnQueue(LinkQueue &Q, int e){
     46     QueuePtr p;
     47     p = (QueuePtr)malloc(sizeof(QNode));
     48     if(!p){
     49         exit(ERROR);//分配失败
     50     }
     51     p->data = e;
     52     p->next = NULL;
     53     Q.rear->next = p;
     54     Q.rear = p;
     55     return OK;
     56 }
     57 
     58 void DestroyQueue(LinkQueue &Q){
     59     if(Q.front != Q.rear){
     60         while(Q.front){
     61             Q.rear = Q.front->next;
     62             free(Q.front);
     63             Q.front = Q.rear;
     64         }
     65     }
     66 }
     67 
     68 //删除队头元素,并用e返回
     69 Status DeQueue(LinkQueue &Q, int &e){
     70     if(Q.front != Q.rear){//先判断队列是否为空
     71         QueuePtr p;
     72         e = Q.front->next->data;
     73         if(Q.front->next == Q.rear){//队列只有一个元素
     74             p = Q.rear;
     75             Q.rear = Q.front;
     76             Q.front->next = NULL;
     77         }else{
     78             p = Q.front->next;
     79             Q.front->next = p->next;
     80             p->next = NULL;
     81         }    
     82         free(p);
     83         return OK;
     84     }
     85 }
     86 
     87 //打印队列元素
     88 void PrintQueue(LinkQueue Q){
     89     if(Q.front != Q.rear){
     90         do{
     91             Q.front = Q.front->next;
     92             printf("%d ",Q.front->data);
     93         }while(Q.front->next);
     94     }
     95     printf("
    ");
     96 }
     97 
     98 //********************************循环队列的基本操作*****************************
     99 //初始化队列
    100 Status InitQueueXh(SqQueue &Q){
    101     Q.base = (int *)malloc(MAXQSIZE * sizeof(int));//动态分配空间
    102     if(!Q.base){
    103         exit(ERROR);//分配空间失败
    104     }
    105     Q.front = Q.rear = 0;
    106     return OK;
    107 }
    108 
    109 //在队尾插入新元素
    110 Status EnQueueXh(SqQueue &Q, int e){
    111     if((Q.rear + 1) % MAXQSIZE == Q.front){
    112         exit(ERROR);//队循环列已满
    113     }
    114     Q.base[Q.rear] = e;
    115     Q.rear = (Q.rear + 1) % MAXQSIZE;
    116     return OK;
    117 }
    118 
    119 int DestroyQueueXh(SqQueue &Q){
    120     return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
    121 }
    122 
    123 //删除队头元素,并用e返回
    124 Status DeQueueXh(SqQueue &Q, int &e){
    125     if(Q.front == Q.rear){//先判断队列是否为空
    126         return false;
    127     }
    128     e = Q.base[Q.front];
    129     Q.front = (Q.front + 1) % MAXQSIZE;
    130     return OK;
    131 }
    132 
    133 //打印队列元素
    134 void PrintQueueXh(SqQueue Q){
    135     if(Q.front != Q.rear){
    136         do{
    137             printf("%d ",Q.base[Q.front]);
    138             Q.front++;
    139         }while(Q.front != Q.rear);
    140     }
    141     printf("
    ");
    142 }
    143 
    144 //主方法
    145 int main(){
    146     int e, i;
    147     int Data[6] = {3,1,7,8,9,1};
    148 
    149     printf("****************队列的基本操作**************
    ");
    150     //初始化队列
    151     LinkQueue Qa, Qb;
    152     InitQueue(Qa);
    153     //初始化Qa
    154     for(i = 0; i < 6; i++){
    155         EnQueue(Qa,Data[i]);
    156     }    
    157     //打印Qa
    158     printf("Qa的各个元素:");
    159     PrintQueue(Qa);
    160 
    161     //删除队首元素
    162     DeQueue(Qa,e);
    163     printf("删除Qa的队首元素:%d
    ",e);
    164     printf("删除首元素后的Qa: ");
    165     PrintQueue(Qa);
    166     printf("销毁后的Qa: ");
    167     DestroyQueue(Qa);
    168     PrintQueue(Qa);
    169 
    170     printf("**************循环队列的基本操作************
    ");
    171     //初始化队列
    172     SqQueue QaXh, QbXh;
    173     InitQueueXh(QaXh);
    174     //初始化Qa
    175     for(i = 0; i < 6; i++){
    176         EnQueueXh(QaXh,Data[i]);
    177     }    
    178     //打印Qa
    179     printf("QaXh的各个元素:");
    180     PrintQueueXh(QaXh);
    181 
    182     //删除队首元素
    183     DeQueueXh(QaXh,e);
    184     printf("删除QaXh的队首元素:%d
    ",e);
    185     printf("删除首元素后的QaXh: ");
    186     PrintQueueXh(QaXh);
    187     printf("得到QaXh的元素个数:%d
    ",DestroyQueueXh(QaXh));
    188 }
    复制代码
     
    分类: 数据结构
    标签: 数据结构
  • 相关阅读:
    微信小程序之遮罩功能实现
    微信小程序之获取点击软键盘搜索按钮(confirm-type="search")之后的值
    python之路——闭包函数
    python之路——装饰器函数
    Python中的单例模式的几种实现方式及优化
    08-函数
    14-定时器
    13-JS中的面向对象
    12-关于DOM操作的相关案例
    17-案例
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4591096.html
Copyright © 2020-2023  润新知