学一哈静态链表
描述以及特点
一个固定大小的数组
首位两端是不存储数据的
首(0标)节点元素的cur 存储下一空闲位置的下标
数组尾端元素cur存放链表的起点
通过改变元素的cur 来实现元素的位置调整
结构图
循环截至条件
节点元素的cur 是否==0
JAVA代码实现
package com.example.demo.data;
import java.util.Objects;
/**
* @author tm
* @date 2021-06-25 14:49
* @description java 实现带头节点的循环单链表
*/
public class CycleSingleLinkList<T> {
public static void main(String[] args) {
CycleSingleLinkList<Object> objectCycleSingleLinkList = new CycleSingleLinkList<>();
System.out.println("===========选择头插法(默认尾插法)============");
objectCycleSingleLinkList.headInsert = false;
System.out.println("===========新增============");
for (int i = 0; i < 10; i++) {
objectCycleSingleLinkList.add(i);
}
System.out.println("新增完后长度为:" + objectCycleSingleLinkList.size + " 元素情况:" + objectCycleSingleLinkList.toString());
objectCycleSingleLinkList.add(0, new Integer("1000"));
System.out.println("0标增加数据为1000的节点后长度为:" + objectCycleSingleLinkList.size + " 元素情况:" + objectCycleSingleLinkList.toString());
System.out.println("===========删除============");
Boolean remove = objectCycleSingleLinkList.remove(1);
System.out.println("删除第1个节点" + remove + "之后长度为:" + objectCycleSingleLinkList.size + " 元素情况:" + objectCycleSingleLinkList.toString());
Boolean remove1 = objectCycleSingleLinkList.remove(new Integer("9"));
System.out.println("删除数据为9节点" + remove1 + "之后长度为:" + objectCycleSingleLinkList.size + " 元素情况:" + objectCycleSingleLinkList.toString());
System.out.println("===========查询============");
System.out.println("通过数据1000查询" + objectCycleSingleLinkList.get(new Integer("1000")).data);
System.out.println("通过下标0查询" + objectCycleSingleLinkList.get(0).data);
System.out.println("===========修改============");
boolean replace = objectCycleSingleLinkList.replace(0, new Integer(10000));
System.out.println("替换0下标数据为1w:" + replace + "之后长度为:" + objectCycleSingleLinkList.size + " 元素情况:" + objectCycleSingleLinkList.toString());
objectCycleSingleLinkList.replace(new Integer(8), new Integer(800));
System.out.println("替换据8为800:" + "之后长度为:" + objectCycleSingleLinkList.size + " 元素情况:" + objectCycleSingleLinkList.toString());
}
//特定位置替换数据
private boolean replace(int index, T data) {
//检查index 范围
checkPositionIndex(index);
//确定头插 尾插
int currentIndex = getBorder(index);
//获取具体下标的数据
Node<T> current = getPositionPreNode(currentIndex + 1);
current.data = data;
return true;
}
//替换老数据
private T replace(T oldData, T newData) {
//获取具体下标的数据
Node<T> current = get(oldData);
if (null != current) {
current.data = newData;
return oldData;
}
return null;
}
private Node<T> get(int index) {
//范围
checkPositionIndex(index);
//确定头插 尾插
int border = getBorder(index);
//头节点不存在数据 所以从第一个有数据节点开始
Node<T> node = this.head.next;
for (int i = 0; i < border; i++) {
node = node.next;
}
return node;
}
private Node<T> get(T oldData) {
//头节点不存在数据 所以从第一个有数据节点开始
Node<T> node = this.head.next;
while (node != this.head) {
if (Objects.equals(node.data, oldData)) {
return node;
}
node = node.next;
}
return null;
}
//删除特定数据的节点
private Boolean remove(T data) {
Node<T> current = get(data);
if (null == current) {
return true;
}
Node<T> next = current.next;
//小优化 针对尾节点O(n)和非尾节点O(1)删除
if (next != this.head) {
//非尾节点O(1)删除
//将下一个节点的向下引用、数据赋予给当前节点
current.data = next.data;
current.next = next.next;
//help Gc
next.next = null;
next.data = null;
} else {
//尾节点O(n)删除
Node<T> node = this.head;
while (node.next != current) {
node = node.next;
}
node.next = this.head;
//help Gc
current.next = null;
current.data = null;
}
this.size--;
return true;
}
//删除插入的第x 从0开始
private Boolean remove(int index) {
//检查index 范围
checkPositionIndex(index);
//确定是尾插法还是头插法
int border = getBorder(index);
Node<T> pre = getPositionPreNode(border);
Node<T> del = pre.next;
pre.next = del.next;
//help Gc
del.next = null;
del.data = null;
this.size--;
return true;
}
//确定是尾插法还是头插法
private int getBorder(int index) {
int border;
if (this.headInsert) {
//1.头插法(index顺序就是反的)
border = size - index - 1;
} else {
//2.尾插法(index)
border = index;
}
return border;
}
private Node<T> getPositionPreNode(int index) {
Node<T> pre = this.head;
for (int i = 0; i < index; i++) {
pre = pre.next;
}
return pre;
}
//特定位置插入数据节点
private void add(int index, T data) {
//检查index 范围
checkPositionIndex(index);
int border = getBorder(index);
//获取具体下标的数据
Node<T> pre = getPositionPreNode(border);
pre.next = new Node<T>(data, pre.next);
this.size++;
}
//顺序插入数据节点
private void add(T t) {
//头插法
if (this.headInsert) {
Node<T> head = this.head;
head.next = new Node<>(t, head.next);
} else {
//尾插法
Node<T> last = this.head;
while (last.next != this.head) {
last = last.next;
}
last.next = new Node<>(t, this.head);
}
this.size++;
}
//检查下表范围
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size - 1;
}
private String outOfBoundsMsg(int index) {
return "Index: " + index + ", size: " + (size - 1);
}
@Override
public String toString() {
//头节点不存在数据 所以从第一个有数据节点开始
Node<T> node = this.head.next;
StringBuilder stringBuilder = new StringBuilder();
while (node != this.head) {
stringBuilder.append(node.data);
stringBuilder.append(" ");
node = node.next;
}
return stringBuilder.toString();
}
//采用头插法还是尾插法
private boolean headInsert;
//线性表长度
private int size;
//头节点
private Node<T> head;
public CycleSingleLinkList() {
this.head = new Node<>(null, null);
this.head.next = this.head;
}
//定义节点
private static class Node<T> {
//节点数据
private T data;
//后驱引用
private Node<T> next;
public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
}
}