链表总结

链表总结

  • 链表是通过指针串联在一起的线性结构,每个节点分为数据域指针域
    链表可分为 单链表双链表循环链表
    img
    单链表

1 链表的定义

  • 容易忘记的点,故记录
    //single lingked list
    struct ListNode {
        int val;//storage element
        ListNode *next;//pointer to next element
        ListNode() : val(0), next(nullptr) {}//constructor1
        ListNode (int x) : val(x), next(nullptr) {} //constructor2
        ListNode (int x, ListNode *ptr) : val(x), next(ptr) {} //constructor3
    };
    ListNode* L1 = new ListNode(5); // init 1
    /*or*/
    ListNode* L2 = new ListNode();
    L2->val = 5;

2 链表的操作

  • 若引入头节点,链表的操作将简单许多:
class Solution {
    public:
     ListNode* CreatDummyHead(ListNode* head) {
        ListNode* dummyhead = new ListNode(0);//virtual head node
        dummhead->next = head;
        return dummyhead;
     }
}

3 链表相关算法题的经典解决方法

3.1 双指针法

双指针法是一个很经典的方法,在链表、数组等地方都有很经典的应用,笔者更喜欢通过题目探究应用。题目为代码随想录中所挑出的经典算法。

  • LettCode:反转链表
    题目描述:img
    img
    设置两个节点P1,P2
    反转操作为:
    1、储存P2.next到temp
    2、P2.next = P1
    3、P1 = P2
    4、P2 = temp
  • LettCode:删除倒数第n个节点
    题目描述:img
    img
  • LettCode:两两交换链表中的节点
    img
    设置两个指针P1、P2,P1指向head,P2指向node1(如果指向node1和node2的话,前面节点无法表示),进行节点交换,交换后一次移动两个,需要注意的是终止条件是:P1后存在两个节点则交换,否则不进行交换。代码如下:
    img
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummy_head = new ListNode(0);
        dummy_head->next = head;
        ListNode* p1 = dummy_head;
        while(p1->next && p1->next->next)
        {
            
            ListNode* p2 = p1->next;
            ListNode* p3 = p2->next;
            ListNode* tmp1 = p3->next;
            p1->next = p3;
            p3->next = p2;
            p2->next = tmp1;
            p1 = p1->next->next;    
        }
        return dummy_head->next;
    }
}

3.2 递归法

递归法看似简单,但是在写算法的时候总会绕进去(事实上脑子并没有几个栈,不能跳进去,但是忍不住......),没有彻底清楚的感觉,只能一点点的总结,一点点的理解。
递归的三要素:本级递归的任务终止条件返回值

  • LettCode:反转链表
    这个题的第二种办法就是递归法,我们需要梳理我们这道题所对应的三要素是什么。

递归的其中之一的要素,返回条件是:反转后形成新链表的头节点(返回值)

同时怎么结束呢?当链表中没有可交换的节点则结束,就是只剩一个节点,或者没有节点,终止条件就是:只剩一个节点,或者没有节点(终止条件)
我们本级递归所要做的事情就是:反转(本级递归的任务)
reverse函数里就光反转节点,在参数传递中已经将指针进行了移动。

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        return reverse(NULL,head);
              
    }
    ListNode* reverse(ListNode* p1 ,ListNode* p2)
    {
        if(!p2) {return p1;}
              ListNode* tmp = p2->next;
              p2->next = p1;
              //p1 = p2;
              //p2 = tmp;
              return reverse(p2,tmp);

    }
};
  • LettCode:两两交换链表中的节点
    递归的图参考的就是lyl's blog的博客,其实两两交换节点,可以抽象成,本级递归的任务就是交换noden 和noden+1 即可,然后行成新的完成链表返回。
    img
    对应三要素:
    终止条件:没有可交换节点
    本级递归的任务:交换节点
    返回值:新的完成链表的头节点
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {

        ListNode* n = head;
        if(n == nullptr || n->next == nullptr)
        {
            return n;
        }
        ListNode* nnext = n->next;
        n->next = swapPairs(nnext->next);
        nnext->next = n;
        return nnext;
    }
};

3.3 环形列表的知识点

posted @ 2023-01-08 23:08  jiumaohappyboy  阅读(36)  评论(0编辑  收藏  举报