1 实现原理和步骤
单向链表是通过引用next指向下一个节点来实现的,当对链表进行增删操作时,只需移动引用,而不需要移动数据,算法的时间复杂度为O(1)。
问题来了,如果Node1不通过引用next,有什么办法能够快速建立与Node2的连接?答案是通过数组下标。上述节点的数据结构变为:
即使用数据类型为Node的数组来放置链表的所有节点,每个节点中的cur数值存放链表下一个节点的物理下标,这种类型的链表称为静态链表。
其中,物理下标是节点存放在数组的真实下标,而逻辑下标指该节点在链表中的位置。
2 完整代码
package linkedlist;
import java.util.LinkedList;
/**
* 静态链表
*/
public class StaticList<T> {
/**
* 默认大小
*/
private final int DEFAUL_SIZE = 10;
/**
* 静态链表,底层是数组
*/
private Node<T>[] list;
/**
* 空闲节点下标
*/
private int currentFree;
/**
* 静态链表头节点的物理下标
*/
private int head;
/**
* 静态链表长度
*/
private int size;
/**
* 静态链表节点的数据结构
* @param <T>
*/
class Node<T> {
T data;
int cur;
}
/**
* 初始化
*/
public StaticList() {
list = new Node[DEFAUL_SIZE];
for (int i = 0; i < DEFAUL_SIZE; i++) {
list[i] = new Node<T>();
list[i].cur = i + 1;
}
list[DEFAUL_SIZE - 1].cur = -1;
currentFree = 0;
head = 0;
size = 0;
}
/**
* 获取第position个节点的物理下标
*
* @param position
* @return
*/
public int getIndex(int position) {
if (position < 0 || position > size - 1) {
throw new IndexOutOfBoundsException("查询索引越界");
}
int i = 0;
int temp = head;
while (i < position) {
temp = list[temp].cur;
i++;
}
if (i == position) {
return temp;
}
return -1;
}
/**
* 按逻辑位置顺序向静态链表中添加新元素
*
* @param data
* @return
*/
public boolean add(T data) {
if (currentFree >= DEFAUL_SIZE) {
throw new IndexOutOfBoundsException("链表已满,添加数据失败:" + data);
}
list[currentFree].data = data;
currentFree = list[currentFree].cur;
size++;
return true;
}
/**
* 向静态链表指定逻辑位置插入新元素
*
* @param position
* @param data
* @return
*/
public void add(int position, T data) {
if (position < 0 || position >= size) {
throw new IndexOutOfBoundsException("索引越界");
} else if (currentFree >= DEFAUL_SIZE) {
throw new IndexOutOfBoundsException("链表已满,添加数据失败:" + data);
}
list[currentFree].data = data;
int nextCurrentFree = list[currentFree].cur; //空闲节点的后继节点
if (position == 0) { //插入位置在链表头结点
list[getIndex(size - 1)].cur = list[currentFree].cur;
list[currentFree].cur = head;
head = currentFree; //更新链表头结点位置
} else {
int preIndex = getIndex(position - 1); //插入位置前一个节点的真实下标
int nextIndex = list[preIndex].cur; //插入位置后一个节点的真实下标
int preCurrentFree = getIndex(size - 1); //空闲节点的上的前驱节点
list[preIndex].cur = currentFree;
list[currentFree].cur = nextIndex;
list[preCurrentFree].cur = nextCurrentFree;
}
currentFree = nextCurrentFree;
size++;
}
/**
* 获取静态链表制定逻辑位置的节点
* position
*
* @param position
* @return
*/
public Node<T> get(int position) {
int tIndex = getIndex(position);
if (tIndex != -1) {
return list[tIndex];
}
return null;
}
/**
* 查询静态链表长度
*
* @return
*/
public int size() {
return size;
}
/**
* 刪除链表指定逻辑位置元素
*
* @param position
* @return 返回
*/
public T delete(int position) {
if (position < 0 || position >= size) {
throw new IndexOutOfBoundsException("索引越界");
}
int index = getIndex(position); //待删节点的物理位置
int preIndex = -1; //待删节点的前驱节点的物理位置
int preCurrentFree = getIndex(size - 1); //空闲节点的前驱节点的物理位置
T oldValue = list[index].data; //清楚待删节点中的值
list[index].data = null;
//释放待删节点的物理位置
if(position == 0){ //待删节点为头节点
head = list[index].cur;
list[preCurrentFree].cur = index;
list[index].cur = currentFree;
currentFree = index;
}else if(position == size - 1){ //待删节点为尾节点
currentFree = index;
}else{
preIndex = getIndex(position - 1);
list[preIndex].cur = list[index].cur;
list[preCurrentFree].cur = index;
list[index].cur = currentFree;
currentFree = index;
}
size--;
return oldValue;
}
/**
* 修改链表指定逻辑位置节点
* @param position
* @param data
* @return
*/
public T Set(int position, T data) {
if (position < 0 || position >= size) {
throw new IndexOutOfBoundsException("索引越界");
}
int index = getIndex(position);
T oldValue = list[index].data;
list[index].data = data;
return oldValue;
}
/**
* 按照静态链表的逻辑顺序打印所有节点信息
* @return
*/
@Override
public String toString() {
if (size == 0){
return "{}";
}
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < size; i++) {
sb.append("{链表中的位置position:" + i + ", 数据data:" + get(i).data + ", 在数组中的位置index:" + getIndex(i) + ", 游标cur:" + get(i).cur + "},\n");
}
sb.replace(sb.length() - 2, sb.length(), "]");
return sb.toString();
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
StaticList<String> list = new StaticList();
int num = list.DEFAUL_SIZE - 3;
System.out.println("===========================添加数据=======================");
for (int i = 0; i < num; i++) {
list.add(i + "_" + i);
}
System.out.println(list.toString());
System.out.println("===========================插入链表头结点=======================");
list.add(0, "7_7");
System.out.println(list.toString());
System.out.println("===========================插入链表中间节点=======================");
list.add(4, "8_8");
System.out.println(list.toString());
System.out.println("===========================插入链表的尾节点=======================");
list.add(list.size - 1, "9_9");
System.out.println(list.toString());
System.out.println("===========================删除头结点=======================");
list.delete(0);
System.out.println(list.toString());
System.out.println("===========================删除中间结点=======================");
list.delete(4);
System.out.println(list.toString());
System.out.println("===========================删除中间结点=======================");
list.delete(4);
System.out.println(list.toString());
System.out.println("===========================删除尾结点=======================");
list.delete(list.size - 1);
System.out.println(list.toString());
System.out.println("===========================插入节点=======================");
list.add("10_10");
System.out.println(list.toString());
System.out.println("===========================插入节点=======================");
list.add("11_11");
System.out.println(list.toString());
System.out.println("===========================插入节点=======================");
list.add("12_12");
System.out.println(list.toString());
System.out.println("===========================修改节点的值=======================");
list.Set(list.size - 1, "12_12");
System.out.println(list.toString());
}
}
}
3 输出结果
- 3.1 添加数据
[{链表中的位置position:0, 数据data:0_0, 在数组中的位置index:0, 游标cur:1},
{链表中的位置position:1, 数据data:1_1, 在数组中的位置index:1, 游标cur:2},
{链表中的位置position:2, 数据data:2_2, 在数组中的位置index:2, 游标cur:3},
{链表中的位置position:3, 数据data:3_3, 在数组中的位置index:3, 游标cur:4},
{链表中的位置position:4, 数据data:4_4, 在数组中的位置index:4, 游标cur:5},
{链表中的位置position:5, 数据data:5_5, 在数组中的位置index:5, 游标cur:6},
{链表中的位置position:6, 数据data:6_6, 在数组中的位置index:6, 游标cur:7}]
- 3.2 插入链表头结
[{链表中的位置position:0, 数据data:7_7, 在数组中的位置index:7, 游标cur:0},
{链表中的位置position:1, 数据data:0_0, 在数组中的位置index:0, 游标cur:1},
{链表中的位置position:2, 数据data:1_1, 在数组中的位置index:1, 游标cur:2},
{链表中的位置position:3, 数据data:2_2, 在数组中的位置index:2, 游标cur:3},
{链表中的位置position:4, 数据data:3_3, 在数组中的位置index:3, 游标cur:4},
{链表中的位置position:5, 数据data:4_4, 在数组中的位置index:4, 游标cur:5},
{链表中的位置position:6, 数据data:5_5, 在数组中的位置index:5, 游标cur:6},
{链表中的位置position:7, 数据data:6_6, 在数组中的位置index:6, 游标cur:8}]
- 3.3 插入链表中间
[{链表中的位置position:0, 数据data:7_7, 在数组中的位置index:7, 游标cur:0},
{链表中的位置position:1, 数据data:0_0, 在数组中的位置index:0, 游标cur:1},
{链表中的位置position:2, 数据data:1_1, 在数组中的位置index:1, 游标cur:2},
{链表中的位置position:3, 数据data:2_2, 在数组中的位置index:2, 游标cur:8},
{链表中的位置position:4, 数据data:8_8, 在数组中的位置index:8, 游标cur:3},
{链表中的位置position:5, 数据data:3_3, 在数组中的位置index:3, 游标cur:4},
{链表中的位置position:6, 数据data:4_4, 在数组中的位置index:4, 游标cur:5},
{链表中的位置position:7, 数据data:5_5, 在数组中的位置index:5, 游标cur:6},
{链表中的位置position:8, 数据data:6_6, 在数组中的位置index:6, 游标cur:9}]
- 3.4插入链表的尾节点
[{链表中的位置position:0, 数据data:7_7, 在数组中的位置index:7, 游标cur:0},
{链表中的位置position:1, 数据data:0_0, 在数组中的位置index:0, 游标cur:1},
{链表中的位置position:2, 数据data:1_1, 在数组中的位置index:1, 游标cur:2},
{链表中的位置position:3, 数据data:2_2, 在数组中的位置index:2, 游标cur:8},
{链表中的位置position:4, 数据data:8_8, 在数组中的位置index:8, 游标cur:3},
{链表中的位置position:5, 数据data:3_3, 在数组中的位置index:3, 游标cur:4},
{链表中的位置position:6, 数据data:4_4, 在数组中的位置index:4, 游标cur:5},
{链表中的位置position:7, 数据data:5_5, 在数组中的位置index:5, 游标cur:9},
{链表中的位置position:8, 数据data:9_9, 在数组中的位置index:9, 游标cur:6},
{链表中的位置position:9, 数据data:6_6, 在数组中的位置index:6, 游标cur:-1}]
- 3.5删除头结点
[{链表中的位置position:0, 数据data:0_0, 在数组中的位置index:0, 游标cur:1},
{链表中的位置position:1, 数据data:1_1, 在数组中的位置index:1, 游标cur:2},
{链表中的位置position:2, 数据data:2_2, 在数组中的位置index:2, 游标cur:8},
{链表中的位置position:3, 数据data:8_8, 在数组中的位置index:8, 游标cur:3},
{链表中的位置position:4, 数据data:3_3, 在数组中的位置index:3, 游标cur:4},
{链表中的位置position:5, 数据data:4_4, 在数组中的位置index:4, 游标cur:5},
{链表中的位置position:6, 数据data:5_5, 在数组中的位置index:5, 游标cur:9},
{链表中的位置position:7, 数据data:9_9, 在数组中的位置index:9, 游标cur:6},
{链表中的位置position:8, 数据data:6_6, 在数组中的位置index:6, 游标cur:7}]
- 3.6删除中间结点
[{链表中的位置position:0, 数据data:0_0, 在数组中的位置index:0, 游标cur:1},
{链表中的位置position:1, 数据data:1_1, 在数组中的位置index:1, 游标cur:2},
{链表中的位置position:2, 数据data:2_2, 在数组中的位置index:2, 游标cur:8},
{链表中的位置position:3, 数据data:8_8, 在数组中的位置index:8, 游标cur:4},
{链表中的位置position:4, 数据data:4_4, 在数组中的位置index:4, 游标cur:5},
{链表中的位置position:5, 数据data:5_5, 在数组中的位置index:5, 游标cur:9},
{链表中的位置position:6, 数据data:9_9, 在数组中的位置index:9, 游标cur:6},
{链表中的位置position:7, 数据data:6_6, 在数组中的位置index:6, 游标cur:3}]
- 3.7删除中间结点
[{链表中的位置position:0, 数据data:0_0, 在数组中的位置index:0, 游标cur:1},
{链表中的位置position:1, 数据data:1_1, 在数组中的位置index:1, 游标cur:2},
{链表中的位置position:2, 数据data:2_2, 在数组中的位置index:2, 游标cur:8},
{链表中的位置position:3, 数据data:8_8, 在数组中的位置index:8, 游标cur:5},
{链表中的位置position:4, 数据data:5_5, 在数组中的位置index:5, 游标cur:9},
{链表中的位置position:5, 数据data:9_9, 在数组中的位置index:9, 游标cur:6},
{链表中的位置position:6, 数据data:6_6, 在数组中的位置index:6, 游标cur:4}]
- 3.8删除尾结点
[{链表中的位置position:0, 数据data:0_0, 在数组中的位置index:0, 游标cur:1},
{链表中的位置position:1, 数据data:1_1, 在数组中的位置index:1, 游标cur:2},
{链表中的位置position:2, 数据data:2_2, 在数组中的位置index:2, 游标cur:8},
{链表中的位置position:3, 数据data:8_8, 在数组中的位置index:8, 游标cur:5},
{链表中的位置position:4, 数据data:5_5, 在数组中的位置index:5, 游标cur:9},
{链表中的位置position:5, 数据data:9_9, 在数组中的位置index:9, 游标cur:6}]
- 3.9插入节点
[{链表中的位置position:0, 数据data:0_0, 在数组中的位置index:0, 游标cur:1},
{链表中的位置position:1, 数据data:1_1, 在数组中的位置index:1, 游标cur:2},
{链表中的位置position:2, 数据data:2_2, 在数组中的位置index:2, 游标cur:8},
{链表中的位置position:3, 数据data:8_8, 在数组中的位置index:8, 游标cur:5},
{链表中的位置position:4, 数据data:5_5, 在数组中的位置index:5, 游标cur:9},
{链表中的位置position:5, 数据data:9_9, 在数组中的位置index:9, 游标cur:6},
{链表中的位置position:6, 数据data:10_10, 在数组中的位置index:6, 游标cur:4}]
- 3.10插入节点
[{链表中的位置position:0, 数据data:0_0, 在数组中的位置index:0, 游标cur:1},
{链表中的位置position:1, 数据data:1_1, 在数组中的位置index:1, 游标cur:2},
{链表中的位置position:2, 数据data:2_2, 在数组中的位置index:2, 游标cur:8},
{链表中的位置position:3, 数据data:8_8, 在数组中的位置index:8, 游标cur:5},
{链表中的位置position:4, 数据data:5_5, 在数组中的位置index:5, 游标cur:9},
{链表中的位置position:5, 数据data:9_9, 在数组中的位置index:9, 游标cur:6},
{链表中的位置position:6, 数据data:10_10, 在数组中的位置index:6, 游标cur:4},
{链表中的位置position:7, 数据data:11_11, 在数组中的位置index:4, 游标cur:3}]
- 3.11插入节点
[{链表中的位置position:0, 数据data:0_0, 在数组中的位置index:0, 游标cur:1},
{链表中的位置position:1, 数据data:1_1, 在数组中的位置index:1, 游标cur:2},
{链表中的位置position:2, 数据data:2_2, 在数组中的位置index:2, 游标cur:8},
{链表中的位置position:3, 数据data:8_8, 在数组中的位置index:8, 游标cur:5},
{链表中的位置position:4, 数据data:5_5, 在数组中的位置index:5, 游标cur:9},
{链表中的位置position:5, 数据data:9_9, 在数组中的位置index:9, 游标cur:6},
{链表中的位置position:6, 数据data:10_10, 在数组中的位置index:6, 游标cur:4},
{链表中的位置position:7, 数据data:11_11, 在数组中的位置index:4, 游标cur:3},
{链表中的位置position:8, 数据data:12_12, 在数组中的位置index:3, 游标cur:7}]
- 3.12修改节点的值
[{链表中的位置position:0, 数据data:0_0, 在数组中的位置index:0, 游标cur:1},
{链表中的位置position:1, 数据data:1_1, 在数组中的位置index:1, 游标cur:2},
{链表中的位置position:2, 数据data:2_2, 在数组中的位置index:2, 游标cur:8},
{链表中的位置position:3, 数据data:8_8, 在数组中的位置index:8, 游标cur:5},
{链表中的位置position:4, 数据data:5_5, 在数组中的位置index:5, 游标cur:9},
{链表中的位置position:5, 数据data:9_9, 在数组中的位置index:9, 游标cur:6},
{链表中的位置position:6, 数据data:10_10, 在数组中的位置index:6, 游标cur:4},
{链表中的位置position:7, 数据data:11_11, 在数组中的位置index:4, 游标cur:3},
{链表中的位置position:8, 数据data:12_12, 在数组中的位置index:3, 游标cur:7}]
4 参考文献
[1]程杰. 大话数据结构[M]. 清华大学出版社,2011