cen's blog cen's blog
首页
  • 编程文章

    • markdown使用
  • 学习笔记

    • 《JavaScript教程》
    • C++学习
    • C++数据结构
    • MySQL
    • Linux
  • 高中时代
  • 工作日常
  • CLion
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 分类
  • 标签
  • 归档
关于
GitHub (opens new window)

cen

十年饮冰,难凉热血
首页
  • 编程文章

    • markdown使用
  • 学习笔记

    • 《JavaScript教程》
    • C++学习
    • C++数据结构
    • MySQL
    • Linux
  • 高中时代
  • 工作日常
  • CLion
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 分类
  • 标签
  • 归档
关于
GitHub (opens new window)
  • 链表
    • 链表
    • 单链表的实现
    • 链表算法题
      • 移除链表元素
      • 反转链表
      • 相交链表
      • 交换链表
      • 合并两个有序链表
  • 栈和队列
  • 二叉树
  • 堆
  • 排序
  • 搜索二叉树
  • 平衡二叉树
  • 红黑树
  • 哈希表
  • C++数据结构
cen
2024-10-30
目录

链表

# 链表

链表(linked list)是一种线性数据结构,其中的每个元素都是一个节点对象,各个节点通过指针相连接。指针记录了下一个节点的内存地址,通过它可以从当前节点访问到下一个节点。

链表的设计使得各个节点可以分散存储在内存各处,它们的内存地址无须连续。

单链表图解

# 单链表的实现

template<class T>
class SLList {
public:
    // 构造函数
    SLList() : head(nullptr) {}

    // 打印链表元素
    void printSLList();

    // 增删成员函数
    // 尾插
    void push_back(T t);

    // 前插
    void push_front(T t);

    // 尾删
    void pop_back();

    // 前删
    void pop_front();

    // 在第一个指定位置后插入一个数据(后插)
    void insert(T pos, T t);

    // 在第一个指定位置删除一个数据
    void erase(T pos);

    // 析构函数
    ~SLList() {
        ListNode *node = head;
        while (node != nullptr) {
            ListNode *temp = node->next;
            delete node;
            node = temp;
        }
    }

    class ListNode {
    public:
        ListNode *next; // 指针域
        T data;         // 数据域
        ListNode(T x) : next(nullptr), data(x) {}
    };

    void append(SLList<T> &l) {
        if (!l.head) return; // 如果l为空,则什么也不做
        // 找到当前链表的最后一个节点
        ListNode *node = head;

        while (node->next != nullptr) {
            node = node->next;
        }
        // 将当前链表的最后一个节点的下一个指向l的第一个节点
        node->next = l.head;
    }

private:
    ListNode *head;
};

template<class T>
void SLList<T>::printSLList() {
    ListNode *node = head;
    while (node != nullptr) {
        cout << node->data << " -> ";
        node = node->next;
    }
    cout << "nullptr";
}

template<class T>
void SLList<T>::push_back(T t) {
    ListNode *node = head;
    ListNode *newnode = new ListNode(t);
    // 检查头节点是否为空
    // 头节点为空
    if (node == nullptr)
        head = newnode;
        // 头节点非空
    else {
        while (node->next != nullptr) {
            node = node->next;
        }
        node->next = newnode;
    }
}

template<class T>
void SLList<T>::push_front(T t) {
    // 与尾插类似
    ListNode *node = head;
    ListNode *newnode = new ListNode(t);
    if (head != nullptr) {
        newnode->next = node;
    }
    head = newnode;
}

template<class T>
void SLList<T>::pop_back() {
    ListNode *node = head;
    if (node == nullptr || node->next == nullptr) {
        head = nullptr;
        return;
    }
    while (node->next->next != nullptr) {
        node = node->next;
    }
    delete node->next;
    node->next = nullptr;
}

template<class T>
void SLList<T>::pop_front() {
    ListNode *node = head;
    if (node == nullptr || node->next == nullptr) {
        head = nullptr;
        return;
    }
    head = head->next;
    delete node;
}

template<class T>
void SLList<T>::insert(T pos, T t) {
    ListNode *node = head;
    ListNode *newnode = new ListNode(t);
    if (head == nullptr)
        return;
    if (head->data == pos) {
        newnode->next = head->next;
        head->next = newnode;
        return;
    }
    while (node->next != nullptr) {
        node = node->next;
        if (node->data == pos)
            break;
    }
    newnode->next = node->next;
    node->next = newnode;
}

template<class T>
void SLList<T>::erase(T pos) {
    // 指定位置数据
    ListNode *node = head;
    if (head == nullptr || head->data == pos)
        return;
    while (node->next->next != nullptr) {
        node = node->next;
        if (node->next->data == pos)
            break;
    }
    ListNode *tempnode = node->next;
    node->next = tempnode->next;
    delete tempnode;
}


