2001-3-26
华中科技大学计算机学院 (5)数据结构
3.4 队列 (排队,queue)
3.4.2 链式队列,用带表头结点的单链表表示 队列
1.一般形式
(1)空队列,
(2) 非空队列,
其中,Q.front----队头 (首 )指针,指向表头结点。
Q.rear----队尾指针,指向队尾结点。
Q.front->data 不放元素。
Q.front->next 指向队首结点 a1。
/// ∧
data next
表头结点
///
data next
表头结点
a1
队头结点
an ∧
队尾结点
...
Q.front
Q.rear
Q
Q.front
Q.rear
Q
2.定义结点类型
(1)存放元素的结点类型
typedef struct Qnode
{ ElemType data; //data为抽象元素类型
struct Qnode *next; //next为指针类型
}Qnode,*QueuePtr; //结点类型,指针类型其中,Qnode----结点类型
QueuePtr----指向 Qnode的指针类型
(2)由头、尾指针组成的结点类型
typedef struct
{ Qnode *front; //头指针
Qnode *rear; //尾指针
}LinkQueue; //链式队列 类型
data next
front
rear
3.生成空队列 算法
#define LENG sizeof(Qnode) //求结点所占的单元数
LinkQueue InitQueue( ) //生成仅 带表头结点的空队列 Q
{ LinkQueue Q; //说明变量 Q
Q.front=Q.rear=(QueuePtr)malloc(LENG); //生成表头结点
Q.front->next=NULL; //表头结点的 next为空指针
return Q; //返回 Q的值
}
main()
{
LinkQueue que; /*定义一个队列 */
que=InitQueue();
………
}
/// ∧
data next
表头结点
Q.front
Q.rear
Q
x
新结点 X
///
表头结点
Q.front
Q.rear x ∧
X
队头 (尾)结点
P
4.(空队列时)插入新元素 x
P
///
表头结点
Q.front
Q.rear x ∧队头 (尾) y
data next
///
表头结点
Q.front
Q.rear x队头结点 y ∧
新结点 y
队尾结点
X
(非空队列时)插入新元素 y
插入新元素 e的的算法 (1)
LinkQueue EnQueue(LinkQueue Q,ElemType e)
{ Qnode *p; //说明变量 p
p=(Qnode *)malloc(LENG); //生成新元素结点
p->data=e; //装入元素 e
p->next=NULL; //为队尾结点
Q.rear->next=p; //插入新结点
Q.rear=p; //修改尾指针
return Q; //返回 Q的新值
}
main()
{
LinkQueue que; /*定义一个队列 */
que=InitQueue();
que=EnQueue(que,10);
}
插入新元素 e的的算法 (2)
int EnQueue(LinkQueue *Q,ElemType e)
{ Qnode *p; //说明变量 p
p=(Qnode *)malloc(LENG); //生成新元素结点
if (!p) {printf(“OVERFLOW”); //新结点生成失败
return ERROR;}
p->data=e; //装入元素 e
p->next=NULL; //为队尾结点
Q->rear->next=p; //插入新结点
Q->rear=p; //修改尾指针
return OK; //成功返回
}
main()
{
LinkQueue que; /*定义一个队列 */
que=InitQueue();
EnQueue(&que,10);
}
5.出队 ----删除队头结点
(1)若原队列有 2个或 2个以上的结点
///
表头结点
a1
队头结点
a2,..Q.frontQ.rear
P
///
表头结点
a1
队头结点
a2,..Q.frontQ.rear
P
(a)执行,Q.front->next=p->next;
(b)执行,free(p);
///
表头结点 队头结点
a2,..Q.frontQ.rear
P
X
(2)若原队列只有 1个结点
/// ∧
表头结点
a1 ∧
队头结点
Q.front
Q.rear
P
(a)执行,Q.front->next=p->next;
/// ∧
表头结点
a1 ∧
队头结点
Q.front
Q.rear
P
(b)执行,free(p);
/// ∧
表头结点
Q.front
Q.rear
P
/// ∧
表头结点
Q.front
Q.rear
(c)执行,Q.rear=Q.front;
X
X
X
X
出队算法,
LinkQueue DelQueue(LinkQueue Q,ElemType *e)
{ Qnode *p; //说明变量 p
if (Q.front==Q.rear) //若原队列为空
exit("Empty queqe"); //退出去
p=Q.front->next; //P指向队头结点
(*e)=p->data; //取出元素,e指向它
Q.front->next=p->next; //删除队头结点
if (Q.rear==p) //若原队列只有 1个结点
Q.rear=Q->front; //修改尾指针
free(p); //释放被删除结点的空间
return Q; //返回出队后的 Q
}
A
A B C
0 1 2 3 4 5
0 1 2 3 4 5
0 1 2 3 4 5
← A进队
f
← B,C,D进队
f r
f r
(3)B,C进队后,
3.4.3 队列的顺序表示和实现
(1)初始化后,
(2)A进队后,
假设用一维数组 Q[0..5]表示 顺序队列
1.顺序队列 与,假溢出设 f指向队头元素,r指向队尾元素空队列r
空队列 f=r+1
D E F
0 1 2 3 4 5
0 1 2 3 4 5
fr
← D,E,F 进队
f r
← G进队,“假溢出解决假溢出的办法之一,移动元素。
(6)D,E,F移到前端后:
D E F
0 1 2 3 4 5
f r
← G 进队
(4)A,B,C 出队之后:
(5)D,E,F 依次进队之后:
此时空队列 f=r+1
D E F G
0 1 2 3 4 5
f r
D E F
0 1 2 3 4 5
r
← G 进队,插入到 Q[0]
2.循环队列 与解决假溢出的办法之二
----将 Q当循环表使用:
G D E F
0 1 2 3 4 5
r
(2) G进 Q[0]之后,f
f
(7)G进队之后:
(1)
G H I D E F
0 1 2 3 4 5
2
3 4
5
01
F
G
D E
///
///
← H,I 进队
2
3 4
5
01
F
G
D E
I
H
(3)H,I进队之后
f
r
f
r
fr
“满队列,
将 Q[0..5]解释为循环队列的示意图:
f=r+1时空队列?
满队列?
3.设 f指向队头元素前一个空位,约定此空位不放元素 ; r指向队尾元素 。将 Q[0..5]解释为 循环队列 。
A
A B C D
0 1 2 3 4 5
0 1 2 3 4 5
0 1 2 3 4 5
← A进队
f r
← B,C,D进队
f r
f r
(3)B,C,D进队
Q[++r]=B;
Q[++r]=C;
Q[++r]=D;
(1)初始化
f=r=0;
(2)A进队
++r;
Q[r]=A;
空队列
D
0 1 2 3 4 5
f r
(4)A,B,C出队
e1=Q[++f];
e2=Q[++f];
e3=Q[++f];
← E 进队
D E
0 1 2 3 4 5
f r
← F 进队(5)E进队
Q[++r]=E;
F D E
0 1 2 3 4 5
fr
← G,H 进队(6)F进队r=(++r)%6;
Q[r]=F;
F G H D E
0 1 2 3 4 5
fr
← G,H 进队(7)G,H进队后:
当 r+1==f,为 满队列若队列为 Q[0..maxleng-1],共有 maxleng-1个元素
A B C D E
0 1 2 3 4 5
rf
当 (f==0)&&(r==maxleng-1)即当 (r+1)% maxleng==f
也为 满队列
0 1 2 3 4 5
rf
(2)A,B,C,D,E
依次出队后:
当 (f==r)为 空队列
(1)若 A,B,C,D,E
依次进队后:
4.设 f指向队头元素 ; r指向队尾元素的下一个空位,约定此空位不放元素。 将 Q[0..5]解释为 循环队列 。
A
A B C D
0 1 2 3 4 5
0 1 2 3 4 5
0 1 2 3 4 5
← A进队
f r
← B,C,D进队
f r
f r
(3)B,C,D进队
Q[r++]=B;
Q[r++]=C;
Q[r++]=D;
(1)初始化
f=r=0;
(2)A进队
Q[r]=A;
r++;
空队列
D
0 1 2 3 4 5
f r
(4)A,B,C出队
e1=Q[f++];
e2=Q[f++];
e3=Q[f++];
← E 进队
D E
0 1 2 3 4 5
f r
← F 进队(5)E进队
Q[r++]=E;
D E F
0 1 2 3 4 5
fr
← G,H 进队(6)F进队Q[r++]=F;
r=r%6;
F G H D E
0 1 2 3 4 5
fr
← G,H 进队(7)G,H进队后:
当 r+1==f,为 满队列若队列为 Q[0..maxleng-1],共有 maxleng-1个元素
A B C D E
0 1 2 3 4 5
rf
当 (f==0)&&(r==maxleng-1)也为满队列
0 1 2 3 4 5
rf
(2)A,B,C,D,E
依次出队后:
当 (f==r)为 空队列
(1)若 A,B,C,D,E
依次进队后:
5.顺序队列算法举例定义队列的 C类型
#define MAXSIZE 10
Typedef struct
{
ElemType elem[MAXSIZE];
int front,rear;
} SeQueue;
SeQueue Q;
elem[0]
elem[1]
… …
elem


