链表的操作

链表节点的获取

如何快速获取链表的结点个数K

链表的节点是结构体指针,密钥什么办法可以快速获取链表的结点个数。

所以只能从头到尾进行循环统计:

while(temp)
{
    ++i;
    temp=temp->next;
}

如何快速获取链表的倒数第n结点

分析:

倒数第1个就是k-(1-1),倒数第二个就是 k-(2-1),倒数第三个就是k-(3-1)

方法:

1,先统计链表节点总数,再循环到第n个节点。

单项链表如何获取当前节点的前一个节点

头节点特殊问题

很多情况下需要对头节点进行判断和作特殊处理,麻烦,怎么办:

在头节点前面再增加一个哑节点(dummy node),让头节点不再是头节点。

merge two sorted lists

Refusing to use violence algorithm to deal all question from now no.

code:

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if (l1 == nullptr) {
            return l2;
        } else if (l2 == nullptr) {
            return l1;
        } else if (l1->val < l2->val) {//如果小于
            l1->next = mergeTwoLists(l1->next, l2);//获取的是
            return l1;
        } else {//如果大于或者等于
            l2->next = mergeTwoLists(l1, l2->next);
            return l2;
        }
    }
};

递归算法实现。

} else if (l1->val < l2->val) {//如果小于
            l1->next = mergeTwoLists(l1->next, l2);//小于的下一个和大的那个比较
            return l1;
        } else {//如果大于或者等于
            l2->next = mergeTwoLists(l1, l2->next);
            return l2;
        }

函数总是返回小的那个

比较之后小的那个用于获取返回值

再把小的那个的后一个和大的那个进行比较

每一次的函数返回都是复合条件的结果,知道比较到结束条件。

递归的使用:

凡是形同数据进行循环的不要再暴力实现了,记得用递归。

迭代实现:

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* preHead = new ListNode(-1);

        ListNode* prev = preHead;
        while (l1 != nullptr && l2 != nullptr) {
            if (l1->val < l2->val) {
                prev->next = l1;
                l1 = l1->next;
            } else {
                prev->next = l2;
                l2 = l2->next;
            }
            prev = prev->next;
        }

        // 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
        prev->next = l1 == nullptr ? l2 : l1;

        return preHead->next;
    }
};

底层原理:

两两比较,获取小的,小的往后移,大的保留下次再比较。

总链表每一次获取之后都要移到最后一个节点。

链表节点获取的注意事项

获取节点之前要先判定本节点存不存在,比如获取值为NULL的节点的下一个节点,那就不存在了。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        //ListNode* pre=head->next;不能在这里获取
        //ListNode* tp=pre->next;
        if(head==nullptr)//应该先判定再获取
        return head;
        else if(head->next==nullptr)
        return head;
        else{
        ListNode* pre=head->next;
        ListNode* tp=pre->next;
        pre->next=head;
        head->next=swapPairs(tp);
        return pre;
        }
    }
};
        if(head==nullptr)
        return head;
        else if(head->next==nullptr)
        return head;
        else{
        ListNode* pre=head->next;
        ListNode* tp=pre->next;
        pre->next=head;
        head->next=swapPairs(tp);
        return pre;
        }
    }
};

迭代法实现节点的交换要保存下来第二个节点之后的链表。

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummyHead = new ListNode(0);
        dummyHead.next = head;
        ListNode temp = dummyHead;
        while (temp.next != null && temp.next.next != null) {
            ListNode node1 = temp.next;
            ListNode node2 = temp.next.next;
            temp.next = node2;
            node1.next = node2.next;
            node2.next = node1;
            temp = node1;
        }
        return dummyHead.next;
    }
}

1,亚节点的使用可以减轻思维压力,也方便使用,迭代中尽量使用。

反转链表

子链表反转功能块

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值