c语言队列编程,C语言 队列(链式队列)

bbd95e492c60eb49a25b1e9512935e8e.png

链式队列----用链表实现,链式队列就是一个操作受限的单向链表,如果读者了解单向链表的建立过程,那理解链式队列就很容易了,先回顾一下单向链表的建立过程

(不熟悉单向链表的可以先看看另一片随笔,再回来看链式队列理解起来更容易☺链表(单向链表的建立、删除、插入、打印)https://www.linuxidc.com/Linux/2019-08/159766.htm

单向链表

单向链表节点的组成部分

1 struct link

2 {

3    int data;

4    struct link *next;

5 };

数据域:data----用来存储节点数据

指针域:struct link *next----用来存储下一个节点的地址

链式队列和单向链表比就多了两个指针,头指针和尾指针(这里我多加了一个length来记录队列的长度)

typedef struct QNode    /* 声明链式队列的结点 */

{

int data;

struct QNode *next;

}Node;

typedef struct QueuePoint    /* 声明链式队列的首尾指针 */

{

Node *front;

Node *rear;

int length; /* 记录链式队列长度 */

}Queue;

后面就是单向链表的建立了,这里就不再赘述了,重点分析下头指针的尾指针的移动,为了方便理解先附上main函数部分的代码

main()

{

int i = 0;

char c;

Queue q;    //链式队列首尾指针 和 长度

q.front = q.rear = NULL;    /* 首尾指针初始化 */

q.length = 0;                /* 链式队列长度初始化 */

q = init(q);                /* 初始化队列 */

printf("Do you want to append a new node(Y/N)?");

scanf_s(" %c", &c);

while (c == 'Y' || c == 'y')

{

q = AppendNode(q);    /* 入队*/

DisplyNode(q);        /* 按先进先出对队列进行打印 */

printf("Do you want to append a new node(Y/N)?");

scanf_s(" %c", &c);

}

printf("Do you want to delete node(Y/N)?");

scanf_s(" %c", &c);

while (c == 'Y' || c == 'y')

{

q = DeletNode(q);

DisplyNode(q);

printf("Do you want to delete node(Y/N)?");

scanf_s(" %c", &c);

}

return 0;

}

下面上图

08003c7655138bd9724d36885c4461a5.png

(灵魂画手已上线)

简单描述一下上图的步骤

第一步:初始化队列(就是添加一个头节点在队列中),头结点不存储数据,使队首指针和队尾指针都指向头结点

第二步:入队(添加节点),使队尾指针指向头新建的节点,队首指针不变仍然指向头结点

初始化队列和入队----实现代码

//函数功能:初始化队列(其实就是搞个头结点放在队列里面)

//单独弄个子函数来初始化队列是为了方便入队的时候判断队列是否为空

Queue init (Queue p)

{

p.front = p.rear = (Node *)malloc(sizeof(Node));

if (p.front == NULL && p.rear == NULL)

{

printf("initialization failed");

exit(0);

}

p.front->next = NULL;

return p;

}

//函数功能:新建节点并添加到队列中,记录队列长度

Queue AppendNode (Queue p)

{

int data;

Node *q;

q = (Node *)malloc(sizeof(Node));

if (q == NULL)    /* 判断分配内存是否失败 */

{

printf("No enough memory to allocate");

exit(0);

}

p.rear->next = q;        /* 最后一个节点的指针指向新建节点*/

p.rear = q;                /* 队尾指针指向新建节点*/

printf("Input node data\n");

scanf("%d", &data);

p.rear->data = data;

p.rear->next = NULL;

p.length++;

return p;

}

后面来分析下出队时首尾指针的变化,因为后面出队时要用到判断队列是否为空的一个子函数,这里先附上子函数代码

int IsemptyQueue(Queue p)

{

if (p.front == p.rear)    /* 队首指针和队尾指针重合队列为空 */

{

return Empty;

}

else

{

return NoEmpty;

}

}

出队时队首指针的位置是不变的,队首指针始终指向头节点,出队时头节点的指针域指向出队节点的后一节点,并将出队的节点用free()函数释放掉,为了方便读者理解下面上图

b8a16bdb34e30c69f193cedc1441ff68.png

出队实现代码

Queue DeletNode (Queue p)

{

Node *del;

if (IsemptyQueue(p) == Empty)        /* 判断队列是否为空*/

{

printf("队列为空,无法出队 ");

return p;

}

else        /* 队列不为空 */

{

if (p.front->next == p.rear)    /* 如果出队的节点为最后一个节点 */

{

printf("出队节点的数据为%d----", p.rear->data);

free(p.rear);    /* 释放最后一一个节点*/

p.rear = p.front;        /* 队首指针和队尾指针都指向头节点 */

p.front->next = NULL;

p.length--;

}

else

{

del = p.front->next;

printf("出队节点的数据为%d----", del->data);

p.front->next = p.front->next->next; /* 使头节点的指针域指向出队节点的下一个节点 */

free(del);        /* 释放出队的节点 */

p.length--;

}

return p;

}

}

顺序队列和链式队列首尾指针的比较

1.顺序队列是用数组实现的,首指针在出队的时候移动,尾指针在入队的时候移动,需要考虑队列为空和队列为满的两种情况

2.链式队列是用链表实现的,首指针不移动始终指向头节点,尾指针在入队的时候移动,只考虑队列为空的情况(不用考虑满是因为链表长度在程序运行过程中可以不断增加,只要存储空间够malloc就能申请内存空间来存放节点)

下面附上完整代码

#include

#include

#include

#define Empty 0        /* 队列为空 */

#define NoEmpty 1    /* 队列不为空*/

typedef struct QNode    /* 声明链式队列的结点 */

{

int data;

struct QNode *next;

}Node;

typedef struct QueuePoint    /* 声明链式队列的首尾指针 */

{

Node *front;

Node *rear;

int length; /* 记录链式队列长度 */

}Queue;

void DisplyNode (Queue p);        /* 打印队列 */

Queue init (Queue p);            /* 初始化队列 */

Queue AppendNode (Queue p);        /* 入队 */

Queue DeletNode (Queue p);        /* 出队 */

int IsemptyQueue (Queue p);        /* 判断队列是否为空*/

main()

{

int i = 0;

char c;

Queue q;    //链式队列首尾指针 和 长度

q.front = q.rear = NULL;    /* 首尾指针初始化 */

q.length = 0;                /* 链式队列长度初始化 */

q = init(q);                /* 初始化队列 */

printf("Do you want to append a new node(Y/N)?");

scanf_s(" %c", &c);

while (c == 'Y' || c == 'y')

{

q = AppendNode(q);    /* 入队 */

DisplyNode(q);        /* 按先进先出对队列进行打印 */

printf("Do you want to append a new node(Y/N)?");

scanf_s(" %c", &c);

}

printf("Do you want to delete node(Y/N)?");

scanf_s(" %c", &c);

while (c == 'Y' || c == 'y')

{

q = DeletNode(q);    /* 出队 */

DisplyNode(q);        /* 按先进先出对队列进行打印 */

printf("Do you want to delete node(Y/N)?");

scanf_s(" %c", &c);

}

return 0;

}

int IsemptyQueue(Queue p)

{

if (p.front == p.rear)    /* 队首指针和队尾指针重合队列为空 */

{

return Empty;

}

else

{

return NoEmpty;

}

}

Queue DeletNode (Queue p)

{

Node *del;

if (IsemptyQueue(p) == Empty)        /* 判断队列是否为空*/

{

printf("队列为空,无法出队 ");

return p;

}

else        /* 队列不为空 */

{

if (p.front->next == p.rear)    /* 如果出队的节点为最后一个节点 */

{

printf("出队节点的数据为%d----", p.rear->data);

free(p.rear);    /* 释放最后一一个节点*/

p.rear = p.front;        /* 队首指针和队尾指针都指向头节点 */

p.front->next = NULL;

p.length--;

}

else

{

del = p.front->next;

printf("出队节点的数据为%d----", del->data);

p.front->next = p.front->next->next; /* 使头节点的指针域指向出队节点的下一个节点 */

free(del);        /* 释放出队的节点 */

p.length--;

}

return p;

}

}

//函数功能:初始化队列(其实就是搞个头结点放在队列里面)

//单独弄个子函数来初始化队列是为了方便入队的时候判断队列是否为空

Queue init (Queue p)

{

p.front = p.rear = (Node *)malloc(sizeof(Node));

if (p.front == NULL && p.rear == NULL)

{

printf("initialization failed");

exit(0);

}

p.front->next = NULL;

return p;

}

//函数功能:新建节点并添加到队列中,记录队列长度

Queue AppendNode (Queue p)

{

int data;

Node *q;

q = (Node *)malloc(sizeof(Node));

if (q == NULL)    /* 判断分配内存是否失败 */

{

printf("No enough memory to allocate");

exit(0);

}

p.rear->next = q;        /* 最后一个节点的指针指向新建节点*/

p.rear = q;                /* 队尾指针指向新建节点*/

printf("Input node data\n");

scanf("%d", &data);

p.rear->data = data;

p.rear->next = NULL;

p.length++;

return p;

}

//函数功能:按照先进先出原则对队列进行打印

void DisplyNode (Queue p)

{

if (IsemptyQueue(p) == Empty)

{

printf("队列为空,无法打印\n");

}

else

{

p.front = p.front->next;

printf("当前队列中的%d个节点[", p.length);

while (p.front != NULL)

{

printf("%d->", p.front->data);

p.front = p.front->next;

}

putchar(']');

putchar('\n');

}

}

程序试运行结果:

dae0a774a73d4c5d0a00d6c800f0288f.png

0b1331709591d260c1c78e86d0c51c18.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值