对于链表的增删改查操作是数据结构的基础,但是当我们提交代码的时候经常会遇到头结点的判断出错问题,这里以leetcode的一道题为例重点记录下构建链表的动静态初始化方法,可以包含头结点的处理,不用对头结点做单独处理。
Merge Two Sorted Lists
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4
这道题很简单,只要初始化定义两个指针p1和p2,分别指向两个链表,把小的那个节点构建到新的链表中即可。
这里给出模板:
//新定义的链表头指针的前一个指针
ListNode* pre_head = new ListNode(-1);
//用来指向尾节点
ListNode* tmp = head;
while(something){
//把tmp指向下一个节点
tmp->next = l1;
//把tmp更新为尾节点
tmp = tmp->next;
}
已这道题为例,代码如下:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if (!l1) {
return l2;
}
if (!l2) {
return l1;
}
ListNode* head = new ListNode(-1);
ListNode* tmp = head;
while (l1 && l2) {
if (l1->val >= l2->val) {
tmp->next = l2;
tmp = tmp->next;
l2 = l2->next;
}
else {
tmp->next = l1;
tmp = tmp->next;
l1 = l1->next;
}
}
if (!l1 && l2) {
tmp->next = l2;
}
if (l1 && !l2) {
tmp->next = l1;
}
return head->next;
}
这种情况已经包含了头结点的情况,因为最后返回head->next,即使两个链表都为空,则head->next也为空,返回的依然为空指针。
如果是删除节点,a->b->c,我们要删除节点b,一般的做法是找到删除节点的前一个节点a,把a的下一个指针指向c,并删除b节点。但是如果是删除头结点a怎么办呢?a可是没有前驱节点的,所以如果不考虑这种情况就会报错。而用静态初始化链表法(静态声明pre_head节点),并把pre_head的下一个指针指向头结点(动态绑定旧链表),便可以解决删除头结点的问题:找到头结点head的前一个节点pre_head,把pre_head的next指向head的next,删除head,便完成了head头结点的删除,使代码具有统一性,健壮性更强。
ListNode* pre_head = new ListNode(-1);
pre_head->next=head
删除节点的代码如下(这里假设待删除节点):
void deleteNode(ListNode* head, ListNode* deleteNode) {
ListNode* pre_head = new ListNode(-1);
ListNode* tmp = pre_head;
pre_head->next = head;
ListNode* preDeleteNode = tmp;
while (tmp != deleteNode) {
preDeleteNode = tmp;
tmp = tmp->next;
}
//preDeleteNode为待删除节点deleteNode的头一个节点
preDeleteNode->next = tmp->next;
delete tmp;
}
这种静动态构造链表的方法非常重要,以后测试用例如果未通过(特别是关于
头结点的特殊节点报错),请考虑这种方法。