C 数据结构之栈和队列
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C 数据结构之栈和队列相关的知识,希望对你有一定的参考价值。
栈的基本运算有六种:
构造空栈: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
#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 数据结构之栈和队列的主要内容,如果未能解决你的问题,请参考以下文章