[代码随想录算法训练营Day03 链表Part1]

Day 03

链表 Part 01

1. 链表基础

  • C++ 中链表写法:C++用结构体定义链表节点,结构体有两个成员,一个是整数val,一个是指向ListNode类型的指针next,并且给了三个构造函数,构造函数冒号后面的内容代表初始化列表。
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){}
};

在这里插入图片描述
在这里插入图片描述

  • Python 中链表写法:python用类代表链表节点,val和next是这个类的两个属性。python中没有指针概念,next就是一个普通变量,它将记录指向对象的一个引用。
class ListNode:
	def __init__(self,val=0,next=None):
		self.val = val
		self.next = next

在这里插入图片描述

2. 删除元素(力扣203)

  1. 题目描述:移除元素
  2. 思路:如果不引入虚拟头结点,那么当要删除的对象在头结点时,需要对head单独操作。因此为了代码统一,引入虚拟头结点dummy_head。最终返回结果时,要返回dummy_head.next。
  3. Python 语法细节:
    在初始化一个类的时候,不传递参数时参数为构造函数中的默认值。
  4. Python 代码
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        dummy_head=ListNode(next=head)
        l = dummy_head
        while l.next:
            if l.next.val == val:
                l.next = l.next.next
            else:
                l=l.next

        return dummy_head.next
  1. C++语法细节:
  • 定义指针的写法:ListNode *next ,ListNode* dummy_head这里*的位置靠前或者靠后都可以。
    在这里插入图片描述
    在这里插入图片描述
  • new的用法:
    new 是 C++ 中用于动态分配内存并在堆上创建对象的运算符。它的用法是在需要动态创建对象时,使用 new 来分配内存,并调用对象的构造函数来初始化对象。通常情况下,new 运算符返回指向新分配对象的指针
    在这里插入图片描述
  1. C++ 代码
/**
 * 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) {
    /*用new在堆上创建一个头结点*/
        ListNode* dummy_head = new ListNode(0,head);
        ListNode* c = dummy_head;
        while (c->next != NULL){
            if (c->next->val == val){
                ListNode* tmp = c->next;
                c->next = c->next->next;
                delete tmp;
            }
            else{
                c=c->next;
            }
        }
        head = dummy_head->next;
        delete dummy_head;
        return head;


    }
};

3. 设计链表(力扣707)

  1. 题目描述:设计链表
  2. 思路:先定义链表的结点,再定义我的链表。用类来定义,类的成员包括虚拟表头和链表长度,因为类的一些方法需要判断index是否符合规范,所以需要有链表程度属性。
    3.python 语法细节:
  • 在类的方法中需要使用类的成员时,需要加上self.
  • 按索引进行插入时,插入是在指定位置index之前(注意链表索引从0开始),因此可以插入的位置包括最后一个元素的后面(也就是说index=size也是可以的,是插在了最后边),遍历指针l需要指向待插入位置的前一个。
  • 按索引进行删除时,删除的是index指定的位置,可以删除的位置不包括index=size,遍历指针l需要指向待删除位置的前一个
  • 按索引进行查找时,删除的是index指定的位置,可查找的位置不包括index=size,遍历指针就遍历到要查的位置(不是前一个,因此定义l的时候为l=self.dummy.next)
  1. Python代码
class ListNode:
    def __init__(self,val=0,next=None):
        self.val = val
        self.next = next

class MyLinkedList:

    def __init__(self):
        self.dummy_head = ListNode()
        self.size = 0
    def get(self, index: int) -> int:
    	# index不可以是size
        if index<0 or index>=self.size:
            return -1
        # l指向要查找的元素
        l = self.dummy_head.next
        for i in range(index):
            l = l.next
        return l.val


    def addAtHead(self, val: int) -> None:
        self.dummy_head.next = ListNode(val,self.dummy_head.next)
        self.size = self.size+1

    def addAtTail(self, val: int) -> None:
        l = self.dummy_head
        while l.next:
            l = l.next
        l.next = ListNode(val)
        self.size = self.size+1

    def addAtIndex(self, index: int, val: int) -> None:
    	#index可以是size
        if index<0 or index > self.size:
            print('index out of sixe')
            return
        else:
        #l遍历到待插入位置的前一个元素
            l = self.dummy_head
            for i in range(index):
                l = l.next
            l.next = ListNode(val,l.next)      
            self.size = self.size+1
            
    def deleteAtIndex(self, index: int) -> None:
    	#index不可以是size
        if index < 0 or index >= self.size:
            return
        #l指针遍历导要删除的位置的前一个
        l = self.dummy_head
        for i in range(index):
            l = l.next
        l.next = l.next.next
        self.size = self.size -1
  1. C++代码细节:
  • 链表节点的定义,使用在类中定义的结构体。结构体被定义在类的内部时,它们仅仅是类的一部分,而不是类的实例。这意味着每个类的实例都有一个嵌套的结构体类型,并且类的所有实例共享这个结构体定义。因此,结构体定义不会占用类的实例的存储空间。
  • 成员变量 dummy_head 是指向结构体ListNode 的指针,因此他**一定要写在结构体定义的后边!**否则就会报如下错误:
    在这里插入图片描述
  • 构造 函数MyLinkedList(),实现的是对类的成员的赋值。变量的赋值和变量的声明要有区分,此处不能再写 int size_ = 0 会识别为两个变量。
  • 空指针写法:nullptr
  • for 循环写法 for(int i =0;i<index;i++)注意 要写int 要写;
  • C++ 中不能只写return 要写返回值。
  1. C++实现 语法:
