zoukankan      html  css  js  c++  java
  • C 数据结构之栈和队列

    栈:又叫后进先出表,简称为LIFO线性表。

    栈的基本运算有六种:

    构造空栈:initStack()、

    判断栈空:isEmpty()、

    判断栈满:isFull()、

    进栈: Push()、将元素压入栈顶。

    出栈: Pop() 、 将元素从栈顶弹出。

    取栈顶元素:getTop()、不同与弹出,只是使用栈顶元素的值,该元素仍在栈顶不会改变。
    栈由其内核的不同,可以分为:顺序栈和链栈
          顺序栈的内核是:数组
          链栈的内核是:链表 


    队列

    1.1 队列定义 

    队列(Queue)也是一种运算受限的线性表,它的运算限制与栈不同,是两头都有限制,插入只能在表的一端进行(只进不出),而删除只能在表的另一端进行(只出不进),允许删除的一端称为队尾(rear),允许插入的一端称为队头 (Front)

    ,队列的操作原则是先进先出的,所以队列又称作FIFO表(First In First Out)

    队列的基本运算也有六种:

    置空队 :InitQueue(Q)

    判队空: QueueEmpty(Q)

    判队满: QueueFull(Q)

    入队 : EnQueue(Q,x)

    出队 : DeQueue(Q)

    取队头元素: QueueFront(Q),不同与出队,队头元素仍然保留。

     

    队列也有顺序存储和链式存储两种存储结构,前者称顺序队列,后者为链队。 
    顺序队列是在能估计出队列的最大长度的时候。
    若不能估计出队列的最大长度,就使用链式队列。 

     1 /*  利用地址实现对数组的存取
     2 
     3     int array[5];
     4 
     5     int * arr=array;     //该array是数组的首地址,首地址是数组中下表为:0 的元素的地址。
     6 
     7     for(int i=0;i<5;i++){
     8 
     9         scanf("%d",arr+i); //利用地址向数组里存数据
    10 
    11     }
    12 
    13     
    14 
    15     for(int i=0;i<5;i++){
    16 
    17         printf("%p
    ",arr+i); //输出数组中每个数据的地址
    18 
    19     }
    20 
    21  
    22 
    23     for(int i=0;i<5;i++){
    24 
    25         printf("%d
    ",*(arr+i)); //利用地址取出数组中的数据
    26 
    27     }
    28 
    29 */

     
    队列按照内核的不同分为两种:
                       1、用连续的内存空间来作为内核,而这种情况有两种实行方式:
                                                  ①、通过下标实现   ②、通过指针实现

                   2、用链表实现
             在实现队列的时候,队列中要有一个内存区域为空,不能存数据,这样在判断队列满和队列空的时候才能更方便。而空的位置可以是队首指向的空间,也可以是队尾指向的空间。 这种情况下:判断队列空是通过队头和队尾指向同一个内存区域,而判断队列满是通过队尾的下一个是队头的方式。
             用模的方式实现队列循环:
                             rear = ( rear + 1 ) % length ;
                             eg: rear = ( rear + 1) % 5
                             rear = 0 ........0
                             rear = 1 .........1
                               .            .
                               .            . 
                             rear = 5 ........0 
            这样就可以实现 rear 在 0 — 4 循环,就可以实现队列的循环。 

    以下 code 是通过下标实现的连续内存空间的队列:

      1 #include "queue.h"
      2 
      3 #include <stdio.h>
      4 
      5 #include <stdbool.h>
      6 
      7 #include <stdlib.h>
      8 
      9  
     10 
     11 struct Queue {  //声明队列的结构体
     12 
     13     int * arr;  //该指针指向内存中的一块连续的内存,是该连续内存的首地址
     14 
     15     int front;  //用连续内存空间的下标来作为的队头
     16 
     17     int rear;   //用连续内存空间的下标来作为队尾
     18 
     19     int length; //连续内存空间的长度
     20 
     21  
     22 
     23 };
     24 
     25     
     26 
     27 // 初始化队列
     28 
     29 bool initQueue(struct Queue * queue,int length){
     30 
     31     int * arr=(int *)malloc(sizeof(int)*length);     //在内存中划分一快连续的内存空间,空间的大小为:int * length
     32 
     33     queue->arr=arr;                                  //分别记录该内存空间的首地址,其实下标和长度。
     34 
     35     queue->front=0;
     36 
     37     queue->rear=0;
     38 
     39     queue->length=length;
     40 
     41     return  true;
     42 
     43 }
     44 
     45  
     46 
     47 // 入队
     48 
     49 bool inQueue(struct Queue * queue){
     50 
     51     if (!isFull(queue)) {    //判断队列是否已满,如果队列已满,我们就不在添加,未满则添加
     52 
     53         printf("请输入队列元素:");
     54 
     55         scanf("%d",(queue->arr + queue->rear));
     56 
     57         if(*(queue->arr + queue->rear)== 0) return false;
     58 
     59         queue->rear=(queue->rear + 1) % queue->length;   //用取模的方式来保证队列是循环队列
     60 
     61         return true;
     62 
     63     }else{
     64 
     65         return  false;
     66 
     67     }
     68 
     69 }
     70 
     71  
     72 
     73 // 出队
     74 
     75 bool outQueue(struct Queue * queue){
     76 
     77     if(!isEmpty(queue)){
     78 
     79         printf("出队元素为:%d
    ",*(queue->arr+queue->front));
     80 
     81         queue->front=(queue->front + 1) % queue->length;      //用取模的方式来保证队列是循环队列
     82 
     83         return true;
     84 
     85     }else{
     86 
     87         printf("出队失败!
    ");
     88 
     89         return  false;
     90 
     91     }
     92 
     93 }
     94 
     95  
     96 
     97 // 判断空
     98 
     99 bool isEmpty(struct Queue * queue){
    100 
    101     if(queue->front==queue->rear){                   //当队列的队头等于队尾的时候队列为空,其共同指向的内存区域为空,是没有村人和值的
    102 
    103         printf("队列为空!
    ");
    104 
    105         return true;
    106 
    107     }
    108 
    109     return  false;
    110 
    111 }
    112 
    113  
    114 
    115 // 判断满
    116 
    117 bool isFull(struct Queue * queue){
    118 
    119     if((queue->rear+1)%queue->length==queue->front){     //当队列的(rear+1)取长度的模等于front时,队列为满。
    120 
    121         printf("队列已满! 
    ");
    122 
    123         return  true;
    124 
    125     }
    126 
    127     return  false;
    128 
    129 }
    130 
    131  
    132 
    133 // 遍历队列
    134 
    135 void print(struct Queue * queue){
    136 
    137     printf("----------------
    ");
    138 
    139     int temp = queue->front;
    140 
    141     while (!isEmpty(queue)) {
    142 
    143         if(queue->arr + temp==queue->arr + queue->rear) break;
    144 
    145         printf("%d 
    ",*(queue->arr + temp));
    146 
    147         temp=(temp+1) % queue->length;
    148 
    149     }
    150 
    151     printf("----------------
    ");
    152 
    153 }
    154 
    155  
    156 
    157 // 清空队列
    158 
    159 bool clearQueue(struct Queue * queue){
    160 
    161     if(!isEmpty(queue)){
    162 
    163         queue->front=queue->rear;   //置空队列就是让队头等于队尾(因为当队头等于队尾时队列为空)
    164 
    165         printf("队列已清空!
    ");
    166 
    167         return true;
    168 
    169     }
    170 
    171     printf("队列清空失败!
    ");
    172 
    173     return false;
    174 
    175 }
    176 
    177 
    178 
    179 主函数:
    180  
    181 
    182 int main(int argc, const char * argv[]) {
    183 
    184     struct Queue  queue;
    185 
    186     initQueue(&queue, 5);
    187 
    188     
    189 
    190     while(inQueue(&queue)){}
    191 
    192     
    193 
    194     print(&queue);
    195 
    196     
    197 
    198     outQueue(&queue);
    199 
    200     print(&queue);
    201 
    202     outQueue(&queue);
    203 
    204     print(&queue);
    205 
    206     
    207 
    208     
    209 
    210     inQueue(&queue);
    211 
    212     print(&queue);
    213 
    214     
    215 
    216     outQueue(&queue);
    217 
    218     print(&queue);
    219 
    220     outQueue(&queue);
    221 
    222     print(&queue);
    223 
    224     outQueue(&queue);
    225 
    226     print(&queue);
    227 
    228     outQueue(&queue);
    229 
    230     print(&queue);
    231 
    232     
    233 
    234     inQueue(&queue);
    235 
    236     print(&queue);
    237 
    238     clearQueue(&queue);
    239 
    240     return 0;
    241 
    242 }
    243 
    244  
    View Code

     
     

    #include "queue.h"

    #include <stdio.h>

    #include <stdbool.h>

    #include <stdlib.h>

     

    struct Queue {  //声明队列的结构体

        int * arr;  //该指针指向内存中的一块连续的内存,是该连续内存的首地址

        int front;  //用连续内存空间的下标来作为的队头

        int rear;   //用连续内存空间的下标来作为队尾

        int length; //连续内存空间的长度

    };

        

    // 初始化队列

    bool initQueue(struct Queue * queue,int length){

        int * arr=(int *)malloc(sizeof(int)*length);     //在内存中划分一快连续的内存空间,空间的大小为:int * length

        queue->arr=arr;                                  //分别记录该内存空间的首地址,其实下标和长度。

        queue->front=0;

        queue->rear=0;

        queue->length=length;

        return  true;

    }

    // 入队

    bool inQueue(struct Queue * queue){

        if (!isFull(queue)) {    //判断队列是否已满,如果队列已满,我们就不在添加,未满则添加

            printf("请输入队列元素:");

            scanf("%d",(queue->arr + queue->rear));

            if(*(queue->arr + queue->rear)== 0) return false;

            queue->rear=(queue->rear + 1) % queue->length;   //用取模的方式来保证队列是循环队列

            return true;

        }else{

            return  false;

        }

    }

    // 出队

    bool outQueue(struct Queue * queue){

        if(!isEmpty(queue)){

            printf("出队元素为:%d ",*(queue->arr+queue->front));

            queue->front=(queue->front + 1) % queue->length;      //用取模的方式来保证队列是循环队列

            return true;

        }else{

            printf("出队失败! ");

            return  false;

        }

    }

    // 判断空

    bool isEmpty(struct Queue * queue){

        if(queue->front==queue->rear){                   //当队列的队头等于队尾的时候队列为空,其共同指向的内存区域为空,是没有村人和值的

            printf("队列为空! ");

            return true;

        }

        return  false;

    }

    // 判断满

    bool isFull(struct Queue * queue){

        if((queue->rear+1)%queue->length==queue->front){     //当队列的(rear+1)取长度的模等于front时,队列为满。

            printf("队列已满!  ");

            return  true;

        }

        return  false;

    }

    // 遍历队列

    void print(struct Queue * queue){

        printf("---------------- ");

        int temp = queue->front;

        while (!isEmpty(queue)) {

            if(queue->arr + temp==queue->arr + queue->rear) break;

            printf("%d ",*(queue->arr + temp));

            temp=(temp+1) % queue->length;

        }

        printf("---------------- ");

    }

    // 清空队列

    bool clearQueue(struct Queue * queue){

        if(!isEmpty(queue)){

            queue->front=queue->rear;   //置空队列就是让队头等于队尾(因为当队头等于队尾时队列为空)

            printf("队列已清空! ");

            return true;

        }

        printf("队列清空失败! ");

        return false;

    }



    主函数:
     

    int main(int argc, const char * argv[]) {

        struct Queue  queue;

        initQueue(&queue, 5);

        

        while(inQueue(&queue)){}

        

        print(&queue);

        

        outQueue(&queue);

        print(&queue);

        outQueue(&queue);

        print(&queue);

        

        

        inQueue(&queue);

        print(&queue);

        

        outQueue(&queue);

        print(&queue);

        outQueue(&queue);

        print(&queue);

        outQueue(&queue);

        print(&queue);

        outQueue(&queue);

        print(&queue);

        

        inQueue(&queue);

        print(&queue);

        clearQueue(&queue);

        return 0;

    }

     

    以下 code 是通过地址实现的连续内存空间的队列:  
     

    #include "queue.h"

    #include <stdio.h>

    #include <stdbool.h>

    #include <stdlib.h>

     

    struct Queue{

          int * pBase;    连续内存区域的首地址

          int * pFront;   队头

          int * pRear;    队尾

          int length;     连续内存空间的长度

    };

    //初始化队列

    void initQueue(struct Queue * q,int length){

        q->pBase=(int * )malloc(sizeof(int)*length);  //获得一块连续的内存,其大小为:int 的 length 倍 ,并将该快内存区域的指针强转为 int 指针类型。

        q->pFront=q->pBase;   //将队头赋值为连续内存区域的首地址。

        q->pRear=q->pBase;    //将队尾赋值为连续内存区域的首地址。

        q->length=length;

    }

    //入队

    bool inQueue(struct Queue * q){

        if (!isFull(q)) {                                     //入队之前先判断队列是否已满

            printf("请输入队列元素:");

            scanf("%d",q->pRear);                             //如果未满,则将元素放入队尾指针指向的内存空间

            if(q->pRear-q->pBase==q->length-1){               //如果队尾减去连续内存空间的首地址等于连续内存空间的长度减1,则说明队尾已经到了连续内存空间的最后,则需要将队尾赋值为连续内存空间的首地址

                q->pRear=q->pBase;

            }else{

                q->pRear=q->pRear+1;                          //如果队尾没有到连续内存空间的最后,则直接将队尾赋值为队尾的下一个内存空间。

            }

            return true;

        }

        return false;

    }

    //出队

    void outQueue(struct Queue * q){

        if(!isEmpty(q)){                                      //出队时要先判断队列是否为空,如果队列为空,这不能进行出队操作,不为空的时候才能进行出队操作

            printf("出队的元素为:%d ",*q->pFront);

            if(q->pFront-q->pBase==q->length-1){              //当输出队列的一个元素之后要判断该输出的元素是否为连续内存空间的最后一个空间的元素,

                q->pFront=q->pBase;                           //如果是最后的一个元素,则需要将队尾赋值为连续内存空间的首地址

            }else{

                q->pFront=q->pFront+1;                         //如果队尾不是连续内存空间的最后一个,则直接将队尾向后移动一个

            }

        }

    }

    //判断空

    bool isEmpty(struct Queue * q){                           //当队头等于队尾的时候,队列为空。

        if(q->pFront==q->pRear) {

            printf("队列已空! ");

            return true;

        }

        return false;

    }

    //判断满

    bool isFull(struct Queue * q){                            //当队尾加 1 等于队头,或队尾减去队头等于连续内存空间的长度减去 1 的时候队列为满。

        if(q->pRear+1==q->pFront || q->pRear-q->pFront==q->length-1){

            printf("队列已满! ");

            return true;

        }

        return false;

    }

    //遍历

    void print(struct Queue * q){

        printf("------------ ");

        int * temp=q->pFront;                                  //遍历的时候一定要先将队头先赋值给一个中间变量,否则会改变队列的队头指针,从而影响后续的操作。

        while(!isEmpty(q)){

            if(temp==q->pRear) break;

            printf("%d ",*temp);

            

            

            if(temp - q->pBase==q->length-1){

                temp=q->pBase;

            }else{

                temp=temp+1;

            }

        }

        printf("------------ ");

    }

    //清空

    bool clearQueue(struct Queue * q){                        //清空队列,就直接将队头等于队尾就可以了

        if(!isEmpty(q)){

            q->pFront=q->pRear;

            printf("队列已经清空! ");

            return true;

        }

        return true;

    }


    主函数:

    int main(int argc, const char * argv[]) {

        

        struct Queue  queue;

        

        initQueue(&queue, 5);

        

        while(inQueue(& queue)){}

        print(&queue);

        

        inQueue(&queue);

        

        outQueue(&queue);

        outQueue(&queue);

        

        print(&queue);

        

        inQueue(&queue);

        

        print(&queue);

        isFull(&queue);

        

        clearQueue(&queue);

        

        print(&queue);

        

        while(inQueue(& queue)){}

        print(&queue);

        return 0;

    }



    以下 code 是通过链表实现的队列:  

    #include "queue.h"

    #include <stdlib.h>

    struct Data {

        int i;

        struct Data * next;

    };

    struct Queue {

        struct Data * qhead;

        struct Data * qend;

        int length;

        int count;

    };

    struct Data * newData(){

        struct Data * data=(struct Data *)malloc(sizeof(struct Data));

        printf("请输入队列元素:");

        scanf("%d",&data->i);

        data->next=NULL;

        return data;

    }

    struct Queue * initQueue(int length){

        struct Queue * queue=(struct Queue * )malloc(sizeof(struct Queue));

        queue->qhead=NULL;

        queue->qend=NULL;

        queue->length=length;

        queue->count=0;

        return queue;

    }

    int add(struct Queue * queue,struct Data * data){

        if(!isFull(queue)){

            if(queue->count==queue->length-1){

                queue->qend->next=data;

                data->next=queue->qhead;

                queue->qend=data;

                queue->count=(queue->count)+1;

                return 0;

            }else{

                if(queue->qhead==NULL && queue->qend==NULL){

                    queue->qhead=data;

                    queue->qend=data;

                }else{

                    queue->qend->next=data;

                    queue->qend=data;

                }

                queue->count=(queue->count)+1;

                return 1;

            }

        }else{

            printf("队列已满!!! ");

            return 0;

        }

    }

    void get(struct Queue * queue){

        if(queue->qhead!=NULL) {

            printf("得到的元素是: %d ",queue->qhead->i);

            struct Data * temp=queue->qhead;

            queue->qhead=queue->qhead->next;

            queue->count=(queue->count)-1;

            free(temp);

        }

    }

    void print(struct Queue * queue){

        if(!isEmpty(queue)){

            struct Data * temp=queue->qhead;

            printf("-------------- ");

            printf("%d ",queue->qhead->i);

            do {

                queue->qhead=queue->qhead->next;

                printf("%d ",queue->qhead->i);

                

            } while ((queue->qend->i) != (queue->qhead->i));

            printf("-------------- ");

            queue->qhead=temp;

        }else{

            printf("队列为空!!! ");

        }

    }

    int isEmpty(struct Queue * queue){

        if(queue->qhead==queue->qend){

            return 1;

        }else{

            return 0;

        }

    }

    void clearQueue(struct Queue * queue){

        while (queue->qhead!=NULL) {

            if(queue->qhead->i==queue->qend->i){

                free(queue->qhead);

                queue->qhead=NULL;//保留着的不指向任何值的指针,不一定是指向NULL,而只有将其赋值为NULL时才能指向NULL

                queue->qend=NULL;

                continue;

            }

            struct Data * temp=queue->qhead;

            queue->qhead=temp->next;

            free(temp);

        }

        

        

        

        //    while (queue->qhead!=queue->qend) {

        //            printf("queue->count = %d ",queue->count);

        //        struct Data * temp=queue->qhead;

        //        queue->qhead=temp->next;

        //        free(temp);

        //    }

        //    struct Data * temp=queue->qhead;

        //    queue->qhead=temp->next;

        //    free(temp);

        //

        //

        //    queue->qhead = NULL;

        //    queue->qend = NULL;

    }

    int isFull(struct Queue * queue){

        

        if(queue->qend==NULL)  return 0;

        if(queue->qend->next==NULL) return 0;

        if(queue->qend->next->i==queue->qhead->i){

            return 1;

        }else{

            return 0;

        }

    }

    int QueueFront(struct Queue * queue){

        return queue->qhead->i;

    }

     
    主函数:

    int main(int argc, const char * argv[]) {

        struct Queue * queue = initQueue(5);

        

        

        if(isEmpty(queue)){

            printf("队列为空 ");

        }else{

            printf("队列不为空 ");

        }

        

        while (add(queue,newData())) {

        }

        

        printf("对首元素是:%d ",QueueFront(queue));

        

        print(queue);

        if(isFull(queue)){

            printf("队列已满 ");

        }else{

            printf("队列未满 ");

        }

        

        

        get(queue);

        printf("剩下的队列为: ");

        print(queue);

        

        get(queue);

        printf("剩下的队列为: ");

        print(queue);

        

        get(queue);

        printf("剩下的队列为: ");

        print(queue);

        get(queue);

        

        printf("对首元素是:%d ",QueueFront(queue));

        

        

        add(queue,newData());

        print(queue);

        add(queue,newData());

        print(queue);

        add(queue,newData());

        print(queue);

        add(queue,newData());

        print(queue);

        add(queue,newData());

        print(queue);

        add(queue,newData());

        print(queue);

        print(queue);

        

        

        if(isEmpty(queue)){

            printf("队列为空 ");

        }else{

            printf("队列不为空 ");

        }

        

        

        if(isFull(queue)){

            printf("队列已满 ");

        }else{

            printf("队列未满 ");

        }

        printf("对首元素是:%d ",QueueFront(queue));

        

        clearQueue(queue);

        

        

        if(isEmpty(queue)){

            printf("队列为空 ");

        }else{

            printf("队列不为空 ");

        }

        

        

        print(queue);

        return 0;

    }

  • 相关阅读:
    浅谈数据库设计技巧
    用Sqlhelper类简化数据访问示例
    SQL数据库对象命名详细文档
    C# 中SqlParameter类的使用方法小结
    DataGridView 列宽和行高自动调整的设定
    生成8位的不重复乱码
    DataGridView 冻结列或行
    用Sqlhelper类简化数据访问示例
    .Net中DataTable的保存
    LeapFTP 出现 “426 ”错误的解决方法
  • 原文地址:https://www.cnblogs.com/oural-yan/p/6900473.html
Copyright © 2011-2022 走看看