单链表
其实可以简单的理解为数组,但只要用的好,实际功能是远远大于数组的,再此次文章中,我们暂且可以简单理解为数组,但不要被误导,两者实际上还有很多的不同(比如说数组的随机访问时间复杂度为O(1)而单链表为O(n)等等等等)
举个简单的链表
list = [ 1, 2, 3, 4, 5] // 我们可以将其画出来,就像这样
1 -> 2 -> 3 -> 4 -> 5 //这里的每个数组就是链表的节点并通过 " -> " 串在了一起
意思也就是说,我们只要能将一些零零散散的节点像烤串一样串在一起,那么就是实现了一个简单的链表
算法逻辑
第一步(节点)
节点中需要存放数据,并且要利用指针访问
class Node
{
public:
int data;
Node* next;
};
第二步(连接链表)
链表的链接与节点数据的存放是辩证统一的,两者缺一不可。
一个最基础的链表,至少具有插入元素和输出元素的功能,不过在此我也会实现链表的一些其他功能(随机访问,随机插入,排序等等等等)
链表功能
插入节点
表尾插入
意思就是说,我们将从头开始遍历链表(链表头号元素不为空的时候),持续遍历到不存在下一个节点为止,当程序发现不存在下一个节点时,在此处插入新的节点
void insert(int data)
{
Node* new_node = new Node();
new_node->data = data;
new_node->next = nullptr;
if (head == nullptr)
{
head = new_node;
}
else {
Node* current = head;
while (current->next != nullptr)
{
current = current->next;
}
current->next = new_node;
}
}
随机插入
和上述方法类似,也会从头开始遍历链表,但不会一直遍历到表尾(除非插入位置的值大于链表的长度),当遍历链表直至num的位置时插入新的节点
num = 我们需要插入元素的位置,并在此位置的左侧插入新的节点
void rand_insert(int num, int data)
{
Node* new_node = new Node();
new_node->data = data;
new_node->next = nullptr;
if (head == nullptr)
{
head = new_node;
}
else
{
Node* current = head;
int count = 0;
while (current->next != nullptr && count < num)
{
current = current->next;
count++;
}
if (current->next != nullptr)
{
new_node->next = current->next;
current->next = new_node;
}
else {
current->next = new_node;
}
}
}
这里着重说明一些核心代码
new_node->next = current->next
这一行将新节点的下一个节点指向当前节点的下一个节点。这样做的目的是在当前节点和它的下一个节点之间插入新节点,使得新节点成为当前节点的下一个节点。
current->next = new_node
这一行将当前节点的下一个节点更新为新节点。这样,新节点就被正确地插入到了链表中
输出链表
或许看到这里你也已经明白怎么输出链表了,还是跟上述插入节点一样,从表头开始遍历链表,每遍历完一个节点就输出这个节点的值即可
void display()
{
if (head == nullptr)
{
return;
}
else
{
Node* current = head;
while (current->next != nullptr)
{
cout << current->data << "->";
current = current->next;
}
cout << current->data << endl;
}
}
删除节点
有链表的插入那么也就有节点的删除,这里将通过访问链表中节点的位置来删除节点,就跟数组类似,访问到目标节点时停止遍历,使指向该节点的指针指向下一个节点,从而“跳过”此节点直接访问下一个节点
void delete_node(int num)
{
if (head == nullptr)
{
return;
}
else
{
if (num == 0)
{
Node* temp = head;
head = head->next;
delete temp;
return;
}
Node* current = head;
int count = 0;
while (count < num - 1)
{
current = current->next;
count++;
}
Node* temp = current->next;
current->next = current->next->next;
delete temp;
}
}
返回链表长度
无需多元,从头开始遍历,设定一个计数器count使每遍历完一个节点进行count += 1 的操作,最后返回的count的值即为链表的长度
int len()
{
if (head == nullptr)
{
return 0;
}
else
{
Node* current = head;
int count = 1;
while (current->next != nullptr)
{
current = current->next;
count++;
}
return count;
}
}
随机访问
位置访问
跟数组一样,在下表上写上链表中元素的位置,程序就会给你返回此位置元素的值,原理还是跟上述方法一样,从头开始遍历,直至遍历到num时停止并返回此时遍历到的元素的值即可
num = 需要访问的元素的位置
int value(int num)
{
if (head == nullptr)
{
return -1;
}
else
{
Node* current = head;
int count = 0;
while (count < num)
{
current = current->next;
count++;
}
return current->data;
}
}
查找元素
给定一个数,查看链表中是否有这个数。
一般情况下我们可以通过遍历链表来实现,这是最无脑且有效的办法,但如果题目中有一些特殊情况,比如已排序的链表之类的话,那么我们可以用二分查找等方式降低程序的时间复杂的
不过遍历链表查找元素的时间复杂度也不高,为O(n)
num = 我们要查找的元素的值
void get(int num)
{
if (head == nullptr)
{
return;
}
else
{
for (int i = 0; i < len(); i++)
{
if (value(i) == num)
{
cout << "找到元素" << num << ",其位置为" << i << endl;
return;
}
}
cout << "链表中不存在该元素" << endl;
}
}
链表的排序
就跟数组的排序一样,根据链表中节点的值或者一些其他要求进行排序,这里以冒泡排序为例,不过冒泡排序是一个时间复杂度相对较高O(n**2)的排序方式,也是最简单通俗易懂的排序方式,在此不会多讲,博主会在下一期文章中专门讲11中不同的排序方式。
链表排序的底层逻辑就是节点内数据的交换,至于怎么交换,那么就取决于使用了什么样的排序方式了
void bubble_sort()
{
if (head == nullptr)
{
return;
}
else
{
bool swapped = true;
while (swapped)
{
swapped = false;
Node* current = head;
while (current->next != nullptr)
{
if (current->data > current->next->data)
{
swap(current->data, current->next->data);
swapped = true;
}
current = current->next;
}
}
}
}
完整代码
#include <iostream>
using namespace std;
class Node
{
public:
int data;
Node* next;
};
class LinkedList
{
public:
Node* head;
LinkedList() : head(nullptr) {}
void insert(int data)
{
Node* new_node = new Node();
new_node->data = data;
new_node->next = nullptr;
if (head == nullptr)
{
head = new_node;
}
else {
Node* current = head;
while (current->next != nullptr)
{
current = current->next;
}
current->next = new_node;
}
}
void display()
{
if (head == nullptr)
{
return;
}
else
{
Node* current = head;
while (current->next != nullptr)
{
cout << current->data << "->";
current = current->next;
}
cout << current->data << endl;
}
}
int len()
{
if (head == nullptr)
{
return 0;
}
else
{
Node* current = head;
int count = 1;
while (current->next != nullptr)
{
current = current->next;
count++;
}
return count;
}
}
int value(int num)
{
if (head == nullptr)
{
return -1;
}
else
{
Node* current = head;
int count = 0;
while (count < num)
{
current = current->next;
count++;
}
return current->data;
}
}
void rand_insert(int num, int data)
{
Node* new_node = new Node();
new_node->data = data;
new_node->next = nullptr;
if (head == nullptr)
{
head = new_node;
}
else
{
Node* current = head;
int count = 0;
while (current->next != nullptr && count < num)
{
current = current->next;
count++;
}
if (current->next != nullptr)
{
new_node->next = current->next;
current->next = new_node;
}
else {
current->next = new_node;
}
}
}
void get(int num)
{
if (head == nullptr)
{
return;
}
else
{
for (int i = 0; i < len(); i++)
{
if (value(i) == num)
{
cout << "找到元素" << num << ",其位置为" << i << endl;
return;
}
}
cout << "链表中不存在该元素" << endl;
}
}
void delete_node(int num)
{
if (head == nullptr)
{
return;
}
else
{
if (num == 0)
{
Node* temp = head;
head = head->next;
delete temp;
return;
}
Node* current = head;
int count = 0;
while (count < num - 1)
{
current = current->next;
count++;
}
Node* temp = current->next;
current->next = current->next->next;
delete temp;
}
}
void bubble_sort()
{
if (head == nullptr)
{
return;
}
else
{
bool swapped = true;
while (swapped)
{
swapped = false;
Node* current = head;
while (current->next != nullptr)
{
if (current->data > current->next->data)
{
swap(current->data, current->next->data);
swapped = true;
}
current = current->next;
}
}
}
}
};
int main()
{
LinkedList list;
list.insert(5);
list.insert(4);
list.insert(3);
list.insert(2);
list.insert(1);
cout << "链表初始化为:" << endl;
list.display();
int num = 4;
list.delete_node(num);
cout << "删除第" << num + 1 << "节点后" << endl;
list.display();
cout << "长度为:" << list.len() << endl;
cout << "此位置元素值为:" << list.value(1) << endl;
list.get(2);
list.display();
list.rand_insert(1, 9999); //在左侧插入
list.display();
list.bubble_sort();
cout << "排序后的链表为:" << endl;
list.display();
return 0;
}
这就是本期文章的全部内容了,希望对你有帮助,在评论区留下自己的观点给博主提提建议。
当然,最重要的是,自己试试看吧,你会做的更好