前言
-🏀大家好,我是BXuan,热爱编程与篮球的软件工程大二学生一名
-📚近期在准备4月份的蓝桥省赛,本章与大家一起聊聊有关链表的问题!如文有误,请大家指出并多多包涵。
-🏃放弃不难,但坚持一定很酷。
文章目录
🚩概念
①链表是线性表的链式存取的数据结构,是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
②链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:数据域(数据元素的映象)+ 指针域(指示后继元素存储位置),数据域就是存储数据的存储单元,指针域就是连接每个结点的地址数据。
🚩顺序存储VS链式存储
-
顺序存储
-
链式存储
🚩顺序表VS链表
顺序表
优点:
-
无需为表示结点间的逻辑关系而增加额外的存储空间(因为逻辑上相邻的元素其存储的物理位置也是相邻的);
-
可方便地随机存取表中的任一元素:由于顺序表每个元素的大小相等,且知道第几个元素就可以通过计算得到任意元素的地址,既可以随机存取任一元素。
缺点:
-
插入或删除运算不方便:除表尾的位置外,在表的其它位置上进行插入或删除操作都必须移动大量的结点,其效率较低;
如在 7、8 之 间插入 X 元素,那我们为了保证其顺序性需要把 8 和 9 向后移动一位,再将 X 放到 8 的位置。
这样的存储方式增加了处理器和 IO 资源的消耗代价,这是我们不愿意看到的,至于删除其原理相同。
-
难以匹配存储规模:
由于顺序表要求占用连续的存储空间,存储分配只能预先进行静态分配,因此当表长变化较大时,难以确定合适的存储规模。
时间复杂度
查找操作为 O(1),插入和删除操作为 O(n)。
链表
优点:
- 插入和删除速度快,保留原有的物理顺序,在插入或者删除一个元素的时候,只需要改变指针指向即可;
- 没有空间限制, 存储元素无上限, 只与内存空间大小有关;
- 动态分配内存空间,不用事先开辟内存;
- 使内存的利用率变高。
缺点:
- 占用额外的空间以存储指针,比较浪费空间,不连续存储,Malloc 函数开辟空间碎片比较多;
- 查找速度比较慢,因为在查找时,需要循环遍历链表。
时间复杂度:
查找操作为 O(n), 插入和删除操作为 O(1)。
🚩知识点
- 单链表实现原理与应用
- 循环链表实现原理与应用
- 双向链表实现原理与应用
一、小王子(单链表)
问题描述
小王子有一天迷上了排队的游戏,桌子上有标号为 1−10 的 10 个玩具,现在小王子将他们排成一列,可小王子还是太小了,他不确定他到底想把那个玩具摆在哪里,直到最后才能排成一条直线,求玩具的编号。已知他排了 M 次,每次都是选取标号为 X 个放到最前面,求每次排完后玩具的编号序列。
要求一:采用单链表解决
输入描述
第一行是一个整数 M,表示小王子排玩具的次数。
随后 M 行每行包含一个整数 X,表示小王子要把编号为 X 的玩具放在最前面。
输出描述
共 M 行,第 i 行输出小王子第 i 次排完序后玩具的编号序列。
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
输入输出案例
输入
5
3
2
3
4
2
输出
3 1 2 4 5 6 7 8 9 10
2 3 1 4 5 6 7 8 9 10
3 2 1 4 5 6 7 8 9 10
4 3 2 1 5 6 7 8 9 10
2 4 3 1 5 6 7 8 9 10
代码示例
import java.util.Scanner;
//1:无需package
//2: 类名必须Main, 不可修改
public class Main {
// 构建单链表结构
static class Node{
int data; // 数据域
Node next; // 指针域
// 传入当前链表的数据域的值
Node(int v){
data = v;
}
}
// 将头节点单独插入到链表中
static Node head = new Node(1);
// 构建插入函数
static void init(){
// 首先将
Node x = head;
for(int i = 1;i <= 10;i++){
x=(x.next = new Node(i));
}
x.next = null;
}
//然后选中的数字 就在链表中将其删除,然后重新插入到头节点后面
static void del(int x){
Node before = head;
for(Node T = head.next;T != null;T = T.next){
if(T.data == x){
//在删除之前需要将临时结点保存然后方便后续进行插入
Node temp = T;
before.next = T.next;
//结束函数
return;