??在存储一大波数据的时候,我们最常用的可能是数组,但是有时候数组就是不够灵活。
比如说,有一大串数据,如果中间插入一个数字的话,就要将后面的数字往后一个一个挪,怎么挪呢~
1、开刀:把数组在特定的位置截开
2、新建:创建一个新的足够长的定长数组
3、缝合:依次将前半段、那个数字、后半段缝合
这样的操作明显是很消耗时间的,如果使用链表就快很多啦,因为链表只需要将前后两段的关联切开,中间插入数据,然后再缝合两边联系就可以了。
来啊,手写链表啊
首先,手写链表要注意的关键就是联系的切开和缝合。
在这里,我们会尝试用Java数组来实现简单的单向链表。
?主要思路:
- 创建数组: 建立两个等长的数组(data、right),长度为初始数据的2倍(防止后续做增强操作时下标越界)
- 定义数组: 数组data存储链表内容,数组right存储游标
说到游标,聪明的你应该懂我了,主要思路大致这样:
假设初始数据长度为n,即会创建一个n*2长度的数组,当我们增加一个数字a到下标b后面,就会将data数组下标n的0修改为k,而right[b]则会变更为n。那么 ,手写链表的除了一个值,就是data[right[i]],而第一个值呢,就是data[0]。
复杂?那画个图吧~
简单来说,就是data数组读取了第0号位置的数据后,通过下表找到right数组中对应的值,通过这个值去查找data表的对应下标,就这样完成中间的“链接”。
让我们用Java代码实现一下吧。
主要功能:
1 输入自定义长度的数组
2 选定在哪个位置插入数字 66
3 输出结果
import java.util.Arrays;
import java.util.Scanner;
public class MyList {
public static void main(String[] args) {
int[]data,right;
int i,t ,n;
System.out.print("请输入初始链表长度:");
n = new Scanner(System.in).nextInt();
data=new int[n*2];
right=new int[n*2];
System.out.println("请依次输入相应"+n+"个数字:");
for(i=0;i<n;i++) {
data[i]=new Scanner(System.in).nextInt();
//System.out.println(data[i]);
if(i<n-1) {right[i]=i+1;}else {right[i]=0;}
}
System.out.println("初始链表内容为:"+Arrays.toString(data));
//System.out.println("指针链表内容为:"+Arrays.toString(right));
System.out.print("需要在哪个下标后插入一个66");
t=new Scanner(System.in).nextInt();
while(t<0 || t>n-1) {
System.out.print("请在0-"+(n-1)+"中间选择t:");
t=new Scanner(System.in).nextInt();
}
for(i=t+1;i<n+1;i++) {//逐个变更后续right链接
right[i]=i;
}
data[n]=66; //在data数组插入66
right[t]=n; //将66对应的下标数字赋予right数组要插入66的位置
right[n]=0; //确保right数组最后一个数值是0,用来指引data[0]的位置
//System.out.println("--初始链表内容为:"+Arrays.toString(data));
//System.out.println("--指针链表内容为:"+Arrays.toString(right));
System.out.print("结果输出: ");
System.out.print(data[right[n]]+" ");
for(i=0;i<n;i++) {
System.out.print (data[right[i]]+" "); //实现链表插入功能
}
}
打印输出的结果:
上面的代码能看懂不?来我们根据数据结构画个图吧~
?插入前
?插入后
原链表内容是12345
后来我们在3号位置后面硬插入一个数字66
那么,最后输出的结果是
1 2 3 4 66 5
俗话说,思路最重要,然后你懂没?
这里我们用了right数组实现向右指针的链接,那向左呢?估计你已经有一个很好的思路去实现双向链表了,根据下标查询数值,更不在话下了,想想这个,是不是有点类似我们的装饰者模式?
?好了,结束了,给点个赞不?