链表+删除元素+设计链表+反转链表+交换链表节点

1定义:链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。

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;
class ListNode:
def __init__(self,val,next=None):
    self.val = val
    self.next = next

mysql的索引原理B+Tree也是这样叶子节点不仅包括了数据还有索引值。

单链表:

双链表:也就是包含两个指针可以指向上下两个节点,可以实现前后查询。

循环链表:很明显就是链表首尾相连成了一个环。

2.存储方式

数组在内存中是连续分布的,(二维在java不是)

链表在内存中不是连续分布的,由其存储的下一个节点的指针就可以看出来,是离散分布的。

想要删除节点,其实也很好理解,就是将上一个节点的指针指向要删除节点 的下一个节点的地址,就实现了删除。注:对于C++而言由于是new出来的所以最好是delete掉,python语言有自己的内存回收机制。

添加节点也很好理解,就是将当前节点的指针指向要添加的节点,然后这个要添加节点的指针指向原本下一个节点的地址。

添加和删除都是O(1),但是查找是O(n)

1.移除链表元素

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;
    }
};
class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        dummyHead = ListNode(val =0)
        dummyHead.next = head
        cur = dummyHead
        while(cur.next is not None):
            if cur.next.val == val:
                tmp = cur.next
                cur.next = cur.next.next
            else:
                cur = cur.next # 还是需要遍历下去
        head = dummyHead.next
        return head    

2.设计链表(注意:index从0开始)

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* new_head = new LinkedNode(val);
        new_head->next = _dummyHead->next;
        _dummyHead->next = new_head;
        _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<0) index = 0;
        if(index>_size) return;
        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--;}

// 打印链表
    void printLinkedList() {
        LinkedNode* cur = _dummyHead;
        while (cur->next != nullptr) {
            cout << cur->next->val << " ";
            cur = cur->next;
        }
        cout << endl;
    }
private:
    int _size;
    LinkedNode* _dummyHead;
};
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:
        if index < 0 or index >= self.size:
            return -1
        
        cur = self.dummy_head.next
        for i in range(index):
            cur = cur.next
        if cur == None:
            return -1
        return cur.val

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

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

    def addAtIndex(self, index: int, val: int) -> None:
        if index < 0 or index > self.size:
            return
        
        current = self.dummy_head
        for i in range(index):
            current = current.next
        current.next = ListNode(val, current.next)
        self.size += 1
            

    def deleteAtIndex(self, index: int) -> None:
        if index < 0 or index >=self.size:
            pass
        else:
            cur = self.dummy_head
            for i in range(index):
                cur = cur.next
            cur.next = cur.next.next
            self.size -= 1

用python注意点还是比较多的,首先是get方法考虑cur==None

其次就是add和delete方法中index这个等于号要注意,由于index从0开始,对于add而言要想加在最后必须index==self.size,对于delete而言正常是self.size = index -1,如果是self.size=index那么已经超出了范围。

反转链表

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* temp;
        ListNode* cur = head;
        ListNode* pre = NULL;
        while(cur){
            temp = cur->next;
            cur->next = pre;
            pre = cur;
            cur = temp;
        }
        return pre;
    }
};

这个就比较好理解:先用一个pre占位,存储cur节点的下一个节点,将cur节点的下一个节点变成pre(这一步实现反转),之后pre赋值cur,再将temp赋给cur实现遍历。

class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        cur = head
        pre = None

        while(cur):
            temp = cur.next
            cur.next = pre
            pre = cur
            cur = temp
        return pre

 交换链表两两节点:题目还是有点歧义的,并不是不断作相邻交换,而是两个两个一组交换,所以cur = cur->next->next而不是cur=cur->next.

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummy_head = new ListNode();
        dummy_head->next = head;
        ListNode* cur = dummy_head;
        while(cur->next != nullptr && cur->next->next != nullptr){
            ListNode* tmp = cur->next;
            ListNode* tmp1 = cur->next->next->next;
            cur->next = cur->next->next;
            cur->next->next = tmp;
            cur->next->next->next = tmp1;
            cur = cur->next->next;
        }
        ListNode* result = dummy_head->next;
        delete dummy_head;
        return result;
    }
};

class Solution:
    def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
        dummyhead = ListNode()
        dummyhead.next = head
        cur = dummyhead
        while(cur.next != None and cur.next.next != None):
            # 由于虚拟头的下一个节点是后面第二个节点,所以第一个节点要保存,
            # 第二个节点的下一个节点也要保存
            tmp = cur.next 
            tmp1 = cur.next.next.next
            # 开始进行交换
            cur.next = cur.next.next
            cur.next.next = tmp
            cur.next.next.next = tmp1
            # 移动cur
            cur = cur.next.next
        return dummyhead.next

删除链表倒数第n个元素,由于不知道链表到底有多少个元素,所以需要使用双指针,一个快指针一直走到链表结束,另一个慢指针距离链表n+1,当快指针结束时慢指针正好走到倒数第n个元素的前一个。这样就实现了找到,之后删除就是前面的将下一个节点的指针换成下下个节点的指针即可。

class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        dummyhead = ListNode()
        dummyhead.next = head
        cur = dummyhead
        slow = cur
        fast = cur
        for i in range(n+1):
            fast = fast.next
        while(fast != None):
            fast = fast.next
            slow = slow.next
        slow.next = slow.next.next
        
        return dummyhead.next
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyhead = new ListNode();
        dummyhead->next = head;
        ListNode* slow = dummyhead;
        ListNode* fast = dummyhead;
        for(int i=0;i<n+1;i++){
            fast = fast->next;
        }
        while(fast != NULL){
            fast = fast->next;
            slow = slow->next;
        }
        slow->next = slow->next->next;
        return dummyhead->next;
    }
};

链表相交 

对示例1:

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'

有点疑问,为什么不是在1相交

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        lenA = 0
        lenB = 0
        curA = headA
        curB = headB
        while(curA):
            lenA += 1
            curA = curA.next
        while(curB):
            lenB += 1
            curB = curB.next
        
        curA = headA
        curB = headB
        if(lenA<lenB):
            lenA, lenB = lenB, lenA
            curA, curB = curB, curA
        
        gap = lenA-lenB

        for i in range(gap):
            curA = curA.next
        while(curA):
            if(curA==curB):
                return curA
            else:
                curA = curA.next
                curB = curB.next
        return None

环形链表

class Solution(
public:
    ListNode *detectCycle(ListNode *head){
        ListNode* fast = head;
        ListNode* slow= head;
        while(fast!=NULL && fast->next!=NULL){
            fast = fast->next->next;
            slow = slow->next;
            if(slow==fast){
                ListNode* con = fast;
                slow = head;
                while(slow!=con){
                    slow = slow->next;
                    con = con->next;
                }
                   return con;
             }
               return NULL;
    }
};
            
            

主要还是前期分析,首先 先找到相遇的点,之后通过分析可以知道慢指针一定在入环的第一圈就被追上,所以根据等式可以得到x=z,那么从起点和相遇点开始走,相等的那个点就是入环点。

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值