class MyLinkedList {
private:
    int size_;
    
public:

    struct ListNode{
    int val;
    ListNode* next;
    ListNode(int x):val(x),next(nullptr){}
    ListNode(int x,ListNode* next):val(x),next(next){}
};
    ListNode* dummy_head;

    MyLinkedList() {
        size_ =0;
        dummy_head = new ListNode(0);
    }
    
    int get(int index) {
        if((index <0) or (index >= size_)){
            return -1;
        }
        ListNode* cur = dummy_head->next;
        for(int i=0;i<index;i++){
            cur = cur->next;
        }
        return cur->val;


    }
    
    void addAtHead(int val) {
        dummy_head->next = new ListNode(val,dummy_head->next);
        size_++;
    }
    
    void addAtTail(int val) {
        ListNode* cur = dummy_head;
        while (cur->next != nullptr){
            cur = cur->next;
        }
        cur->next = new ListNode(val,nullptr);
        size_++;
    }
    
    void addAtIndex(int index, int val) {
        if((index <0) or (index >size_)){
            return;
        }
        ListNode* cur = dummy_head;
        for(int i=0;i<index;i++){
            cur = cur->next;
        }
        cur->next = new ListNode(val,cur->next);
        size_++;

    }
    
    void deleteAtIndex(int index) {
        if((index <0) or (index >=size_)){
            return;
        }
        ListNode* cur = dummy_head;
        for(int i=0;i<index;i++){
            cur = cur->next;
        }
        ListNode* tmp = cur->next;
        cur->next = cur->next->next;
        delete tmp;
        tmp = nullptr;
        size_--;
    }

};

4. 反转链表(力扣206)

  1. 题目描述:反转链表
  2. 思路:将每个节点的指针指向反转即可。使用pre 指针记录前一个节点,cur记录当前节点,tmp指针记录cur的下一个节点。
  3. python语法细节:
  • pre 指针在定义时不要新建一个节点,直接定义为None,需要的时候再让它指向cur
  1. Python代码
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        ### 双指针转向法
        # if head == None:
        #     return head
        # cur = head
        # pre = None
        # while cur :
        #     tmp = cur.next
        #     cur.next = pre
        #     pre = cur
        #     cur = tmp
        # cur = pre
        # while cur:
        #     print(cur.val)
        #     cur = cur.next
        # return pre
        ### 递归法
        return self.reverse(head,None)

    def reverse(self,cur:ListNode,pre:ListNode) ->ListNode:
        if cur == None:
            return pre
        tmp = cur.next
        cur.next = pre
        return self.reverse(tmp,cur)
  1. C++语法细节
  • 定义指针一定要初始化,不然会有问题,报错不容易察觉。
  1. C++代码
/**
 * 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 == nullptr){
        //     return head;
        // }
        // ListNode* cur;
        // ListNode* pre = nullptr;
        // cur = head;
        // while(cur != nullptr){
        //     ListNode* tmp = cur->next;
        //     cur->next = pre;
            
        //     pre = cur;
        //     cur = tmp;
        // }
        // cur = pre;
        // while(cur != nullptr){
        //     cout<<cur->val<<endl;
        //     cur = cur->next;
        // }
        // return pre;

        /*递归法*/
        ListNode* pre = nullptr;
        return reverse(head,pre);

    }
    ListNode* reverse(ListNode* cur,ListNode* pre) {
        if (cur == nullptr){
            return pre;
        }
        ListNode* tmp = cur->next ;
        cur->next = pre;
        return reverse(tmp,cur);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值