这里呢就用一道题来解释什么叫做哨兵位,以及哨兵位应该怎么使用。
链接请点这边☛☛☛☛牛客CM11
方法一:
将链表中的元素进行遍历,当这个链表中有小于x的数时,将这个位置的数据头插到链表,销毁此位置,然后链表继续向后走。不建议此方法,中途涉及保存当前位置,头位置等的问题,很麻烦!!(感兴趣可以自写代码尝试)
方法二:
将链表中的数据按顺序存到一个数组当中,然后按题目要求排序,再将值放回到原链表中,此方法的较为稳妥,可以尝试。
方法三(哨兵位):
分别开辟两个结构体来当小头链表和大头链表,将小于x的节点存到小头,其他节点存到大头,然后让小头的尾与大头的头连接到一起,返回小头的地址即可。(此方法非常适合用于此类题型,十分建议!!)
下面是AC代码演示及说明。
p1表示小链表,p11表示小链表头节点的拷贝
p2表示大链表,p22表示大链表头节点的拷贝
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class Partition {
public:
ListNode* partition(ListNode* pHead, int x) {
ListNode* p1, *p11, *p2, *p22;
ListNode* cur = pHead;
p1 = (ListNode*)malloc(sizeof(ListNode));
p11 = p1;
p2 = (ListNode*)malloc(sizeof(ListNode));
p22 = p2;
while(cur)
{
if(cur->val < x)
{
p1->next = cur;//小链表赋值
p1 = p1->next;//小链表向下走
}
else
{
p2->next = cur;//大链表进行赋值
p2 = p2->next; //大链表向下走
}
cur = cur->next;//原链表向下走
}
p2->next = NULL;//大链表后面无需连其他节点,让他不再向后连,进行置空
p1->next = p22->next;//小链表的尾连在大链表的第一个头,这边注意是开的是哨兵位,所以第一个节点不保存它的数据,所以要让他连在第二个的位置,这样整个链表就连在一起了
pHead = p11->next;//同样这边需要将这个头指向这个链表的第二个位置
free(p11);//释放两个malloc的哨兵位,释放堆空间
free(p22);
return pHead;
}
};
从上述的代码中,我们说明了两个问题。
首先什么是哨兵位,可以看到,我们方法三的思路就是将这个数据分别存在两个链表中,这两个链表的头不会存数据,只是起到连接的作用,那么这样的头就是哨兵位的头,只起到连接作用,而不存放数据,函数结束还需要将这个哨兵位的头进行free操作。
第二个问题就是代码中的biglist->next = NULL,这句的作用在于,当这个链表在结束后,对于小链表的尾是指向大链表的头,而大链表的尾还是指向的是原来的数,所以就要对他指向的next进行置空的操作,否则有可能能会造成死循环的现象。
画图演示死循环如图
所以要将大链表的尾的next置为NULL。
觉得有用可以分享给小伙伴,欢迎一起来交流~~