数组是连续的,每当我们需要在数组当中插入或删除数组中间的数据时,都必须要移动大量的元素,效率低下
数组是保存在内存当中的一组连续的格子
程序事先会保存数组的地址,当我们需要访问数组当中的某个数组时,只需要让数组地址加上偏移值即可
例如:a数组地址为1000,那么a[4]的地址就是:1004
与数组不同的是,组成链表的格子不是连续的,它们可以分步在各个地方,这种不相邻的格子,就叫做结点
既然分步在各个地方,那么计算机是通过什么东西来寻找链表当中的节点呢?
采用指针的方式来完成这步操作
每个结点除了保存数据,它还保存着链表里下一个结点的内存地址
这份用来指示下一个结点的内存地址的额外数据,被称为链
结点
链
结点
链
在图示当中,每个结点的后一个格子都指向后一个结点的前一个格子
因此,如果我们想要知道链表在内存当中的位置,就必须要明确第一个格子的位置
对于结点来说,既要能够保证存储数据,又要能够存储下一个结点的内存地址,应该采用那种数据结构最为合适呢?
一个节点当中需要包含两种不同的数据类型,采用结构体的方式最为合适
答案
节点的实现方式
struct test
{
int data; //保存数据的部分
test *next; //保存下一个结点的指针部分
};
创建多个节点
test a;
a.data = 'a';
test b;
b.data = 'b';
test c;
c.data = 'c';
test d;
d.data = 'd';
将节点之间进行链接
a.next = &b;
b.next = &c;
c.next = &d;
d.next = nullptr; //d的next并不会指向任何一个结点,所以是空节点
如果我们要找到链表当中的某个值,我们是没有办法像数组一样进行快速定位,比如:a[4]
因为我们不能很快的确定结点在内存当中的位置
因此,对于链表来说,我们只能先找到第一个结点的数据,再以此找到第二个结点、第三个结点
输出第一个结点的数据
cout << a.data << endl;
输出第二个结点的数据
cout << a.next->data << endl;
输出第三个结点的数据
cout << a.next -> next -> data << endl;
利用循环的方式来读取链表的值
test temp = a; //建立临时变量,用于指向结点
while (temp.next != nullptr){
cout << temp.data << endl;
temp = *temp.next; //修正临时变量
}
cout << temp.data << endl; //打印最后一个结点的内容
a
b
c
d
从尾到头打印链表
请新建一个链表,并将链表结点的数据,从尾到头进行打印
链表数据:78 45 12 56 63 14 78
从尾到头打印结果:78 14 63 56 12 45 78
#include <iostream>
using namespace std;
struct number
{
int data;
number *next;
};
int main(){
int acache[7] = {0};
//建立链表
number a,b,c,d,e,f,g;
a.data = 78;a.next = &b;
b.data = 45;b.next = &c;
c.data = 12;c.next = &d;
d.data = 56;d.next = &e;
e.data = 63;e.next = &f;
f.data = 14;f.next = &g;
g.data = 78;g.next = nullptr;
//遍历链表,将遍历的结果放在数组acache当中
number temp = a;
int i = 0;
while (temp.next != nullptr){
acache[i] = temp.data;i++;
temp = *temp.next;
}
acache[i] = temp.data;
//倒序输出结果
for (int k = i;k >= 0;k--){
cout << acache[k] << endl;
}
}