单链表
by.Qin3Yu
下面的文章将通过使用单链表完成数据的输入和返回元素之和来简要描述和解释单链表。
特别声明:本文仅通过简单的例子帮助新手快速了解单链表,包括且不限于完成家庭作业等水平,如果您是进阶级别,请参阅其他大佬的详细教学。
什么是单链表?
- 单链表是一种数据结构,其本质是结构体,它由一系列节点组成,每个节点包含一个数据元素和一个指向下一个节点的指针。每个节点中只包含指向下一个节点的指针,而不包含指向前一个节点的指针。链表的第一个节点称为头节点,表示链表的开端;链表的最后一个节点称为尾节点,表示链表的结束。
相比于数组,单链表具有以下优势:
- 插入和删除元素时无需移动其他元素,效率更高;
- 可以动态地调整链表的大小,不会出现数组空间分配固定大小的问题;
- 允许节点的灵活插入和删除,链表不必事先预留空间;
- 可以通过改变节点的链接方式轻松地实现栈、队列、以及其他常见的数据结构。
然而,与数组相比,单链表的缺点是它无法进行随机访问。在单链表中,要查找特定元素,需要从表头开始遍历整个链表,直到找到目标元素。因此,在需要频繁随机访问的情况下,使用数组比使用单链表更为合适。
定义一个单链表
- 这段代码定义了一个名为ListNode的结构体,它用于表示单链表中的节点。结构体中包含了一个整型变量,用于存储节点的值val,以及一个指向下一个节点的指针next。此外,代码中还定义了一个构造函数ListNode(int x)。这个构造函数带有一个整型参数x,用于初始化节点的值。在构造函数中,val被初始化为传入的值x,而next则被初始化为nullptr,表示当前节点的下一个节点暂时为空。
struct ListNode{
int val;
ListNode* next;
ListNode(int x):val(x),next(nullptr){}
};
指出头尾结点
- 在使用链表之前,要先用指针head和tail指出链表的头结点和尾结点:
//两个指针都指向空值,表示现在链表中还没有头尾结点
ListNode* head = nullptr;
ListNode* tail = nullptr;
创建新结点
- 在结构体的构造函数中,我们仅需要传入一个参数表示结点的值即可,因此,我们可以直接用以下方法实例化出一个新的结点:
ListNode* newNode = new ListNode(value); //新建一个值为value的结点
判断结点
- 在链表中创建第一个结点时,两个指针都还指向空的内容。因为整个链表只有一个结点,所以这个结点既是头结点,也是尾结点,因此,我们要将头指针和尾指针都指向这个结点:
if( head == nullptr ){
head = newNode; //将头指针指向此结点
tail = newNode; //将尾指针指向此结点
}
- 假设加入的结点已经不是第一个结点,即头指针已经有了指向的结点,则在列表中加入结点之后,头指针不变,仍然指向第一个结点,尾指针向后移动一位(即移动到新建的结点处),因此将会用到以下方法:
else{
tail -> next = newNode; //尾指针的下一个结点是新结点
tail = tail -> next; //尾指针后移一位,使尾指针指向新的尾结点
}
遍历结点
- 在链表创建完成后,我们需要获取链表中的值,在这里,我们使用的方法是获取当前头指针指向结点的值,然后让头指针指向下一个结点,直到头指针经历过所有的结点为止,如果头指针指向了尾结点的下一个结点,则他将会指向一个空值nullptr,我们将利用此性质完成链表的遍历。
- 在本文中,我们以求所有结点值之和为例子,所以我们只新建一个sum整型来获得数据。
ListNode* getval = head; //获取头结点的指针
int sum = 0;
while( getval != nullptr ){
sum += getval ->val; //获取当前指针指向结点的值
getval = getval -> next; //指向下一个结点
}
完整的代码演示如下:
题目:使用单链表完成数据的输入,并在输入0后求出所有结点的和。
#include <iostream>
using namespace std;
struct ListNode{
int val;
ListNode* next;
ListNode(int x):val(x),next(nullptr){}
};
int main(){
//两个指针都指向空值,表示现在链表中还没有头尾结点
ListNode* head = nullptr;
ListNode* tail = nullptr;
while( true ){
int value;
cout << "请输入节点的值(输入0结束):";
cin >> value;
if( value ==0 )
break; //为0则退出循环
ListNode* newNode = new ListNode(value); //新建一个值为value的结点
if( head == nullptr ){
head = newNode; //将头指针指向此结点
tail = newNode; //将尾指针指向此结点
}
else{
tail -> next = newNode; //尾指针的下一个结点是新结点
tail = tail -> next; //尾指针后移一位,使尾指针指向新的尾结点
}
}
ListNode* getval = head; //获取头结点的指针
int sum = 0;
while( getval != nullptr ){
sum += getval ->val; //获取当前指针指向结点的值
getval = getval -> next; //指向下一个结点
}
cout << "结点的和为:" << sum <<endl;
system("pause");
return 0;
}