动态链式队列

动态链式队列详解及完整实例演示

分类: 数据结构 C语言相关 80人阅读 评论(0) 收藏 举报

队列

队列(Queue)是只允许在一端(队尾rear)进行插入,而在另一端(队头front)进行删除的运算受限的线性表。它是一种可以实现“先进先出”(FIFO)的存储结构。队列在具体应用中通常用链表或者数组来实现,因此我们也常常将队列分为静态队列(数组队列),链式队列(主要以链表方式进行操作)。当队列中没有元素时,我们称之为空队列。一般队列的存储结构是顺序存储,当队列的存储结构是链式存储结构(即队列中每个元素都包含一个指向其后继的指针,最后一个指针元素也就是尾结点的指针域为NULL)时,就是链式队列了。和栈不同,队列通常需要对其两端进行操作,而栈一般只需对通过栈顶指针进行操作即可。

对链式队列的相关操作思路

  1. typedef struct Node
  2. {
  3. int data;//数据域
  4. struct Node *pNext;//指针域
  5. }NODE,*PNODE;
  6. typedef struct Queue
  7. {
  8. PNODE pFront;//始终指向头结点(没有实际含义的结点)
  9. PNODE pRear;//始终指向尾结点(注意:尾结点数据域含有效数据,但指针域为空)
  10. }QUEUE,*PQUEUE;//PQUEUE等价于struct Queue*
typedef struct Node
{
	int data;//数据域
	struct Node *pNext;//指针域
}NODE,*PNODE;
typedef struct Queue
{
	PNODE pFront;//始终指向头结点(没有实际含义的结点)
	PNODE pRear;//始终指向尾结点(注意:尾结点数据域含有效数据,但指针域为空)
}QUEUE,*PQUEUE;//PQUEUE等价于struct Queue*

伪算法:

1.初始化。初始化的目的主要是为了造空队列

void init(PQUEUE pQ)//造空队列

{

造头结点;

让尾结点指向头结点;

将尾结点指针域赋为NULL;

return;

}

2.入队

void enter(PQUEUE pQ,int val)

{

造新节点;

将val赋给新节点的数据域;

将新节点的指针域赋为NULL;

· 将尾结点的指针域指向新节点;

使该新结点成为尾结点;

}

3.出队

bool del(PQUEUE pQ)

{

找到第一个有效节点;

判断队列是否为空;

不为空时输出有效节点的数据域;

找出第一个有效节点,并让指向第一个结点的指针指向第二个;

释放第一个结点所占内存;

注意:若队列中只有一个元素时,将头结点的地址赋给队尾,让尾结点成为无效结点;

}

4.遍历:在输出尾结点的值后,跳出循环。当然前提先要判断该队列是否为空;

5. 清空:先判断该队列是否为空;再 找出第一个有效结点,用一个临时变量保存下一个有效节点的地址,并让队头(队首)指向该地址,然后释放第一个结点所占内存,最后将下一个结点的地址赋给该队列的头结点(即让头结点指向下一个结点的地址),如此进行循环直到队尾删除完(只剩头结点,再让尾结点指向头结点,这样相当于又完成了一次对该链式队列的初始化)。

实例说明:

  1. #include<stdio.h>
  2. #include<malloc.h>
  3. #include<stdlib.h>
  4. typedef struct Node
  5. {
  6. int data;//数据域
  7. struct Node *pNext;//指针域
  8. }NODE,*PNODE;
  9. typedef struct Queue
  10. {
  11. PNODE pFront;//始终指向头结点(没有实际含义的结点)
  12. PNODE pRear;//始终指向尾结点(注意:尾结点数据域含有效数据,但指针域为空)
  13. }QUEUE,*PQUEUE;//PQUEUE等价于struct Queue*
  14. void init(PQUEUE);//初始化队列
  15. void enter(PQUEUE,int);//入队
  16. bool del(PQUEUE);//出队
  17. bool traverse(PQUEUE);//遍历
  18. int length(PQUEUE);//求链式队列长度
  19. bool clear(PQUEUE);//清空链式队列
  20. int main()
  21. {
  22. QUEUE Q;
  23. init(&Q);
  24. enter(&Q,1);
  25. enter(&Q,2);
  26. enter(&Q,3);
  27. traverse(&Q);
  28. del(&Q);
  29. traverse(&Q);
  30. printf("队列长度为:%d\n",length(&Q));
  31. clear(&Q);
  32. printf("清空后");
  33. traverse(&Q);
  34. return 0;
  35. }
  36. void init(PQUEUE pQ)//造空队列
  37. {
  38. pQ->pFront=(PNODE)malloc(sizeof(NODE));//造头结点,并让pFront指向该头结点
  39. if(NULL==pQ->pFront)
  40. {
  41. printf("动态内存分配失败!\n");
  42. exit(-1);//终止程序运行
  43. }
  44. pQ->pRear=pQ->pFront;
  45. pQ->pFront->pNext=NULL;
  46. return;
  47. }
  48. void enter(PQUEUE pQ,int val)
  49. {
  50. PNODE pNew=(PNODE)malloc(sizeof(NODE));//造新临时结点
  51. if(NULL==pNew)
  52. {
  53. printf("动态内存分配失败!\n");
  54. exit(-1);//终止程序运行
  55. }
  56. pNew->data=val;
  57. pNew->pNext=NULL;
  58. pQ->pRear->pNext=pNew;
  59. pQ->pRear=pNew;
  60. return;
  61. }
  62. bool del(PQUEUE pQ)//出队
  63. {
  64. PNODE p=pQ->pFront->pNext;//让p指向队头的第一个有效节点
  65. if(NULL==p)
  66. {
  67. printf("队列为空,出队失败!\n");
  68. return false;
  69. }
  70. else
  71. {
  72. printf("出队元素的值为:%d\n",p->data);
  73. if(p==pQ->pRear)//如果是队尾,说明只有一个有效结点
  74. pQ->pRear=pQ->pFront;//因为pFront始终指向的是头结点的地址,这里将头结点的地址赋给队尾(此时队尾成为无效结点)
  75. pQ->pFront->pNext=p->pNext;
  76. free(p);
  77. p=NULL;
  78. return true;
  79. }
  80. }
  81. bool traverse(PQUEUE pQ)
  82. {
  83. PNODE p=pQ->pFront;
  84. if(NULL==p->pNext)
  85. {
  86. printf("队列为空,遍历失败!\n");
  87. return false;
  88. }
  89. printf("队列元素有:");
  90. while(p!=pQ->pRear)
  91. {
  92. p=p->pNext;
  93. printf("%d ",p->data);
  94. }
  95. printf("\n");
  96. return true;
  97. }
  98. int length(PQUEUE pQ)
  99. {
  100. int len=0;
  101. PNODE p=pQ->pFront;
  102. if(NULL==p->pNext)
  103. {
  104. printf("队列为空!\n");
  105. return 0;
  106. }
  107. while(p!=pQ->pRear)
  108. {
  109. p=p->pNext;
  110. ++len;
  111. }
  112. return len;
  113. }
  114. bool clear(PQUEUE pQ)
  115. {
  116. PNODE p=pQ->pFront->pNext,q;//让p指向队头的第一个有效节点
  117. if(NULL==p)
  118. {
  119. printf("队列为空,清空失败!\n");
  120. return false;
  121. }
  122. else
  123. {
  124. while(p!=pQ->pRear)
  125. {
  126. q=p->pNext;//用q来保存p的下一个结点的地址
  127. pQ->pFront=q;
  128. free(p);
  129. p=q;
  130. }
  131. pQ->pRear=pQ->pFront;
  132. return true;
  133. }
  134. }
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef struct Node
{
	int data;//数据域
	struct Node *pNext;//指针域
}NODE,*PNODE;
typedef struct Queue
{
	PNODE pFront;//始终指向头结点(没有实际含义的结点)
	PNODE pRear;//始终指向尾结点(注意:尾结点数据域含有效数据,但指针域为空)
}QUEUE,*PQUEUE;//PQUEUE等价于struct Queue*
void init(PQUEUE);//初始化队列
void enter(PQUEUE,int);//入队
bool del(PQUEUE);//出队
bool traverse(PQUEUE);//遍历
int length(PQUEUE);//求链式队列长度
bool clear(PQUEUE);//清空链式队列

