DAY3 链表的理论基础+Leetcode203移除链表元素+Leetcode707设计链表+Leetcode206反转链表

文章链接:代码随想录

链表的类型:单链表 、双链表、循环链表。链表时通过指针域的指针链接再内存中的各个节点。

链表的定义:其实相当于一个数据结构(打包两个值),分别是当前节点的值,和下一个元素的地址。

C++:

// 单链表
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:

class ListNode:
    def __init__(self, val, next = None):
        self.val = val
        self.next = next

链表的操作:删除节点、添加节点

203. 移除链表元素

题目要求:删除链表中等于给定值val的所有节点。注意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* removeElements(ListNode* head, int val) {
        // Delete header node
        while (head != NULL && head -> val == val) {
            ListNode* tmp = head;
            head = head -> next; // address
            delete tmp;
        }

        // Delete Nonheader node
        ListNode* cur = head;
        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; // 更新cur
            }
        }
        return head;
    }
};

在删除非头节点时,实际上是考察,头节点的下一个节点是否需要删除,如果需要删除只需要把头节点的next指向next->next即可。然后再把旧的头节点的next删除掉。后续一直在更新的是cur,而我们的头节点没有改变。

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) {
        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;
    }
};

在头节点前面新建一个node,指向头节点。

Python:

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def removeElements(self, head, val):
        """
        :type head: ListNode
        :type val: int
        :rtype: ListNode
        """
        dummyhead = ListNode(next = head)

        cur = dummyhead
        while cur.next:
            if cur.next.val == val:
                cur.next = cur.next.next
            else:
                cur = cur.next
        return dummyhead.next

707. 设计链表

题目要求:实现链表的一些功能

如果比较熟悉C++中类与对象的关系,我觉得这道题还是比较好实现的。在初始情况下我并没有一个链表,我只有一个_dummyhead初始值为0,指向nullptr。

C++:

class MyLinkedList {
public:
    // 定义链表节点结构体
    struct LinkedNode{
        int val;
        LinkedNode *next;
        LinkedNode(int val) : val(val), next(nullptr){}
    };
private:
    int _size;
    LinkedNode* _dummyhead;
public:
    // 初始化链表
    MyLinkedList() {
        _dummyhead = new LinkedNode(0);
        _size = 0;
    }
    
    // 返回index节点值,如果非法则返回-1
    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;
        // delete后的tmp并非NULL而是随即量,会成为野指针指向不知名内存空间。
        tmp = nullptr;
        _size--;
    }

    void printLinkedList(){
        LinkedNode* cur = _dummyhead;
        while(cur->next!=nullptr) {
            cout << cur->next->val << " "; 
            cur = cur->next;
        }
        cout << endl;
    }
};

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

Python(双向链表法):

class ListNode:
    def __init__(self, val=0, prev=None, next=None):
        self.val = val
        self.prev = prev
        self.next = next

class MyLinkedList(object):

    def __init__(self):
        self.head = None
        self.tail = None
        self.size = 0
        

    def get(self, index):
        """
        :type index: int
        :rtype: int
        """
        if index < 0 or index >= self.size:
            return -1

        if index < self.size//2:
            cur = self.head
            for i in range(index):
                cur = cur.next
        else:
            cur = self.tail
            for i in range(self.size - index - 1):
                cur = cur.prev
        return cur.val
        
    def addAtHead(self, val):
        """
        :type val: int
        :rtype: None
        """
        newNode = ListNode(val, None, self.head)
        if self.head:
            self.head.prev = newNode
        else:
            self.tail = newNode
        self.head = newNode
        self.size += 1

    def addAtTail(self, val):
        """
        :type val: int
        :rtype: None
        """
        newNode = ListNode(val, self.tail, None)
        if self.tail:
            self.tail.next = newNode
        else:
            self.head = newNode
        self.tail = newNode
        self.size += 1

    def addAtIndex(self, index, val):
        """
        :type index: int
        :type val: int
        :rtype: None
        """
        if index < 0 or index > self.size:
            return
        if index == 0:
            self.addAtHead(val)
        else:
            if index < self.size // 2:
                cur = self.head
                for i in range(index - 1):
                    cur = cur.next
            else:
                cur = self.tail
                for i in range(self.size - index):
                    cur = cur.prev
            newNode = ListNode(val, cur, cur.next)
            if cur.next:
                cur.next.prev = newNode
            else:
                self.tail = newNode
            cur.next = newNode
            self.size += 1

    def deleteAtIndex(self, index):
        """
        :type index: int
        :rtype: None
        """
        if index < 0 or index >= self.size:
            return
        if index == 0:
            self.head = self.head.next
            if self.head:
                self.head.prev = None
            else:
                self.tail = None
        elif index == self.size - 1:
            self.tail = self.tail.prev
            if self.tail:
                self.tail.next = None
            else:
                self.head = None
        else:
            if index < self.size // 2:
                cur = self.head
                for i in range(index):
                    cur = cur.next
            else:
                cur = self.tail
                for i in range(self.size - index - 1):
                    cur = cur.prev
            cur.prev.next = cur.next
            cur.next.prev = cur.prev
        self.size -= 1


# Your MyLinkedList object will be instantiated and called as such:
# obj = MyLinkedList()
# param_1 = obj.get(index)
# obj.addAtHead(val)
# obj.addAtTail(val)
# obj.addAtIndex(index,val)
# obj.deleteAtIndex(index)

这里涉及很多head、tail是否存在的边界问题,需要注意并处理。

206. 反转链表

题目要求:反转一个单链表。

改变链表next的方向,直接将单链表反转。

C++(双指针法,定义一个cur指针存储当前状态,把cur的next指向pre,需要一个tmp暂存cur->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* reverseList(ListNode* head) {
        ListNode* tmp;
        ListNode* cur = head;
        ListNode* pre = NULL;
        while(cur){
            tmp = cur->next;
            cur->next = pre;
            pre = cur;
            cur = tmp;
        }
        return pre;
    }
};

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* reverse(ListNode* pre, ListNode* cur){
        if(cur == NULL) return pre;
        ListNode* tmp = cur->next;
        cur->next = pre;
        return reverse(cur, tmp);
    }
    ListNode* reverseList(ListNode* head) {
        return reverse(NULL, head);
    }
};

C++(递归法2):

/**
 * 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) return NULL;
        if(head->next == NULL) return head;
        ListNode* last = reverseList(head->next);//把head->next作为新的头节点
        head->next->next = head;
        head->next = NULL;
        return last;
    }
};

Python(双指针法):

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        cur = head
        pre = None
        while cur:
            tmp = cur.next
            cur.next = pre
            pre = cur
            cur = tmp
        return pre
            

Python(递归法):

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def reverse(self, cur, pre):
        if cur == None:
            return pre
        tmp = cur.next
        cur.next = pre
        return self.reverse(tmp, cur)
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        return self.reverse(head, None)

要注意分清哪个是cur状态,哪个是pre状态,什么应该被存储在tmp状态中。

你可能感兴趣的:(链表,数据结构,leetcode,算法,c++,python)