拓展: 只保存尾结点的链队列

思考: 所谓队列 ,就是在一端进行删除出队,一段进行入队, 可是其未规定这两端的的距离 . 

在上一节 ,我们采用包含 队首指针和队尾指针的头结点来指向链表的队首和队尾节点 ,我们难道不能直接在节点上定义指针吗? 队尾指针指向 链表最后一个节点,然后队尾节点再直接定位指向队首,

这样我们就实现了队列的首尾指针的定义

说白了,就是在单链表上加了一个rear队尾结点,用来指向最后一个节点 , 逻辑上是一个队列


7ec177d5593e4daa8ea164fdd545d543.png


那链队只需要定义一个尾指针即可 , 我们插入元素时,让队尾元素指向新元素 , 队尾指针指向新元素 ,然后新元素的后继指针指向队头元素

● 链队四要素

        •队空条件: rear = NULL

        • 队满条件: 不考虑

        • 进队e操作 : 将包含e的节点插入到单链表表尾

        • 出队操作: 删除单链表首节点


注意: 我们的链队 是用单链表承接的, 所以每个节点只包含数据域 和 指针域(我们只是定义了一个单链表,然后变换了指针,然后把他看成了队列而已)

定义单链表结点的指针和数据

typedef struct LNode
{
    ElemType data;                //节点的数据区,用类型定义的结构属性
    struct LNode *next;
}LinkList;

●初始化队算法:

将链表的队尾指针置空即可

8cd02b5223ac4ff9ac3b2a3aaff6bfdf.jpeg


//传入要置空的队列
void initQueue(LinkList *&rear)
{
    //直接置空即可
	rear=NULL;
}

● 判断队空的算法

即判断链队的队尾指针指向的是否有节点

bool queueEmpty(LinkList *rear)
{
	return(rear==NULL);
}

● 进队的算法

先把新元素打造成一个新节点,然后插入到队列末尾即可 

//传入要插入的链队 , 存新元素的变量

​
void enQueue(LinkList *&rear,ElemType x)
{

​

打造新节点 ,传入新元素

    LinkList*p;
	p=(LinkList*)malloc(Linkist));
	p->data=x;

先判断链队是否为空,为空,则 新节点作为唯一一个节点, 其队首指针也指向新节点

9486fff1173840cab8e585b191362417.png

if (rear==NULL)
{
    //单链表节点的后继指针指向自己很合理
	p->next=p;
    //rear也是一个单链表节点,其将p赋值给自己,两个管理者管理同一个地方,即代表同一个链队
	rear=p;
}

不为空则把新节点插入到队尾节点的后面,并且移动相关指针

df4960a7070049c1aca5174093265741.jpeg

 原来队尾节点的后继指针指向新节点 , 然后 新节点的后继指针指向队头 ,并且标志队尾的节点也移向新元素,标志队尾

else
	{
        //新节点的后继指针指向队头元素 rear->next(存放着队头元素的地址)
		p->next=rear->next; 
        //插入前的队尾节点的地址存放在rear中 ,让其后继指针指向p即可
		rear->next=p;
        //rear向后移动到 p,标志队尾节点
		rear=p;
	}
}

注意: 这时候,有的朋友会疑惑 ,我们为什么要这种顺序呢? 换一下行不行 ,我们还是那句话,涉及到指针的时候一定要非常小心 ,我们要把队尾元素 an 指向 新元素x ,我们现在已经知道x的地址 , 还有 队尾节点 an的地址(存放在 rear中) ,

我们直接 第一步写:  rear->next = p

此时会把 rear->next的指针覆盖掉 ,rear->next 指向的是队头节点 a1,我们就丢失了后续节点信息,无法接着链接

所以要先把 rear -> next 利用完,再进行相应覆盖

所以先把新节点的后继指针指向 a1

即 :  p->next=rear->next; 

然后再将队尾元素an和 新节点 p 链接起来 

即:    rear -> next = p

 最后把 rear 指向 p

●出队算法

就是把 队尾指针rear 指向的元素删除,然后 rear指向上一个元素,

bf3601fd5a304798af4759a6b1d284b5.jpeg

(1)当链队是空的时候 ,我们当然出队不了元素

(2)当队列中只有一个元素 ,我们就不需要考虑其他节点了,直接将出队节点释放,然后置空rear 即可

(3)当队列中不止一个节点,说明我们出队完, 需要把 rear 指向前一个节点,前一个节点的后继指针指向 队首的第一个节点


//传入 要出队的链表 ,存储出队元素的地址
bool deQueue(LinkList*&rear,ElemType&x)
{
	//要出队的元素位于队头,给要出队的节点起名,存储其地址,当其出队后,即可释放其空间
	LinkList*q;
	//如果链队为空,则无法出队元素
	if (rear==NULL)
	{
		return false;
	}
	//如果链队只有一个元素,就是队尾指针rear和队首rear->next都指向同一个节点时
    else if(rear->next==rear)
	{
		//把要出队的节点传出
		x=rear->data;
		//释放要出队的节点空间
		free(rear);
		//节点置空
		rear=NULL;
	}
	//经过上两个条件的筛选,下面的链队不止一个元素
	else
	{
		//先出队元素地址赋值给q,方便后续释放
		//我们要出队的元素就位于队尾节点的后继节点
		q=rear->next;
		//将出队元素数据传出
		x=q->data;
		//然后将rear的后继指针指向 q的下一个节点
		rear->next=q-next;
		//释放队首节点
		free(q);
	}
	return true;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值