👨💻 博主正在持续更新关于数据结构的博客中。
❤️ 如果你觉得内容还不错,请多多点赞。
⭐️ 如果你觉得对你有帮助,请多多收藏。(防止以后找不到了)
👨👩👧👦如果你想阅读更多的关于数据结构的博客,请多多关注博主。
单向链表节点的定义
在学习单向链表的基本操作值之前,我们要先了解单向链表的节点是怎么定义的,因为单向链表的基本操作都是针对于单向链表的节点进行的,所以我们需要对单向链表的节点有那些成员了如指掌。
//单向链表节点的定义
struct ListNode
{
int data;
ListNode* next;
ListNode(int val) :data(val), next(nullptr) {}
};
单向链表节点由下面两部分构成:
数据域
:存储节点数据的数据域int data;
这部分用于存储节点所包含的实际数据。
- 数据域的类型可以是任意的,比如整数、浮点数、字符、字符串
指针域
:存储下一个节点地址的指针域ListNode* next;
这部分是一个指针,它指向链表中的下一个节点。
单向链表的创建
前提引入:
关于单向链表的创建方法,我们一般都认为有两种方法:
- 头插法
- 尾插法
并也习惯以此作为单向链表创建操作的归类标准,但我认为以此作为分类标准是不够全面的。
虽然说单向链表创建操作从方法上其本质是使用
头插法
还是尾插法
,但我更习惯于从形式上以创建单向链表时调用辅助函数的次数
作为分类的标准。因为以此为分类标准涵盖的范围更广。从方式上:单向链表的创建操作可以分为
- 零次调用函数创建单向链表
- 一次调用函数创建单向链表
- 多次调用函数创建单向链表
这样在一次调用,多次调用中又可以分为使用了
头插法
或尾插法
的情况,这样会使我们对单向链表的创建操作的种类更加清晰。
方式一:零次调用函数创建单向链表
形式一:
//单向链表的创建——零次函数调用
ListNode* node1 = new ListNode(1);
ListNode* node2 = new ListNode(2);
ListNode* node3 = new ListNode(3);
node1->next = node2;
node2->next = node3;
ListNode* head = node1;
完整代码测试
//单向链表的创建——零次函数调用
#include<iostream>
using namespace std;
struct ListNode
{
int data;
ListNode* next;
ListNode(int val) :data(val), next(nullptr) {}
};
class LinkList
{
public:
//单向链表的打印
void printList(ListNode* head)
{
ListNode* curr = head;
while (curr != nullptr)
{
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
//单向链表的销毁
void destroyList(ListNode*& head)
{
while (head != nullptr)
{
ListNode* curr = head;
head = head->next;
delete curr;
}
}
};
int main()
{
//单向链表的创建
ListNode* node1 = new ListNode(1);
ListNode* node2 = new ListNode(2);
ListNode* node3 = new ListNode(3);
node1->next = node2;
node2->next = node3;
ListNode* head = node1;
LinkList list;
cout << "创建好的单向链表为:" << endl;
list.printList(head);
list.destroyList(head);
return 0;
}
输出:
创建好的单向链表为:
1 2 3
形式二:
//单向链表的创建——零次函数调用
ListNode* head = new ListNode(1);
head->next = new ListNode(2);
head->next->next = new ListNode(3);
完整代码测试
//单向链表的创建——零次函数调用
#include<iostream>
using namespace std;
struct ListNode
{
int data;
ListNode* next;
ListNode(int val) :data(val), next(nullptr) {}
};
class LinkList
{
public:
//单向链表的打印
void printList(ListNode* head)
{
ListNode* curr = head;
while (curr != nullptr)
{
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
//单向链表的销毁
void destroyList(ListNode*& head)
{
while (head != nullptr)
{
ListNode* curr = head;
head = head->next;
delete curr;
}
}
};
int main()
{
//单向链表的创建
ListNode* head = new ListNode(1);
head->next = new ListNode(2);
head->next->next = new ListNode(3);
cout << "创建好的单向链表为:" << endl;
LinkList list;
list.printList(head);
list.destroyList(head);
return 0;
}
输出:
创建好的单向链表为:
1 2 3
方式二:一次调用函数创建单向链表
形式一:用户输入+头插法
//单向链表的创建——一次函数调用-用户输入+头插法
bool createList_H(ListNode*& head, int size)
{
for (int i = 1; i <= size; i++)
{
cout << "请输入你要创建的第"<<i<<"个节点的值" << endl;
int val;
cin >> val;
ListNode* newNode = new ListNode(val);
newNode->next = head;
head = newNode;
}
return true;
}
完整代码测试
//单向链表的创建——一次函数调用-用户输入+头插法
#include<iostream>
using namespace std;
struct ListNode
{
int data;
ListNode* next;
ListNode(int val) :data(val), next(nullptr) {}
};
class LinkList
{
public:
//单向链表的创建
bool createList_H(ListNode*& head, int size)
{
for (int i = 1; i <= size; i++)
{
cout << "请输入你要创建的第"<<i<<"个节点的值" << endl;
int val;
cin >> val;
ListNode* newNode = new ListNode(val);
newNode->next = head;
head = newNode;
}
return true;
}
//单向链表的打印
void printList(ListNode* head)
{
ListNode* curr = head;
while (curr != nullptr)
{
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
//单向链表的销毁
void destroyList(ListNode*& head)
{
while (head != nullptr)
{
ListNode* curr = head;
head = head->next;
delete curr;
}
}
};
int main()
{
//单向链表的创建
ListNode* head = nullptr;
LinkList list;
cout << "请输入你要创建的单向链表的长度" << endl;
int size;
cin >> size;
list.createList_H(head, size);
cout << "创建好的单向链表为:" << endl;
list.printList(head);
list.destroyList(head);
return 0;
}
交互过程:
请输入你要创建的单向链表的长度
3
请输入你要创建的第1个节点的值
1
请输入你要创建的第2个节点的值
2
请输入你要创建的第3个节点的值
3
创建好的单向链表为:
3 2 1
注:头插法创建出来的单向链表节点的次序与输入时的顺序相反,但可以使用单向链表的反转操作使其与输入时的顺序相同
形式二:用户输入+尾插法
//单向链表的创建——一次函数调用-用户输入+尾插法
ListNode* createList_T(ListNode*& head, int size)
{
for (int i = 1; i <= size; i++)
{
cout << "请输入你要创建的第"<<i<<"个节点的值" << endl;
int val;
cin >> val;
if (head == nullptr)
{
head= new ListNode(val);
}
else
{
ListNode* curr = head;
while (curr->next != nullptr)
{
curr = curr->next;
}
curr->next = new ListNode(val);
curr = curr->next;
}
}
return head;
}
完整代码测试
//单向链表的创建——一次函数调用-用户输入+尾插法
#include<iostream>
using namespace std;
struct ListNode
{
int data;
ListNode* next;
ListNode(int val) :data(val), next(nullptr) {}
};
class LinkList
{
public:
//单向链表的创建
ListNode* createList_T(ListNode*& head, int size)
{
for (int i = 1; i < size; i++)
{
cout << "请输入你要创建的第"<<i<<"个节点的值" << endl;
int val;
cin >> val;
if (head == nullptr)
{
head= new ListNode(val);
}
else
{
ListNode* curr = head;
while (curr->next != nullptr)
{
curr = curr->next;
}
curr->next = new ListNode(val);
curr = curr->next;
}
}
return head;
}
//单向链表的打印
void printList(ListNode* head)
{
ListNode* curr = head;
while (curr != nullptr)
{
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
//单向链表的销毁
void destroyList(ListNode*& head)
{
while (head != nullptr)
{
ListNode* curr = head;
head = head->next;
delete curr;
}
}
};
int main()
{
//单向链表的创建
ListNode* head = nullptr;
LinkList list;
cout << "请输入你要创建的单向链表的长度" << endl;
int size;
cin >> size;
list.createList_T(head, size);
cout << "创建好的单向链表为:" << endl;
list.printList(head);
list.destroyList(head);
return 0;
}
交互过程:
请输入你要创建的单向链表的长度
3
请输入你要创建的第1个节点的值
1
请输入你要创建的第2个节点的值
2
请输入你要创建的第3个节点的值
3
创建好的单向链表为:
1 2 3
形式三:数组传参+前插法
//单向链表的创建——一次调用函数-数组传参+头插法
ListNode* createList_H(ListNode*& head, const int arr[], int size)
{
for (int i = 0; i < size; i++)
{
ListNode* newNode = new ListNode(arr[i]);
newNode->next = head;
head = newNode;
}
return head;
}
完整代码测试:
//单向链表的创建——一次调用函数-数组传参+头插法
#include<iostream>
using namespace std;
struct ListNode
{
int data;
ListNode* next;
ListNode(int val) :data(val), next(nullptr) {}
};
class LinkList
{
public:
//单向链表的创建
ListNode* createList_H(ListNode*& head, const int arr[], int size)
{
for (int i = 0; i < size; i++)
{
ListNode* newNode = new ListNode(arr[i]);
newNode->next = head;
head = newNode;
}
return head;
}
//单向链表的打印
void printList(ListNode* head)
{
ListNode* curr = head;
while (curr != nullptr)
{
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
//单向链表的销毁
void destroyList(ListNode*& head)
{
while (head != nullptr)
{
ListNode* curr = head;
head = head->next;
delete curr;
}
}
};
int main()
{
//单向链表的创建
ListNode* head = nullptr;
LinkList list;
const int arr[] = { 1,2,3 };
int size = sizeof(arr) / sizeof(arr[0]);
list.createList_H(head, arr, size);
cout << "创建好的单向链表为:" << endl;
list.printList(head);
list.destroyList(head);
return 0;
}
输出:
创建好的单向链表为:
3 2 1
形式三:数组传参+后插法
//单向链表的创建——一次调用函数-数组传参+尾插法
ListNode* createList_T(ListNode*& head, const int arr[], int size)
{
if (head == nullptr)
{
head = new ListNode(arr[0]);
}
ListNode* curr = head;
for (int i = (head == nullptr ? 0 : 1); i < size; i++)
{
while (curr->next != nullptr)
{
curr = curr->next;
}
curr->next = new ListNode(arr[i]);
curr = curr->next;
}
return head;
}
完整代码测试
//单向链表的创建——一次调用函数-数组传参+尾插法
#include<iostream>
using namespace std;
struct ListNode
{
int data;
ListNode* next;
ListNode(int val) :data(val), next(nullptr) {}
};
class LinkList
{
public:
//单向链表的创建
ListNode* createList_T(ListNode*& head, const int arr[], int size)
{
if (head == nullptr)
{
head = new ListNode(arr[0]);
}
ListNode* curr = head;
for (int i = (head == nullptr ? 0 : 1); i < size; i++)
{
while (curr->next != nullptr)
{
curr = curr->next;
}
curr->next = new ListNode(arr[i]);
curr = curr->next;
}
return head;
}
//单向链表的打印
void printList(ListNode* head)
{
ListNode* curr = head;
while (curr != nullptr)
{
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
//单向链表的销毁
void destroyList(ListNode*& head)
{
while (head != nullptr)
{
ListNode* curr = head;
head = head->next;
delete curr;
}
}
};
int main()
{
//单向链表的创建
ListNode* head = nullptr;
LinkList list;
const int arr[] = { 1,2,3 };
int size = sizeof(arr) / sizeof(arr[0]);
list.createList_T(head, arr, size);
cout << "创建好的单向链表为:" << endl;
list.printList(head);
list.destroyList(head);
return 0;
}
输出:
创建好的单向链表为:
1 2 3
方式三:多次调用函数创建单向链表
形式一:头插法
//单向链表的创建——多次调用函数-头插法
ListNode* creatList_H(ListNode*& head,int value)
{
ListNode* newNode = new ListNode(value);
newNode->next = head;
head = newNode;
return head;
}
完整代码测试
//单向链表的创建——多次调用函数-头插法
#include<iostream>
using namespace std;
struct ListNode
{
int data;
ListNode* next;
ListNode(int val) :data(val), next(nullptr) {}
};
class LinkList
{
public:
//单向链表的创建
ListNode* creatList_H(ListNode*& head,int value)
{
ListNode* newNode = new ListNode(value);
newNode->next = head;
head = newNode;
return head;
}
//单向链表的打印
void printList(ListNode* head)
{
ListNode* curr = head;
while (curr != nullptr)
{
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
//单向链表的销毁
void destroyList(ListNode*& head)
{
while (head != nullptr)
{
ListNode* curr = head;
head = head->next;
delete curr;
}
}
};
int main()
{
//单向链表的创建
ListNode* head = nullptr;
LinkList list;
list.creatList_H(head, 1);
list.creatList_H(head, 2);
list.creatList_H(head, 3);
cout << "创建好的单向链表为:" << endl;
list.printList(head);
list.destroyList(head);
return 0;
}
输出:
创建好的单向链表为:
3 2 1
形式二:尾插法
//单向链表的创建——多次调用函数-尾插法
ListNode* creatList_T(ListNode*& head, int value)
{
if (head == nullptr)
{
head = new ListNode(value);
}
else
{
ListNode* curr = head;
while (curr->next != nullptr)
{
curr = curr->next;
}
curr->next = new ListNode(value);
}
return head;
}
完整代码测试
//单向链表的创建——多次调用函数-尾插法
#include<iostream>
using namespace std;
struct ListNode
{
int data;
ListNode* next;
ListNode(int val) :data(val), next(nullptr) {}
};
class LinkList
{
public:
//单向链表的创建
ListNode* creatList_T(ListNode*& head, int value)
{
if (head == nullptr)
{
head = new ListNode(value);
}
else
{
ListNode* curr = head;
while (curr->next != nullptr)
{
curr = curr->next;
}
curr->next = new ListNode(value);
}
return head;
}
//单向链表的打印
void printList(ListNode* head)
{
ListNode* curr = head;
while (curr != nullptr)
{
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
//单向链表的销毁
void destroyList(ListNode*& head)
{
while (head != nullptr)
{
ListNode* curr = head;
head = head->next;
delete curr;
}
}
};
int main()
{
//单向链表的创建
ListNode* head = nullptr;
LinkList list;
list.creatList_T(head, 1);
list.creatList_T(head, 2);
list.creatList_T(head, 3);
cout << "创建好的单向链表为:" << endl;
list.printList(head);
list.destroyList(head);
return 0;
}
输出:
创建好的单向链表为:
1 2 3
创建操作总结:
看到这里我相信你更能体会到,单向链表的创建操作其实本质上就两种方法:头插法
和尾插法
因为在上面展示的各种不同的创建操作中有一些代码片段,一直在重复出现:
- 头插法:
newNode->next = head; head = newNode;
- 尾插法:
curr->next = new ListNode(val);//随机决定用什么初始化节点的data curr = curr->next;//需要根据具体的情况选择写不写这行代码
单向链表的反转
方法一:三指针
//单向链表的反转——三指针
ListNode* reverseList(ListNode*& head)
{
ListNode* newHead = nullptr;
ListNode* curr = head;
ListNode* next = nullptr;
while (curr != nullptr)
{
next = curr->next;
curr->next = newHead;
newHead = curr;
curr = next;
}
head=newHead;
return head;
}
原理图像展示
完整代码测试
//单向链表的反转——三指针
#include<iostream>
using namespace std;
struct ListNode
{
int data;
ListNode* next;
ListNode(int val) :data(val), next(nullptr) {}
};
class LinkList
{
public:
//单向链表的反转
ListNode* reverseList(ListNode*& head)
{
ListNode* newHead = nullptr;
ListNode* curr = head;
ListNode* next = nullptr;
while (curr != nullptr)
{
next = curr->next;
curr->next = newHead;
newHead = curr;
curr = next;
}
head=newHead;
return head;
}
//单向链表的打印
void printList(ListNode* head)
{
ListNode* curr = head;
while (curr != nullptr)
{
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
//单向链表的销毁
void destroyList(ListNode*& head)
{
while (head != nullptr)
{
ListNode* curr = head;
head = head->next;
delete curr;
}
}
};
int main()
{
//单向链表的创建
ListNode* head = new ListNode(3);
head->next = new ListNode(2);
head->next->next = new ListNode(1);
LinkList list;
cout << "创建好的单向链表为:" << endl;
list.printList(head);
cout << "反转好的单向链表为:" << endl;
list.reverseList(head);
list.printList(head);
list.destroyList(head);
return 0;
}
输出:
创建好的单向链表为:
3 2 1
反转好的单向链表为:
1 2 3
方法二:栈操作
//单向链表的反转——栈操作
ListNode* reverseList(ListNode*& head)
{
if (head == nullptr)
{
return nullptr;
}
stack<ListNode*>nodeStk;
ListNode* curr = head;
while (curr != nullptr)
{
nodeStk.push(curr);
curr = curr->next;
}
ListNode* newHead = nodeStk.top();
nodeStk.pop();
curr = newHead;
while (!nodeStk.empty())
{
curr->next = nodeStk.top();
nodeStk.pop();
curr = curr->next;
}
curr->next = nullptr;
head = newHead;
return head;
}
原理图像展示
完整代码测试
//单向链表的反转——栈操作
#include<iostream>
#include<stack>
using namespace std;
struct ListNode
{
int data;
ListNode* next;
ListNode(int val) :data(val), next(nullptr) {}
};
class LinkList
{
public:
//单向链表的反转
ListNode* reverseList(ListNode*& head)
{
if (head == nullptr)
{
return nullptr;
}
stack<ListNode*>nodeStk;
ListNode* curr = head;
while (curr != nullptr)
{
nodeStk.push(curr);
curr = curr->next;
}
ListNode* newHead = nodeStk.top();
nodeStk.pop();
curr = newHead;
while (!nodeStk.empty())
{
curr->next = nodeStk.top();
nodeStk.pop();
curr = curr->next;
}
curr->next = nullptr;
head = newHead;
return head;
}
//单向链表的打印
void printList(ListNode* head)
{
ListNode* curr = head;
while (curr != nullptr)
{
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
//单向链表的销毁
void destroyList(ListNode*& head)
{
while (head != nullptr)
{
ListNode* curr = head;
head = head->next;
delete curr;
}
}
};
int main()
{
//单向链表的创建
ListNode* head = new ListNode(3);
head->next = new ListNode(2);
head->next->next = new ListNode(1);
LinkList list;
cout << "创建好的单向链表为:" << endl;
list.printList(head);
cout << "反转好的单向链表为:" << endl;
list.reverseList(head);
list.printList(head);
list.destroyList(head);
return 0;
}
输出:
创建好的单向链表为:
3 2 1
反转好的单向链表为:
1 2 3
方法三:递归法
//单向链表的反转——递归法
ListNode* reverseList(ListNode* head)
{
if (head == nullptr || head->next == nullptr)
{
return head;
}
else
{
ListNode* newHead = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return newHead;
}
}
原理图像展示
完整代码测试
//单向链表的反转——递归法
#include<iostream>
using namespace std;
struct ListNode
{
int data;
ListNode* next;
ListNode(int val) :data(val), next(nullptr) {}
};
class LinkList
{
public:
//单向链表的反转
ListNode* reverseList(ListNode* head)
{
if (head == nullptr || head->next == nullptr)
{
return head;
}
else
{
ListNode* newHead = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return newHead;
}
}
//单向链表的打印
void printList(ListNode* head)
{
ListNode* curr = head;
while (curr != nullptr)
{
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
//单向链表的销毁
void destroyList(ListNode*& head)
{
while (head != nullptr)
{
ListNode* curr = head;
head = head->next;
delete curr;
}
}
};
int main()
{
//单向链表的创建
ListNode* head = new ListNode(3);
head->next = new ListNode(2);
head->next->next = new ListNode(1);
LinkList list;
cout << "创建好的单向链表为:" << endl;
list.printList(head);
cout << "反转好的单向链表为:" << endl;
ListNode* newHead = list.reverseList(head);
list.printList(newHead);
list.destroyList(newHead);
return 0;
}
输出:
创建好的单向链表为:
3 2 1
反转好的单向链表为:
1 2 3
单向链表的打印
方法一:迭代
//单向链表的打印——迭代
void printList(ListNode* head)
{
ListNode* curr = head;
while (curr != nullptr)
{
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
方法二:递归
//单向链表的打印——递归
void printList(ListNode* head)
{
ListNode* curr = head;
if (curr == nullptr)
{
cout<<endl;
return;
}
cout << curr->data << " ";
printList(curr->next);
}
单向链表的销毁
方法一:迭代
//单向链表的销毁——迭代
void destroyList(ListNode*& head)
{
while (head != nullptr)
{
ListNode* curr = head;
head = head->next;
delete curr;
}
}
方法二:递归
//单向链表的销毁——递归
void destroyList(ListNode*& head)
{
if (head == nullptr)
{
return;
}
destroyList(head->next);
delete head;
}
原理图像展示
单向链表的“创建+反转+打印+销毁”操作汇总小程序
//单向链表的“创建+反转+打印+销毁”操作汇总小程序
#include<iostream>
using namespace std;
struct ListNode
{
int data;
ListNode* next;
ListNode(int val) :data(val), next(nullptr) {}
};
class LinkList
{
public:
//显示基本操作菜单界面
void menuList()
{
cout << "****************单向链表的基本操作*******************" << endl;
cout << "-----------------1.创建单向链表---------------------" << endl;
cout << "-----------------2.反转单向链表---------------------" << endl;
cout << "-----------------3.打印单向链表---------------------" << endl;
cout << "-----------------4.销毁单向链表---------------------" << endl;
cout << "-----------------0.退出该小程序---------------------" << endl;
cout << "**************************************************" << endl;
}
//单向链表的创建——一次函数调用-用户输入+头插法
bool createList_H(ListNode*& head, int size)
{
for (int i = 1; i <= size; i++)
{
cout << "请输入你要创建的第"<<i<<"个节点的值" << endl;
int val;
cin >> val;
ListNode* newNode = new ListNode(val);
newNode->next = head;
head = newNode;
}
return true;
}
//单向链表的反转——三指针
ListNode* reverseList(ListNode*& head)
{
ListNode* newHead = nullptr;
ListNode* curr = head;
ListNode* next = nullptr;
while (curr != nullptr)
{
next = curr->next;
curr->next = newHead;
newHead = curr;
curr = next;
}
head = newHead;
return head;
}
//单向链表的打印——迭代
void printList(ListNode* head)
{
ListNode* curr = head;
while (curr != nullptr)
{
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
//单向链表的销毁——迭代
bool destroyList(ListNode*& head)
{
while (head != nullptr)
{
ListNode* curr = head;
head = head->next;
delete curr;
}
return true;
}
};
int main()
{
ListNode* head = nullptr;
LinkList list;
int n = INT_MAX;
while (n != 0)
{
list.menuList();
cout << "请输入菜单号" << endl;
cin >> n;
switch (n)
{
case 1:
cout << "请输入你要创建的单向链表的长度" << endl;
int size;
cin >> size;
if (list.createList_H(head, size))
{
cout << "单向链表创建成功!" << endl;
}
else
{
cout << "单向链表创建失败!" << endl;
}
break;
case 2:
list.reverseList(head);
cout << "该单向链表已反转" << endl;
break;
case 3:
cout << "该单向链表为:" << endl;
list.printList(head);
break;
case 4:
if (list.destroyList(head))
{
cout << "该单向链表销毁成功!" << endl;
}
else
{
cout << "该单向链表销毁失败!" << endl;
}
break;
}
}
return 0;
}
wow ,你既然看完了,太厉害了👍,为你鼓掌👏 。还有…… 咳咳,别急着走,😭 你是不是忘了什么东西呀~ 😊