算法训练Day03|链表part01(链表理论基础、LeetCode203.移除链表元素、LeetCode707.设计链表、LeetCode206.反转链表)

文章讲解
视频讲解

链表理论基础

链表的节点定义:

// 单链表
struct ListNode {
    int val;  // 节点上存储的元素
    ListNode *next;  // 指向下一个节点的指针
    ListNode(int x) : val(x), next(NULL) {}  // 节点的构造函数
};

通过自己定义构造函数初始化节点:

ListNode* head = new ListNode(5);

使用默认构造函数初始化节点:

ListNode* head = new ListNode();
head->val = 5;

使用默认构造函数,初始化时不能直接给变量赋值。

203.移除链表元素

题目链接

重点

让节点next指针直接指向下下一个节点就可以了。弹头节点往往需要单独处理,比较麻烦,设置一个虚拟头结点再进行删除操作,统一逻辑。

代码

  • 不用虚拟头节点
/**
 * 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* removeElements(ListNode* head, int val) {
        while(head!=NULL&&head->val==val){
            ListNode *tmp=head;
            head=head->next;
            delete tmp;
        }      
        ListNode *cur=head;
        /*这么写也通过了,while判断后的那次循环就不会再判断
        while(cur!=NULL&&cur->next!=NULL){            
            while(cur!=NULL&&cur->next!=NULL&&cur->next->val==val){
                ListNode *tmp=cur->next;
                cur->next=cur->next->next;
                delete tmp;
            }
            cur=cur->next;                       
        }
        */
        while(cur!=NULL&&cur->next!=NULL){            
            if(cur->next->val==val){
                ListNode *tmp=cur->next;
                cur->next=cur->next->next;
                delete tmp;
            }
            else {
                cur=cur->next;
            }                                
        }
        return 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* removeElements(ListNode* head, int val) {
        ListNode* dummyhead=new ListNode();
        dummyhead->next=head;
        ListNode* cur=dummyhead;
        while(cur!=NULL&&cur->next!=NULL){
            if(cur->next->val==val){
                ListNode* tmp=cur->next;
                cur->next=cur->next->next;
                delete tmp;
            }
            else{
                cur=cur->next;

            }
        } 
        //head可能被删了,要重新指向,不然就是操作未知区域
        head=dummyhead->next;
        delete dummyhead;
        return head;
    }
};

以后就一律使用虚拟头节点。

707.设计链表

题目链接
设计链表的五个接口:

  • 获取链表第index个节点的数值
  • 在链表的最前面插入一个节点
  • 在链表的最后面插入一个节点
  • 在链表第index个节点前面插入一个节点
  • 删除链表的第index个节点

代码

class MyLinkedList {
public:  
    struct ListNode{
        int val;
        ListNode* next;
        ListNode(int x):val(x),next(NULL){}
        ListNode(int x ,ListNode* next):val(x),next(next){}

    };
    int size;
    ListNode* dummyhead;
    MyLinkedList() {
        size=0;
        dummyhead=new ListNode(0);       
    }
    int get(int index) {
        if(index<0||index>size-1){
            return -1;
        }
        else{
            ListNode* cur=dummyhead;
            for(int i=0;i<index;i++){
                cur=cur->next;
            }
            return cur->next->val;
        }
    }   
    void addAtHead(int val) {
        ListNode* tmp=new ListNode(val);
        tmp->next=dummyhead->next;
        dummyhead->next=tmp;
        size++;
    }   
    void addAtTail(int val) {
        ListNode* cur=dummyhead;
        while(cur->next!=NULL){
            cur=cur->next;
        }
        ListNode* tmp=new ListNode(val);
        cur->next=tmp;
        size++;
    }
    
    void addAtIndex(int index, int val) {
        if(index<0) index=0;
        if(index>size){//第一次写错了,index=size的时候也是可以的
            return ;
        }
        
        else{
            ListNode* cur=dummyhead;
            for(int i=0;i<index;i++){
                cur=cur->next;
            }
            ListNode* tmp=new ListNode(val);
            tmp->next=cur->next;
            cur->next=tmp;
            size++;
        }

    }   
    void deleteAtIndex(int index) {
        if(index<0||index>size-1){
            return;
        }
        else{
            ListNode* cur=dummyhead;
            for(int i=0;i<index;i++){
                cur=cur->next;
            }  
            ListNode* tmp=new ListNode(0);
            tmp=cur->next;       
            cur->next=cur->next->next;
            delete tmp;
            tmp=nullptr;
            size--;
        }

    }
};

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * MyLinkedList* obj = new MyLinkedList();
 * int param_1 = obj->get(index);
 * obj->addAtHead(val);
 * obj->addAtTail(val);
 * obj->addAtIndex(index,val);
 * obj->deleteAtIndex(index);
 */

206.反转链表

题目链接

重点

普通双指针法:这道题不用虚拟头节点了,因为反转后头结点指向空了。要翻转的节点是cur,cur的前一个节点定义为pre,在cur要指向pre之前,要把 cur->next 节点用tmp指针保存一下。
递归法:我的理解是和普通双指针法思路一样,但是主函数里要有一个函数作为启动节点,参数值是最初的;调用的函数作为功能实现,要有循环条件(翻转完指针的移动)和终止条件(和普通双指针法思路一样)。递归法还是要在多理解一下。

代码

  • 普通双指针法
/**
 - 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* reverseList(ListNode* head) {
        ListNode* cur=head;
        ListNode* pre=nullptr;
        while(cur!=nullptr){
            ListNode* tmp=cur->next;
            cur->next=pre;
            pre=cur;
            cur=tmp;   
        }
        return pre;
    }
};
  • 递归法

class Solution {
public:
    ListNode* reverse(ListNode* cur,ListNode* pre){//别忘了返回类型
        //终止条件
        if(cur==nullptr){
            return pre;
        }
        //函数功能,反转
        ListNode* tmp=cur->next;
        cur->next=pre;
        //return一个循环条件
        // pre = cur;
        // cur = temp;  
        return reverse(tmp,cur);
    }
    ListNode* reverseList(ListNode* head) {
        //直接return,里面写启动条件
        // ListNode* cur = head;
        // ListNode* pre = NULL;
        return reverse(head,nullptr);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值