void testSLList() {
    SLList<int> slList;
    // slList.push_back(100);
    // slList.push_back(200);
    slList.push_back(999);
    slList.push_back(888);
    slList.push_back(777);
    slList.insert(999, 666);
    // 999 -> 666 -> 888 -> 777 -> nullptr
    slList.erase(888);
    SLList<int> l;
    l.push_back(1222);
    l.push_back(123);
    l.push_back(12222);
    l.push_back(3333);
    slList.append(l);
    slList.printSLList();

}
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180

# 链表算法题

# 移除链表元素

描述:给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

  • 未设置哨兵位dummy
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        // 特殊情况1:头指针为空
        if (head == nullptr)
            return head;
        // 特殊情况2:头指针为连续的目标移除元素
        while (head != nullptr && head->val == val) {
            head = head->next;
        }
        // 规范化:cur,prev,next;
        ListNode* prev = nullptr;
        ListNode* cur = head;
        // 先考虑常规情况:
        while (cur != nullptr) {
            if (cur->val == val) {
                prev->next = cur->next;
                cur = prev->next;
            } else {
                prev = cur;
                cur = cur->next;
            }
        }
        return head;
    }
};
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
  • 设置哨兵位
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        // 增加虚拟头节点(哨兵位)
        ListNode* dummy = new ListNode(0, head);
        ListNode* prev = dummy;
        while (prev->next != nullptr) {
            if (prev->next->val == val)
                prev->next = prev->next->next;
            else
                prev = prev->next;
        }
        return dummy->next;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 反转链表

描述:给你单链表的头节点 head ,请你反转链表,并返回反转后的链表的头节点

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* prev = nullptr;
        ListNode* cur = head;
        while (cur != nullptr) {
            ListNode* temp = cur->next;
            cur->next = prev;
            prev = cur;
            cur = temp;
        }
        return prev;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 相交链表

描述:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

  • 常规思路
class Solution {
public:
    ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
        ListNode* head1 = headA;
        ListNode* head2 = headB;
        int count1 = 0;
        int count2 = 0;
        while (head1) {
            head1 = head1->next;
            count1++;
        }
        while (head2) {
            head2 = head2->next;
            count2++;
        }
        // headA 比 headB 长
        if (count1 > count2) {
            for (int i = 0; i < count1 - count2; i++)
                headA = headA->next;
        } else if (count1 < count2) {
            for (int i = 0; i < count2 - count1; i++)
                headB = headB->next;
        }
        while (headA != nullptr) {
            if (headA == headB)
                return headA;
            else {
                headA = headA->next;
                headB = headB->next;
            }
        }
        return nullptr;
    }
};
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
  • 快慢指针

与判断链表中是否有环的思路相似

class Solution {
public:
    ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
        if (!headA || !headB) {
            return nullptr;
        }
        ListNode* head1 = headA;
        ListNode* head2 = headB;
        while (head1 != head2) {
            head1 = head1 == nullptr ? headB : head1->next;
            head2 = head2 == nullptr ? headA : head2->next;
        }
        return head1;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 交换链表

描述:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummy = new ListNode(0, head);
        ListNode* cur = dummy;

        while (cur->next != nullptr && cur->next->next != nullptr) {
            ListNode* temp1 = cur->next;
            ListNode* temp2 = temp1->next->next;
            cur->next = temp1->next;
            temp1->next->next = temp1;
            temp1->next = temp2;
            cur = cur->next->next;
        }
        return dummy->next;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 合并两个有序链表

描述:将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        if (!list1 || !list2)
            return list1 == nullptr ? list2 : list1;
        ListNode* dummy = new ListNode(0);
        ListNode* cur = dummy;
        ListNode* cur1 = list1;
        ListNode* cur2 = list2;
        while (cur1 != nullptr && cur2 != nullptr) {
            if (cur1->val < cur2->val) {
                cur->next = cur1;
                cur1 = cur1->next;
            } else {
                cur->next = cur2;
                cur2 = cur2->next;
            }
            cur = cur->next;
        }
        cur->next = cur1 != nullptr ? cur1 : cur2;
        return dummy->next;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# from cen


#笔记
上次更新: 2025/01/15, 18:13:42
栈和队列

栈和队列→

最近更新
01
线程安全
05-21
02
cmake教程
05-08
03
项目
05-07
更多文章>
Theme by Vdoing | Copyright © 2024-2025 京ICP备2020044002号-3 京公网安备11010502056119号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式