C 数据结构之栈和队列

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\n",arr+i); //输出数组中每个数据的地址
18 
19     }
20 
21  
22 
23     for(int i=0;i<5;i++){
24 
25         printf("%d\n",*(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\n",*(queue->arr+queue->front));
 80 
 81         queue->front=(queue->front + 1) % queue->length;      //用取模的方式来保证队列是循环队列
 82 
 83         return true;
 84 
 85     }else{
 86 
 87         printf("出队失败!\n");
 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("队列为空!\n");
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("队列已满! \n");
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("----------------\n");
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 \n",*(queue->arr + temp));
146 
147         temp=(temp+1) % queue->length;
148 
149     }
150 
151     printf("----------------\n");
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("队列已清空!\n");
166 
167         return true;
168 
169     }
170 
171     printf("队列清空失败!\n");
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\n",*(queue->arr+queue->front));

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

        return true;

    }else{

        printf("出队失败!\n");

        return  false;

    }

}

 

// 判断空

bool isEmpty(struct Queue * queue){

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

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

        return true;

    }

    return  false;

}

 

// 判断满

bool isFull(struct Queue * queue){

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

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

        return  true;

    }

    return  false;

}

 

// 遍历队列

void print(struct Queue * queue){

    printf("----------------\n");

    int temp = queue->front;

    while (!isEmpty(queue)) {

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

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

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

    }

    printf("----------------\n");

}

 

// 清空队列

bool clearQueue(struct Queue * queue){

    if(!isEmpty(queue)){

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

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

        return true;

    }

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

    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\n",*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("队列已空!\n");

        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("队列已满!\n");

        return true;

    }

    return false;

}

 

//遍历

void print(struct Queue * q){

    printf("------------\n");

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

    while(!isEmpty(q)){

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

        printf("%d\n",*temp);

        

        

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

            temp=q->pBase;

        }else{

            temp=temp+1;

        }

    }

    printf("------------\n");

}

 

//清空

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

    if(!isEmpty(q)){

        q->pFront=q->pRear;

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

        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("队列已满!!!\n");

        return 0;

    }

}

 

void get(struct Queue * queue){

    if(queue->qhead!=NULL) {

        printf("得到的元素是: %d\n",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("--------------\n");

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

        do {

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

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

            

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

        printf("--------------\n");

        queue->qhead=temp;

    }else{

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

    }

}

 

 

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\n",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("队列为空\n");

    }else{

        printf("队列不为空\n");

    }

 

    

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

    }

    

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

    

    print(queue);

 

    if(isFull(queue)){

        printf("队列已满\n");

    }else{

        printf("队列未满\n");

    }

    

    

    get(queue);

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

    print(queue);

    

    get(queue);

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

    print(queue);

    

    get(queue);

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

    print(queue);

    get(queue);

    

    printf("对首元素是:%d\n",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("队列为空\n");

    }else{

        printf("队列不为空\n");

    }

    

    

    if(isFull(queue)){

        printf("队列已满\n");

    }else{

        printf("队列未满\n");

    }

 

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

 

    

    clearQueue(queue);

    

    

    if(isEmpty(queue)){

        printf("队列为空\n");

    }else{

        printf("队列不为空\n");

    }

    

    

    print(queue);

    return 0;

}

 













































以上是关于C 数据结构之栈和队列的主要内容,如果未能解决你的问题,请参考以下文章

剑指Offer数据结构之栈和队列[Python版]

剑指Offer数据结构之栈和队列[Python版]

数据结构之栈和队列及其Java实现

数据结构之栈和队列

数据结构之栈和队列

数据结构之栈和队列