… …
… …
elem[MAXSIZE-1]
front
rear
队列 Q
5.顺序队列算法举例
(1)进队算法,
假设用 Q表示顺序队列,头指针 f指向对头元素的前一个空位,
r指向尾元素,e为进队元素。
void En_Queue( SeQueue *Q,Elemtype e)
{ if ((Q->rear+1)% MAXSIZE==Q->front) /*若 Q已满 */
exit(“Queue Overflow”); /*退出 */
Q->rear ++; /*尾指针后移一个位置 */
Q->rear = Q->rear % MAXSIZE; /*为循环队列 */
Q[Q->rear]=e; /*装入新元素 e*/
}
///
0 1 2 MAXSIZE-1
///
0 1 2 MAXSIZE-1
rearfrontrearfront
Q[0..MAXSIZE-1]已满 Q[0.,MAXSIZE-1]已满
(2)出队算法设用 Q表示顺序队列,头指针 front指向队头元素的前一个空位,rear指向队尾元素,删除队头元素,送入指针 e
所指向的对象中。
void De_Queue(SeQueue *Q,Elemtype *e)
{ if (Q->front==Q->rear) /*Q为空队列 */
exit(“Empty Queue”); /*退出 */
Q->front++; /*头指针后移一个位置 */
Q->front=Q->front % MAXSIZE; /*为循环队列 */
(*e)=Q[Q->front]; /*取走队头元素,送 (*e)*/
}
x,.,y
0,.,MAXSIZE-1
rearfront
x,.,y
0,.,MAXSIZE-1
frontrear
作业
1.设输入元素 B,C,A,D到栈中,能得当哪几种输出? 不能得到哪几种输出序列?
(1) A,B,C,D (7) B,A,C,D (13) C,A,B,D (19) D,B,C,A
(2) A,B,D,C (8) B,A,D,C (14) C,A,D,B (20) D,B,A,C
(3) A,C,B,D (9) B,C,A,D (15) C,B,A,D (21) D,C,B,A
(4) A,C,D,B (10) B,C,D,A (16) C,B,D,A (22) D,C,A,B
(5) A,D,B,C (11) B,D,A,C (17) C,D,A,B (23) D,A,B,C
(6) A,D,C,B (12) B,D,C,A (18) C,D,B,A (24) D,A,C,B
3种 5种 5种 1种
2.设链式栈的栈顶头指针为 top,弹出栈顶元素送 e,试写出退栈算法 pop(top,e)。
//弹出栈顶元素送 e,top为链式栈的顶指针
struct node *pop(struct node *top,Elemtype *e)
{ struct node *p;
if (top==NULL) exit("Empty stack") //空栈,退出
p=top; //p指向原栈的顶结点
(*e)=p->data; //取出原栈的顶元素送( *e)
top=top->next; //删除原栈的顶结点
free(p); //释放原栈顶结点的空间
return top; //返回新的栈顶指针 top
}
2.链式栈的退栈算法 push(top,e)。
1.试简要说明下列算术表达式的求值过程:
20 + 26 / ( 16 – 2 *( 3 + 4 ) ) - 7
画出数栈和算符栈的主要变化过程。
2.设用 Q[0..maxleng-1]表示顺序队列,头指针 f指向队头元素的前一个空位,r指向队尾元素,删除队头元素,送入
e。试写出出队算法,De_queue(Q,f,r,e)。
3.设用 Q[0..maxleng-1]表示顺序队列,头指针 f指向队头元素,r指向队尾元素的下一个空位,删除队头元素,送入 e。试写出出队算法,De_queue(Q,f,r,e)。
4.假设用 Q[0..maxleng-1]表示顺序队列,头指针 f指向对头元素,r指向队尾元素的下一个空位,e为进队元素。
试写进队算法,En_equeue(Q,f,r,e)。
家庭作业