前言
本次我们要学习的是链表结构。类似于数组的顺序存储结构,很适合数据查找,但是如果我们要对数据的元素进行增加或者删除,采用顺序存储就要考虑到删减后移位的问题。而链表可以很有效的提高删减过程的效率。
1.指针
在学习链表之前,我们来学习指针。C++的指针就像是一个地址引用,它可以帮助我们访问和操作存储在地址中的数据。
//指针的声明,如果我们要声明一个指向整数的指针,我们有下面两种写法
int *ptr1;
int* ptr1; //两种方式是等效的
//如果想要存储某个变量的地址并获取地址所存储的值,我们需用到取地址符(&)以及解引用符(*)
int x = 10;
int *p = &x;//将x的地址赋给p
int value = *p;//获取p指针指向的值,即x,故value=10
//指针跟数组结合
int array[3]={0, 1, 2};
int *ptr = arr;//指向数组的第1个元素
int value = *(ptr + 2) //指向数组的第3个元素
除了上述之外,还有一个特殊的空指针,用于表示指针不执行任何有效的地址
int *ptr = nullptr;//初始化空指针
2. 链表
进入主题,链表可以像数组一样是顺序存储的,也可以是不连续的。链表的每一个节点含有一个数据域,用来存放数据;以及一个指针域,用来指向下一个结点的位置。
其中,最后一个结点的指针所指向的位置是不存在的,也就是空。链表的第一个节点的存储位置被称为头指针,然后通过next指针域找到下一个节点。为了简化链表的插入和删除操作,我们经常在链表的第一个节点前添加一个节点,称为虚拟头节点(dummyNode),头节点的数据域可以是空的,但是指针域指向第一个节点的指针。
3. 案例
下面从一个案例来熟悉链表的操作。例子来源于代码随想录基础课程。
输入描述:
每次输出只有一组测试数据。
1. 每组的第一行包含一个整数 k,表示需要构建的链表的长度。
2. 第二行包含 k 个整数,表示链表中的元素。
3. 第三行包含一个整数 S,表示后续会有 S 行输入,每行两个整数,第一个整数为 n,第二个整数为 x ,代表在链表的第 n 个位置插入 x。 S 行输入…
4.在 S 行输入后,后续会输入一个整数 L,表示后续会有 L 行输入,每行一个整数 m,代表删除链表中的第 m 个元素。L 行输入…
输出描述:
包含多组输出。
1. 每组第一行输出构建的链表,链表元素中用空格隔开,最后一个元素后没有空格。
2. 然后是 S 行输出,每次插入一个元素之后都将链表输出一次,元素之间用空格隔开,最后一个元素后没有空格
3. 如果插入位置不合法,则输出“Insertion position is invalid.”。
代表在链表的第 n 个位置插入 x。 S 行输入…
4.然后是 L 行输出,每次删除一个元素之后都将链表输出一次,元素之间用空格隔开,最后一个元素后没有空格;
5.如果删除位置不合法,则输出“Deletion position is invalid.”。
输入示例:
5
1 2 3 4 5
3
4 3
3 4
9 8
2
1
0
输出示例:
1 2 3 3 4 5
1 2 4 3 3 4 5
Insertion position is invalid.
2 4 3 3 4 5
Deletion position is invalid.
代码:
#include<iostream>
using namespace std;
struct ListNode
{
int val;
ListNode *next;
ListNode(int x): val(x), next(nullptr){}
};
// 打印链表
void printLinklist (ListNode *dummyHead)
{
ListNode *cur = dummyHead;
while (cur->next != NULL)
{
cout << cur->next->val <<" ";
cur = cur->next;
}
cout << endl;
}
int main()
{
int k, val,s,n,x,L;
cin >> k;
int Listlenth = k; //链表长度
ListNode *dummyHead = new ListNode(0); //创建头节点
ListNode *cur = dummyHead;
// 读取数据
for (int i=0; i<k; i++)
{
cin >> val;
ListNode *newNode = new ListNode(val);
cur->next = newNode;
cur = cur->next;
}
//添加节点
cin >> s;
while (s--)
{
cin >> n >>x;
if (n <= 0 || n>Listlenth)
{
cout << "Insertion position is invalid." <<endl;
continue;
}
//重设置为头指针
cur = dummyHead;
//寻找添加节点的位置,讲cur移到n-1位置
for (int i = 1; i<n; i++) cur= cur->next;
//插入链表
ListNode *newNode = new ListNode(x);
ListNode *temp = cur->next;
cur->next = newNode;
newNode->next = temp;
Listlenth++; //链表长度+1
//打印链表
printLinklist(dummyHead);
}
//删除节点
cin >> L;
int a;
while(L--)
{
cin >> a;
if ( a<= 0 || a>Listlenth)
{
cout << "Deletion position is invalid." <<endl;
continue;
}
//重设置为头指针
cur = dummyHead;
for (int i=1; i<a; i++) cur=cur->next;
cur -> next=cur->next->next;
Listlenth--;
//打印链表
if(Listlenth !=0) printLinklist(dummyHead);
}
return 0;
}
4. 总结
以上即是本次的学习内容。