1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
| /* 插入:进队:队尾 删除:出队:队头 可以想象一下啊买东西排队的情况 First In First Out F I F O 允许插入的一端成为队尾,允许删除的一端称为队头。 所以我们再学习这一部分知识的时候一定要对头插法和 尾插法有着熟练的掌握!
!!!模型一:!!! front: 头指针,指向队列头元素 rear: 尾指针,指向尾元素的下一个 队空条件:front == rear 队满条件:rear - front ==0 这里读者可以自己试试几种队满和对空的情况
通过不断的测试,我们发现,如果仅仅根据rear =MAXSIZE 判断队满的情况是不合理的,因为再实际的生活和问题中我们知道 ,一个队伍可以站多少人,完全取决于总的人数,也就是MAXSIZE ,而不是取决于最后一个人是不是站在了某一个地方,也就是rear==MAXSIZE ,如果那样的话,显然会造成存储空间的大大浪费,所以, 模型二: 我们这里不妨1设想,即使使用数组,数组也是一个循环或者说是一个front 和 rear连在一起环状数组,数组的下标同样成立,比如,当MAXSIZE=5,front =4时 ,按照道理说此时的rear已经起码为5了(其实按照道理是不可以的),也就是说不能再进队了, 但是可以想到,在front 的前面应该还有4个位置,所以根据循环数组 的假设,我们知道此时的rear应该是rear = 1,而不是5,可以继续 在top处入队,假设此时处于4的位置元素为a,=进入新的元素b,之后, b就在4的位置了,而a就在0的位置了,此时相应的rear的位置应该为1,也就是 队头指针进一:front=(front+) MOD MAXSIZE 队尾元素进一: rear = (rear+1) MOD MAXSIZE, 而不是简单的加一操作了。 如此继续进行入队,我们发现: 当队满的时候,front = rear但是不等于0,而且不同的入队和出队的情况下,队满的 情况也不一样,最为头疼的是,我们好像没法判断队空了,因为此时队空和队满都 是front = rear,!!所以,为了可以区分这个问题我们 规定: 1,当rear = front时,队空 2,当(rear+1)MOD MAXSIZE = front 时,队满 由2的规定我们不难发现,按照这种情况下的队满,不是真正意义上的队满, 比如此时rear = 3,front = 4,由2的规定,我们知道已经满足,但是 由于rear并不会指向元素,所以当队满的时候,实际上还是可以加入一个 元素,但是不得不说,这个相对于模型一已经有巨大的改进了; 可以归纳如下: 队空:Q.front == Q.rear 对满: (Q.rear+1)%MAXSIZE == Q.front 进队: Q.data[Q.rear]=x; Q.rear =(Q.rear+1)%MAXSIZE; 出队: x=Q.data[Q.front]; Q.front = (Q.front+1)%MAXSIZE; 模型三: 可以设置一个flag标识,每次
*/ //静态存储 #include <stdio.h> #include <stdlib.h> #define MAX_SIZE 20 typedef char ElemType; //typedef struct //{ // ElemType data[MAX_SIZE]; //所有元素 // int front, raer; //队尾和队头 //} SqQueue; #define MAXQSIZE 100 //最大的队列长度+1 typedef struct { ElemType *base; //用来初始化分配空间 int front; int rear;
} SqQueue;
//初始化队列 void InitQueue(SqQueue &Q) { Q.base = (ElemType *)malloc(MAXQSIZE * sizeof(ElemType)); if (!Q.base) exit(OVERFLOW); //判断是否分配成功 Q.front = Q.rear = 0; }
//销毁队列 void DestroyQueue(SqQueue Q) { if (Q.base) //如果队不是空 { free(Q.base); Q.base = NULL; Q.front = Q.rear = 0; //这里的表参数也要改变 } }
//入队列 int EnQueue(SqQueue &Q,ElemType e{ if ((Q.rear + 1) % MAXQSIZE == Q.front) return 0; //判断是否队满 Q.base[Q.rear] = 0; Q.rear = (Q.rear + 1) % MAXQSIZE; return 1; }
//出队 int DeQueue(SqQueue &Q,Elemtype &e){ if (Q.front == Q.rear) //如果为空,删除并返回队头元素 return 0; //否则返回0 e = Q.base[Q.front]; Q.front = (Q.front + 1) % MAXQSIZE; return 1; }
//取队头元素 int GetHead(SqQueue Q,Elemtype &e){ if (Q.front == Q.rear) return 0; e = Q.base[Q.front]; return 1; }
//判断队空 int QueueEmpty(SqQueue Q){ if (Q.front == Q.rear) return 1; else return 0; }
//求队列中元素的个数(循环队列) int QueueLength(SqQueue Q){ /*其实我自己的想法是根据队满条件建立循环,但是总结发现 这个方法确实成立,而且很简便*/ return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE; }
/*如果只有front队头指针,一个计数器count, 大小为MAXSIZE的 环形数组,问 1,最多可以容纳多少元素 2,设计相关算法*/ #define MaxSize 10 typedef struct{ int data[MaxSize]; int front; int count; }SQ; //SQ为空:sq.count == 0; //队满: sq.count == MaxSize; //队尾元素的位置: (sq.front +sq.count)%MaxSize;
//初始化 void InitSQ(SQ &qu){ qu.front = qu.count = 0;
}
//销毁队列不需要,因为没有malloc
//入队 int EnSQ(SQ &sq,int x){ if (sq.count == MaxSize) return 0; sq.data[(sq.front + sq.count) % MaxSize] = x; sq.count++; //计数器 return 1; }
//出队 int DeSQ(SQ &sq,int &x){ if (sq.count == 0) return 0; x = sq.data[sq.front]; sq.front = (sq.front + 1) % MaxSize; //重要 sq.count--; //计数器 return 1; }
//取队头元素 int GetSQ(SQ sq,int &x){ if (sq.count == 0) //判断队是否为空 return 0; x = sq.data[sq.front]; return 1; }
//判断队空 int SQEmpty(SQ sq){ if (sq.count == 0) return 1; //如果队空,返回1; else return 0; }
|