int main()
{
	QUEUE Q;
	init(&Q);
	enter(&Q,1);
	enter(&Q,2);
	enter(&Q,3);
	traverse(&Q);
	del(&Q);
    traverse(&Q); 
    printf("队列长度为:%d\n",length(&Q));
	clear(&Q);
	printf("清空后");
    traverse(&Q);  
	return 0;
}
void init(PQUEUE pQ)//造空队列
{
	pQ->pFront=(PNODE)malloc(sizeof(NODE));//造头结点,并让pFront指向该头结点
	if(NULL==pQ->pFront)
	{
		printf("动态内存分配失败!\n");
		exit(-1);//终止程序运行
	}
	pQ->pRear=pQ->pFront;
    pQ->pFront->pNext=NULL;
	return; 
}
void enter(PQUEUE pQ,int val)
{
	PNODE pNew=(PNODE)malloc(sizeof(NODE));//造新临时结点
	if(NULL==pNew)
	{
		printf("动态内存分配失败!\n");
		exit(-1);//终止程序运行
	}
	pNew->data=val;
	pNew->pNext=NULL;
	pQ->pRear->pNext=pNew;
	pQ->pRear=pNew;
	return;
}
bool del(PQUEUE pQ)//出队
{
	PNODE p=pQ->pFront->pNext;//让p指向队头的第一个有效节点	
	if(NULL==p)
	{
		printf("队列为空,出队失败!\n");
		return false;
	}
	else
	{
		printf("出队元素的值为:%d\n",p->data);
		if(p==pQ->pRear)//如果是队尾,说明只有一个有效结点
			pQ->pRear=pQ->pFront;//因为pFront始终指向的是头结点的地址,这里将头结点的地址赋给队尾(此时队尾成为无效结点)
		pQ->pFront->pNext=p->pNext;
		free(p);
		p=NULL;
		return true;
	}
}
bool traverse(PQUEUE pQ)
{
	PNODE p=pQ->pFront;
	if(NULL==p->pNext)
	{
		printf("队列为空,遍历失败!\n");
		return false;
	}
	printf("队列元素有:");
	while(p!=pQ->pRear)
	{
		p=p->pNext;
		printf("%d  ",p->data);
	}
	printf("\n");
    return true; 
}
int length(PQUEUE pQ)
{
	int len=0;
	PNODE p=pQ->pFront;
	if(NULL==p->pNext)
	{
		printf("队列为空!\n");
		return 0;
	}
	while(p!=pQ->pRear)
	{
		p=p->pNext;
		++len;
	}
	return len;
}
bool clear(PQUEUE pQ)
{
	PNODE p=pQ->pFront->pNext,q;//让p指向队头的第一个有效节点	
	if(NULL==p)
	{
		printf("队列为空,清空失败!\n");
		return false;
	}
	else
	{
		while(p!=pQ->pRear)
		{
			q=p->pNext;//用q来保存p的下一个结点的地址
			pQ->pFront=q;
			free(p);
			p=q;
		}
		pQ->pRear=pQ->pFront;
        return true; 
	}	
}


注意

1. 在上篇栈中,压栈(进栈)的时候pTop指向了第一个有效结点,而该链式队列中入队的时候pFront仍然还是指向了队列初始化是的头结点(没有实际含义的结点)。

2. 该链式队列中,pRear始终指向尾结点,队尾数据域为有效数据,但其指针域为空;pFront始终指向头结点(附结头结点的目的和上篇栈中的一样,为了方便对链式进行操作)。如:PNODE p=pQ->pFront->pNext;就可以让p指向队首(第一个)有效结点

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值