单链表算法的 C++ 11 实现,代码中包含注释。先实现一个简单的链表类,只包含必要的操作:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <algorithm>
using namespace std;

class ListNode {
public:
    int value;
    ListNode* next;
    ListNode(int _value) { value = _value; next = nullptr; }
};

class SingleList {
public:
    ListNode* head;
    SingleList() { head = nullptr; }
    ~SingleList() { Clear(); }
    void Print() const {
        ListNode* temp = head;
        while (temp != nullptr) {
            cout << temp->value << " ";
            temp = temp->next;
        }
        cout << endl;
    }
    void Clear() {
        ListNode* next;
        while (head != nullptr) {
            next = head->next;
            delete head;
            head = next;
        }
    }
    ListNode* GetTailNode() {
        ListNode* tail = head;
        if (tail != nullptr) {
            while (tail->next != nullptr) {
                tail = tail->next;
            }
        }
        return tail;
    }
    void Insert_Back(int value) {
        ListNode* node = new ListNode(value);
        ListNode* tail = GetTailNode();
        if (tail == nullptr) {
            head = node;
            head->next = nullptr;
        } else {
            tail->next = node;
        }
    }
};

判断单链表是否有环

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// 判断单链表是否有环
// 由于不确定尾节点指向哪个节点,所以不能拿尾节点和头节点比较
// 一种O(n)的办法是:定义两个指针,一个每次递增一步,一个每次递增两步,如果有环,两者必然重合
bool IsSingleListHasLoop(ListNode* head)
{
    if (head == nullptr)
        return false;
    ListNode* first = head;
    ListNode* second = head->next;
    // 第二个指针递增的快,所以只需要判断第二个指针是否为空
    while (second != nullptr && second->next != nullptr) {
        first = first->next;
        second = second->next->next;
        if (first == second)
            return true;
    }
    return false;
}

翻转单链表

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 翻转单链表,返回头节点
ListNode* ReverseSingleList(ListNode* head)
{
    if (head == nullptr)
        return head;
    ListNode* prev = nullptr;
    ListNode* current = head;
    ListNode* next = current->next;
    while (next != nullptr) {
        current->next = prev;
        prev = current;
        current = next;
        next = current->next;
    }
    current->next = prev;
    return current;
}

// 翻转单链表,返回头节点,区别于上一种写法
ListNode* SingleListReverse(ListNode* head)
{
    ListNode* prev = nullptr;
    ListNode* current = head;
    ListNode* next = nullptr;
    while (current != nullptr) {
        next = current->next;
        current->next = prev;
        prev = current;
        current = next;
    }
    return prev;
}

求链表中倒数第k个节点

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// 求链表中倒数第k个节点
ListNode* GetNodeFromTail(ListNode* head, int k)
{
    if (k <= 0) return nullptr;
    // 定义两个指针,使其差距为K,然后遍历到尾节点
    ListNode* knode = nullptr;
    ListNode* current = head;
    int count = 0;
    while (current != nullptr) {
        current = current->next;
        count++;
        if (count == k) {
            knode = head;
        } else if (count > k) {
            knode = knode->next;
        }
    }
    return knode;
}

从尾到头打印链表

1
2
3
4
5
6
7
8
// 从尾到头打印链表
// 非递归的方法需要把遍历的数据存到栈中
void PrintList(ListNode* head) {
    if (head != nullptr) {
        PrintList(head->next);
        cout << head->value << " ";
    }
}