代码随想录算法训练营day3|链表1

本文介绍了链表的结构、节点初始化、删除操作(包括头节点和非头节点),以及使用虚拟头节点和双指针法、递归法反转链表的方法。
摘要由CSDN通过智能技术生成

【链表的定义和初始化】

首先定义节点

struct ListNode
{
   double value;//每个节点的第一部分用来存储数据,节点为double类型的数据
   ListNode *next;//每个节点的第二部分,指向下一个节点的指针
}

节点的构造函数可以不写,C++会默认生成一个构造函数

ListNode* head = new ListNode(5);//自己定义构造函数初始化节点,初始化的同时给变量节点赋值为5


//使用默认的构造函数初始化节点,就是得再加一个给节点赋值的语句
ListNode* head = new ListNode();  
head->val = 5;

【收获1】null是整数类型,用nullptr可以不考虑类型转换问题,它的类型是std::nullptr_t,现在最好用后者。

【收获2】链表适合数据量不固定,频繁增删的数据集合。数组适合数据量较固定,较少增删的数据集合。

【删除链表中的节点】

原题:leetcode203移除链表元素

这道题的求解不涉及复杂的算法,一种是直接从链表中移除元素,将待移除元素的前一个节点的指针,改为指向待移除元素的下一个节点,就实现了把这个节点从链表中移除,但是在C++中不能忘记手动把这个节点delete。

除此之外,头结点的移除和其他节点存在不同,因为移除头节点就要让与头节点相连接的节点变成头节点,代码实现如下:

//删除头节点
while(head != NULL&&head->val==val){  //要确保这个链表不是空的,头节点是有实际值的
    ListNode* tmp = head;    //将头节点的指针下的地址赋值给tmp
    head = head -> next;      //现在头节点移动到链表的下一个节点
    delete tmp;             //删除这个tmp,就让这个节点完全消失了。

}

删除非头节点的代码实现如下:

ListNode* cur = head;
while(cur !=NULL &&cur->next!=NULL){
if(cur->next->val==val){    //不难看出这里cur是val的前一个节点
ListNode* tmp = cur->next;  //要被移除的是val所在处的节点,把存储这个节点位置的指针内的地址给tmp

cur->next = cur->next->next; //把这个val往后一个节点的地址放进cur->next,这样就实现了val地址被 
                              //覆盖掉,也就实现了移除
delete tmp;    //删除tmp,完全将其地址从内存中删除
}else{
cur = cur->next;//如果这个指针不是指向val节点的,就继续往后移动,直到找到这个位置,不进入else中
}
}

【使用虚拟头节点移除节点】

先定义一个虚拟头节点

ListNode* dummyHead = new ListNode(0);//设置一个虚拟节点
dummyHead->next = head;//将虚拟头节点指向head,这样方便后面做删除操作

确保不是空指针的情况下,再判断指针指向的值是不是val,如果是,那就进行删除节点操作,先把指向val的指针里存储的把val前一个节点的指针改为指向val的下一个节点,就是cur->next->next

这里注意一点,就是每个节点的第二部分(指针)存储的是下一个节点的地址。

ListNode* cur = dummyHead;//将虚拟头的值给cur
while(cur->next !=NULL){      //虚拟头指向当前实际头节点,只要这个节点不为空,就进入判断
  if(cur->next->val == val){    //判断cur指向的节点的值是不是
  ListNode* tmp = cur->next;    //将val的地址存进tmp
  cur->next = cur->next->next;   //让val的前一个节点的第二部分指向val的后一个节点
  delete tmp;    //删除tmp,这时就完全删除了val这个节点
}else{
cur = cur->next;    //如果不是指向val的指针,就向前走,让cur的指针向前移,进入下一次判断
}
}

完整求解过程代码:

/**
 * 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(0);
    dummyHead->next = head;
    ListNode* cur = dummyHead;
    while(cur->next != NULL){
        if(cur->next->val==val){
            ListNode* tmp = cur->next;
            cur->next = cur->next->next;
            delete tmp;
        }else{
            cur = cur->next;
        }
    }
    head =dummyHead->next;
    delete dummyHead;
    return head;
    }
};

【链表的设计】

原题链接leetcode设计链表

求解源代码:

class MyLinkedList {
public:
    MyLinkedList() {
    this->head=new ListNode(0);
    this->size = 0;
    }
    
    int get(int index) {
     if(index<0||index >= size){
         return -1;
     }
     ListNode *cur = head;
     for(int i=0;i<=index;i++){
         cur = cur->next;
     }
     return cur->val;
    }
    
    void addAtHead(int val) {
    addAtIndex(0,val);
    }
    
    void addAtTail(int val) {
    addAtIndex(size,val);
    }
    
    void addAtIndex(int index, int val) {
    if(index >size){
        return;
    }
    index = max(0,index);
    size++;
    ListNode *pred = head;
    for(int i=0;i<index;i++){
        pred = pred->next;
    }

    ListNode *toAdd = new ListNode(val);
    toAdd->next = pred->next;
    pred->next = toAdd;
    }
    
    void deleteAtIndex(int index) {
     if(index<0||index >= size){
         return;
     }
     size--;
     ListNode *pred = head;
     for(int i=0;i<index;i++)
     {
         pred = pred->next;
     }
     ListNode *p = pred->next;
     pred->next=pred->next->next;
     delete p;
    }
    private:
    int size;
    ListNode *head;
};

/**
 * 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);
 */

3.原题链接leetcode207反转链表

【双指针法求解】

定义两个指针;pre和cur;pre再前cur在后。

每次让pre的next指向cur,实现一次的局部反转

局部反转完成后,pre和cur同时往前移动一个位置

循环上述过程,直至pre到达链表的尾部

class Solution{
public:
   ListNode* reverseList(ListNode* head){
    while (pre != NULL){
        ListNode* t = pre->next;//定义指针pre,cur;pre在前cur在后
        pre->next = cur;    //让pre指向cur,实现第一次局部反转
        cur = pre;//局部反转完成后,pre和cur同时往前移动一个位置
        pre = t;
      }  //循环到pre到达链表尾部
     return cur;
    }
 };

【递归法求解】

使用递归函数,一直低轨道链表的最后一个节点,该节点就是反转后的头节点,记作ret.

此后,每次函数在返回的过程中,让当前节点的下一个节点的next指针指向当前节点。

同时让当前节点的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* reverseList(ListNode* head) {
    if(head == NULL||head -> next == NULL){
        return head;
    }
    ListNode* ret = reverseList(head->next);
    head->next->next = head;
    head->next =NULL;
    return ret;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值