[代码随想录03]链表操作移除元素、设计链表、反转链表

前言

 链表:链表主要是考基础操作多一点,基本的对链表进行增删查改,所以我们必须要熟悉链表的底层数据结构,题目二的设计链表就是最好的题目

tips:关于链表需要遍历的问题,尽量使用伪头结点去处理,因为遍历操作一般是通过当前节点去改下一个节点,头结点会处于尴尬的地方,需要我们单独处理,为了简化操作,我们可以定义一个伪头,然后统一逻辑处理。

题目链接

203. 移除链表元素 - 力扣(LeetCode) 

 707. 设计链表 - 力扣(LeetCode)

 206. 反转链表 - 力扣(LeetCode)

一、移除元素

思路1:迭代的思路,加入头结点,for循环遍历,如果nxt 是目标值就delete,最后返回伪头的下一个元素。

思路2:递归的思路,不断返回新的头结点去,跳过目标节点,同时删除原节点。

//直接迭代,加入头结点,能大幅度降低代码逻辑
    ListNode* removeElements1(ListNode* head, int val) {
        ListNode dummy(0,head);
        auto cur=&dummy;
        while(cur->next){
            auto nxt=cur->next;
            if(nxt->val==val) cur->next=nxt->next,delete nxt;
            else cur=nxt;
        }
        return dummy.next;
    }
//递归的方法
    ListNode* removeElements(ListNode* head, int val) {
        if(head==nullptr)return nullptr;
        if(head->val==val){
            ListNode* newhead=removeElements(head->next,val);
            delete head;
            return newhead;
        }else{
            head->next=removeElements(head->next,val);
            return head;
        }
    }

二、设计链表

 思路1:设计一个单链表,首先我们需要一个节点的结构体,并显示定义节点的构造函数,链表初始化头结点,接着定义size即可

  • get需要位置是否有效,然后去循环迭代得到下标索引index,去得到具体值。
  • 头插入,伪头后面,直接构造一个新节点,新节点的下一个赋值给伪头的下一个,伪头等于新节点,然后size++
  • 尾插入,构造新节点,循环遍历索引找空,直接插入。
  • 索引index位置插入,结合一下get操作的思路,先对index合法性校验,然后--迭代,新节点的下一个赋值给伪头的下一个,伪头等于新节点,然后size++。就是头插入的操作
  • 删除索引位置,一样的操作但是需要删除中间我们不想要的节点。

 

class MyLinkedList {
public:
    struct LinkedNode{
        int val;
        LinkedNode* next;
        LinkedNode(int val):val(val),next(nullptr){}
    };
    MyLinkedList() {
        _dummyhead=new LinkedNode(0);
        _size=0;
    }
    int get(int index) {
        if(index>(_size-1)||index<0) return -1;
        LinkedNode* cur=_dummyhead->next;
        while(index--){
            cur=cur->next;
        }
        return cur->val;
    }
    void addAtHead(int val) {
        LinkedNode* newNode=new LinkedNode(val);
        newNode->next=_dummyhead->next;
        _dummyhead->next=newNode;
        _size++;
    }
    void addAtTail(int val) {
        LinkedNode* newNode=new LinkedNode(val);
        LinkedNode* cur=_dummyhead;
        while(cur->next!=nullptr){
            cur=cur->next;
        }
        cur->next=newNode;
        _size++;
    } 
    void addAtIndex(int index, int val) {
        if(index>_size)return ;
        if(index<0)index=0;
        LinkedNode*newNode=new LinkedNode(val);
        LinkedNode*cur=_dummyhead;
        while(index--){
            cur=cur->next;
        }
        newNode->next=cur->next;
        cur->next=newNode;
        _size++;
    }  
    void deleteAtIndex(int index) {
        if(index>=_size||index<0)return ;
        LinkedNode*cur=_dummyhead;
        while(index--){
            cur=cur->next;
        }
        LinkedNode* tmp=cur->next;
        cur->next=cur->next->next;
        delete tmp;
        tmp=nullptr;
        _size--;
    }
    private:
    int _size;
    LinkedNode* _dummyhead;
};

三、反转链表

 思路1:主要是迭代的思路,我个人总结了一个口诀,初始化、保存、翻转、更新更新这样对于我们做这道题目能更好的理解翻转操作。

思路2:主要是递归的思路,他比迭代主要少了两行代码,在整体思路上面,我们可以看见主要是通过传递参数的不同去完成更新操作。

 ListNode* reverseList1(ListNode* head) {
//迭代的方式,初始化操作,记住口诀,保存翻转更新。
        ListNode* pre=nullptr,*cur=head,*nxt=nullptr;
        while(cur){
            nxt=cur->next;//保存
            cur->next=pre;//翻转
            pre=cur;//更新
            cur=nxt;
        }
        return pre;
    }
//递归的方式
    ListNode* reverse(ListNode* pre,ListNode* cur){
        if(cur==nullptr)return pre;
        //翻转
        ListNode* nxt=cur->next;
        cur->next=pre;
        return reverse(cur,nxt);//少了两步更新的操作,通过传参来解决
    }
    ListNode* reverseList(ListNode* head) {
        return reverse(nullptr,head);
    }

总结

 总结一下我们常见的链表操作,主要熟悉增删查改,我们在写链表题目的时候最好画一个图,先保存什么,在修改什么,容易混乱。

增加:插入操作的时候,先保存下一个的指向,在挑战上一个的指向

删除:定义一个指针去释放下一个结点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值