1. 程式人生 > 其它 >(十二)連結串列(C++實現)

(十二)連結串列(C++實現)

演算法與資料結構刷題系列之連結串列,僅記錄個人刷題總結記錄,方便複習。

反轉連結串列

leetcode 206:https://leetcode-cn.com/problems/reverse-linked-list/
nowcoder NC76:https://www.nowcoder.com/practice/75e878df47f24fdc9dc3e400ec6058ca?tpId=188&&tqId=38547

1.問題描述

給定單鏈表的頭節點head,反轉連結串列。

2.輸入輸出

  • Input:head = [1, 2, 3, 4, 5]
  • Output:[5, 4, 3, 2, 1]

3.演算法分析

  1. 迭代法:1)實現儲存前一個節點;2)通過當前指標遍歷連結串列;3)儲存後一個節點;4)將當前節點的next指標改為指向前一個節點。5)最後返回新的頭引用——前一個節點。
    • 時間複雜度:O(n)
    • 空間複雜度:O(1)
  2. 遞迴法:
    • 遞迴終止條件:連結串列只剩最後一個節點或者已經為空(最後一個節點就是反轉後的頭節點)
    • 處理:讓當前節點的下一格節點的next指標指向當前節點,且當前節點的next指向NULL,實現連結串列尾部開始的區域性反轉
      • 時間複雜度:O(n)
      • 空間複雜度:O(n)

4.程式設計實現

#include <iostream>
using namespace std;

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* reverseList1(ListNode* head) {  
        // 迭代法 1->2->3->Ø變成Ø->3->2-1
        ListNode* prev = nullptr;
        ListNode* curr = head;
        
        while (curr) {
            ListNode* nxt = curr->next;
            curr->next = prev;
            prev = curr;
            curr = nxt;
        }
        
        return prev;
    }
    
    ListNode* reverseList2(ListNode* head){
        // 遞迴法 1->2->3->Ø變成Ø->3->2-1
        if (!head || !head->next) return head;
        ListNode *newHead = reverseList2(head->next);
        head->next->next = head;
        head->next = nullptr;
        return newHead;
    }
};

int main() {
    Solution sol;
    ListNode* head = new ListNode(), *now = head;  
    int val;
    
    getchar();
    while (cin >> val) {
        now->next = new ListNode(val);
        now = now->next;
        if (cin.get() == ']') break;
    }
    
    
    now = sol.reverseList1(head->next);
    cout << "[";
    while (now) {
        cout << now->val;
        if (now->next) {
            cout << ",";
        } else {
            cout << "]";
        }
        now = now->next;
    }
    
    return 0;
}

k個一組翻轉連結串列

Leetcode:https://leetcode-cn.com/problems/reverse-nodes-in-k-group/

1.問題描述

給定一個連結串列,每k個節點一組進行翻轉,返回翻轉後的連結串列。(k是一個正整數,它的值小於或等於連結串列的長度,如果節點總數不是k的整數倍,將最後剩餘的節點保持原有順序)

2.輸入輸出

  • Input:head=[1, 2, 3, 4, 5],k=2
  • Output:[2,1,4,3,5]

3.演算法分析

先計算以下長度,再根據需要翻轉的段數進行遍歷。

4.程式設計實現

// #include <bits/stdc++.h>
#include <iostream>
using namespace std;

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* reverseKGroup(ListNode *head, int k) {
        ListNode *dummy = new ListNode(0), *prev = dummy, *curr = head, *nextNode;
        dummy->next = head;
        
        int length = 0;
        while (head) {
            length++;
            head = head->next;
        }
        
        for (int i = 0; i < length / k; i++) {
            for (int j = 0; j < k-1; j++) {
                nextNode = curr->next;
                curr->next = nextNode->next;
                nextNode->next = prev->next;
                prev->next = nextNode;
            }
            prev = curr;
            curr = prev->next;
        }
        
        return dummy->next;
    }
};

int main(){
    Solution sol;
    ListNode *head = new ListNode(0), *fake = head;
    int val, k;
    char ch;
    
    getchar();
    while (cin >> val) {
        fake->next = new ListNode(val);
        fake = fake->next;
        if (cin.get() == ']') break;
    }
    cin >> k;
    ListNode *newNode = sol.reverseKGroup(head->next, k);
    while (newNode) {
        cout << newNode->val;
        if (newNode->next) {
            cout << ",";
        } else {
            cout << "";
        }
        newNode = newNode->next;
    }
    return 0;
}

合併兩個有序連結串列

Leetcode:https://leetcode-cn.com/problems/merge-two-sorted-lists/

1.問題描述

​ 將兩個升序連結串列合併成一個新的升序連結串列並返回。新連結串列是通過拼接給定的兩個連結串列的所有節點組成的。

2.輸入輸出

  • Input:l1=[1, 2, 4],l2=[1, 3, 4]
  • Output:[1, 1, 2, 3, 4, 4]

3.演算法分析

​ 迭代法:當l1和l2都不是空連結串列時,判斷l1和l2哪一個連結串列的頭節點的值更小,將較小值得節點新增到結果裡,當一個節點被新增到結果裡之後,將對應連結串列的節點後移一位。

  • 時間複雜度:O(n+m)
  • 空間複雜度:O(1)

4.程式設計實現

#include <iostream>
using namespace std;

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:
    // 1->2->3->Ø變成Ø->3->2-1
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* preHead = new ListNode(-1);
        ListNode* prev = preHead;
        
        while (l1  && l2 ) {
            if (l1->val < l2->val) {
                prev->next = l1;
                l1 = l1->next;
            } else {
                prev->next = l2;
                l2 = l2->next;
            }
            prev = prev->next;
        }
        
        // 合併後l1和l2最多還有一個還未被合併完,直接將連結串列末尾指向未合併完的連結串列即可。
        prev->next = l1 == nullptr? l2 : l1;
        
        return preHead->next;
    }
};

int main() {
    Solution sol;
    ListNode* l1 = new ListNode(1);  
    l1->next = new ListNode(2);  
    l1->next->next = new ListNode(4);  
    
    ListNode* l2 = new ListNode(1);  
    l2->next = new ListNode(3);  
    l2->next->next = new ListNode(4);  
    
    ListNode* newHead = sol.mergeTwoLists(l1, l2);
    while (newHead) {
        cout << newHead->val << " ";
        newHead = newHead->next;
    }
    return 0;
}
本文為博主原創文章,未經博主允許禁止轉載,需轉載請註明出處,歡迎指正!