在单向链表中插入节点 C++
本文讲解了在 C++ 中如何在单向链表中插入新节点的方法。
实现在链表末尾插入节点的函数
链表是线性数据结构,由依次指向彼此的节点组成。在本文中,我们更多地关注单链表结构并相应地实现多个插入操作。
在单链表中,我们有一个数据对象和一个指向列表中下一个节点的指针。我们定义了一个名为 ListNode
的节点结构和两个辅助函数(freeNodes
和 printNodes
),以更好地演示列表插入操作。请注意,插入操作的时间复杂度因我们将节点插入到的位置而异。例如,如果列表末尾未知,则在列表末尾插入需要线性时间。
另一方面,在开头插入一个新节点总是需要固定的时间。下面的代码演示了 insertNodeEnd
函数,它可以被视为构建列表的核心函数。它将列表的头部作为第一个参数和需要存储在新节点上的字符串
数据。该函数可以创建列表中的第一个元素并在其末尾附加新元素。该函数在空闲存储内存上分配新节点。因此,需要 freeNodes
函数在程序退出之前释放所有内存。
#include <iostream>
#include <string>
#include <utility>
#include <vector>
using std::cout; using std::cin;
using std::endl; using std::string;
using std::vector;
struct ListNode {
struct ListNode *next{};
string data;
};
struct ListNode *insertNodeEnd(struct ListNode *root, string data) {
auto new_node = new ListNode;
if (root) {
while (root->next)
root = root->next;
new_node->next = nullptr;
new_node->data = std::move(data);
root->next = new_node;
return root->next;
}
new_node->next = nullptr;
new_node->data = std::move(data);
return new_node;
}
void freeNodes(struct ListNode *root) {
struct ListNode *tmp = nullptr;
while (root) {
tmp = root;
root = root->next;
delete tmp;
}
}
void printNodes(struct ListNode *node) {
auto count = 0;
while (node){
cout << "node " << count << " - data: " << node->data << endl;
node = node->next;
count++;
}
}
int main() {
struct ListNode *head = nullptr;
vector<string> data_set = { "Precise", "Quantal",
"Saucy", "Raring"};
head = insertNodeEnd(head, data_set.at(0));
for (auto it = data_set.begin() + 1; it != data_set.end(); ++it) {
insertNodeEnd(head, *it);
}
printNodes(head);
cout << " ----------------------------------- " << endl;
insertNodeEnd(head, "Utopic");
printNodes(head);
freeNodes(head);
return EXIT_SUCCESS;
}
输出:
node 0 - data: Precise
node 1 - data: Quantal
node 2 - data: Saucy
node 3 - data: Raring
-----------------------------------
node 0 - data: Precise
node 1 - data: Quantal
node 2 - data: Saucy
node 3 - data: Raring
node 4 - data: Utopic
实现一个函数在链表中的给定节点之后插入一个节点
在列表中间插入一个节点通常需要常数时间加上用于找到给定位置的搜索算法的时间复杂度。尽管如此,我们假设搜索函数是单独实现的,并构造了 insertNodeAfter
函数,以便需要将目标节点的位置作为第一个参数提供。
由于 insertNodeEnd
函数返回指向新添加节点的指针,我们利用其返回值来演示 insertNodeAfter
的操作。请记住,对于任意位置插入,你需要一个单独的搜索功能,甚至可能需要一个外部数据结构来在链表上实现更快的搜索操作。
#include <iostream>
#include <string>
#include <utility>
#include <vector>
using std::cout; using std::cin;
using std::endl; using std::string;
using std::vector;
struct ListNode {
struct ListNode *next{};
string data;
};
struct ListNode *insertNodeEnd(struct ListNode *root, string data) {
auto new_node = new ListNode;
if (root) {
while (root->next)
root = root->next;
new_node->next = nullptr;
new_node->data = std::move(data);
root->next = new_node;
return root->next;
}
new_node->next = nullptr;
new_node->data = std::move(data);
return new_node;
}
struct ListNode *insertNodeAfter(struct ListNode *prev, string data) {
if (!prev)
return nullptr;
auto new_node = new ListNode;
new_node->next = nullptr;
new_node->data = std::move(data);
prev->next = new_node;
return new_node;
}
void freeNodes(struct ListNode *root) {
struct ListNode *tmp = nullptr;
while (root) {
tmp = root;
root = root->next;
delete tmp;
}
}
void printNodes(struct ListNode *node) {
auto count = 0;
while (node){
cout << "node " << count << " - data: " << node->data << endl;
node = node->next;
count++;
}
}
int main() {
struct ListNode *head = nullptr;
vector<string> data_set = { "Precise", "Quantal",
"Saucy", "Raring"};
head = insertNodeEnd(head, data_set.at(0));
for (auto it = data_set.begin() + 1; it != data_set.end(); ++it) {
insertNodeEnd(head, *it);
}
printNodes(head);
cout << " ----------------------------------- " << endl;
auto iter = insertNodeEnd(head, "Utopic");
printNodes(head);
cout << " ----------------------------------- " << endl;
insertNodeAfter(iter, "Xenial");
printNodes(head);
freeNodes(head);
return EXIT_SUCCESS;
}
输出:
node 0 - data: Precise
node 1 - data: Quantal
node 2 - data: Saucy
node 3 - data: Raring
-----------------------------------
node 0 - data: Precise
node 1 - data: Quantal
node 2 - data: Saucy
node 3 - data: Raring
node 4 - data: Utopic
-----------------------------------
node 0 - data: Precise
node 1 - data: Quantal
node 2 - data: Saucy
node 3 - data: Raring
node 4 - data: Utopic
node 5 - data: Xenial
实现在链表开头插入节点的函数
单向链表的另一个有用的插入操作是在开头附加一个新节点。该函数具有最佳运行时间 O(1)
,因为始终存储列表的头部以访问列表本身。insertNodeFront
函数获取对根指针和需要存储在节点上的 string
对象的引用。该过程被实现,以便你可以使用它来初始化一个新的链表以及前插入。
或者,你可以重写函数以在 root
参数不是 nullptr
时分配一个新节点。否则,返回 nullptr
表示函数失败。这些函数的接口取决于程序员的需要和 ListNode
的结构。
#include <iostream>
#include <string>
#include <utility>
#include <vector>
using std::cout; using std::cin;
using std::endl; using std::string;
using std::vector;
struct ListNode {
struct ListNode *next{};
string data;
};
struct ListNode *insertNodeEnd(struct ListNode *root, string data) {
auto new_node = new ListNode;
if (root) {
while (root->next)
root = root->next;
new_node->next = nullptr;
new_node->data = std::move(data);
root->next = new_node;
return root->next;
}
new_node->next = nullptr;
new_node->data = std::move(data);
return new_node;
}
struct ListNode *insertNodeFront(struct ListNode *&root, string data) {
auto new_node = new ListNode;
if (root) {
new_node->next = root;
new_node->data = std::move(data);
root = new_node;
return root;
}
new_node->next = nullptr;
new_node->data = std::move(data);
return new_node;
}
void freeNodes(struct ListNode *root) {
struct ListNode *tmp = nullptr;
while (root) {
tmp = root;
root = root->next;
delete tmp;
}
}
void printNodes(struct ListNode *node) {
auto count = 0;
while (node){
cout << "node " << count << " - data: " << node->data << endl;
node = node->next;
count++;
}
}
int main() {
struct ListNode *head = nullptr;
vector<string> data_set = { "Precise", "Quantal",
"Saucy", "Raring"};
head = insertNodeEnd(head, data_set.at(0));
for (auto it = data_set.begin() + 1; it != data_set.end(); ++it) {
insertNodeEnd(head, *it);
}
printNodes(head);
cout << " ----------------------------------- " << endl;
insertNodeFront(head, "Bionic");
printNodes(head);
freeNodes(head);
return EXIT_SUCCESS;
}
输出:
node 0 - data: Precise
node 1 - data: Quantal
node 2 - data: Saucy
node 3 - data: Raring
-----------------------------------
node 0 - data: Bionic
node 1 - data: Precise
node 2 - data: Quantal
node 3 - data: Saucy
node 4 - data: Raring
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn