链表数据结构简介
部分设计思想参考 https://blog.csdn.net/qq_33697094/article/details/121544972
-
线性表:也叫顺序表,是多个元素的有序序列,他的元素与索引一一对应。线性表包含两大存储结构:顺序存储结构与链式存储结构
-
数组:是线性表的顺序存储结构,指用地址中一段顺序存储单元依次存储数据元素
-
链表:是线性表的链式存储结构,他的内存是不连续,每一个元素的地址由上一个元素来存储。
数组与链表的底层数据结构决定了他们自身的特点以及使用场景
- 数组在顺序存储单元存储元素,当我们要进行搜索时,它可以直接根据下标来返回需要搜索元素,但当我们进行增删时,则需要来移动大量元素。
- 链表的存储结构是不连续的,除头尾节点,每一个元素需要存储他的数据值以及上一个元素的节点对象,下一个元素的节点对象。 这一数据结构特点导致我们如果想要搜索链表时,每一次都需要从头或尾开始遍历链表。但当我们增加元素时,只需要将上一元素尾指针指向新元素头节点,将下一元素头指针指向新元素尾节点即可。
代码实现
- 废话少说直接上代码
首先创建链表类 以及内部节点类
//链表类
public class DoubleLinkDemo<T> {
private NodeDemo head;//头指针
private NodeDemo tail;//尾指针
private int length;//链表长度
public DoubleLinkDemo(){
this.length = 0;
}
public DoubleLinkDemo(T data){
NodeDemo<T> tNodeDemo = new NodeDemo<>(data);//新建节点对象
this.head = tNodeDemo;//将该节点对象赋值为头节点
this.tail = head;//因为该链表只有一个节点,所以头尾指针指向相同节点
length++;//链表长度+1
}
}
//节点类
class NodeDemo<T>{
T data; //节点存储 数据
NodeDemo pre; //记录上一节点对象
NodeDemo next;//记录下一节点对象
public NodeDemo(){
this(null,null,null);
}
public NodeDemo(T data){
this(data,null,null);
}
public NodeDemo(T data,NodeDemo pre,NodeDemo next){
this.data = data;
this.pre =pre;
this.next = next;
}
}
链表类添加基本方法
- 链表类基本方法包括
//是否为空
public boolean isEmpty(){
}
//长度
public int length(){
}
//头节点插入元素
public void insertHead(T data){
}
//尾节点插入元素
public void insertTail(T data){
}
//指定索引新增元素
public void insertNode(T data,int index){
}
//指定索引删除元素
public void deleteNode(int index){
}
//指定索引获取元素
public Object get(int index){
}
//索引获取node对象 (此方法内部使用 为private)
private NodeDemo getNode(int index) {
}
基本方法实现
public class DoubleLinkDemo<T> {
private NodeDemo head;//头指针
private NodeDemo tail;//尾指针
private int length;//链表长度
public DoubleLinkDemo(){
this.length = 0;
}
public DoubleLinkDemo(T data){
NodeDemo<T> tNodeDemo = new NodeDemo<>(data);
this.head = tNodeDemo;//新节点赋值为头节点
this.tail = head;//由于链表只有一个元素 所以头尾指针都指向同一元素
length++;//链表长度+1
}
//是否为空
public boolean isEmpty() {
return head == null;
}
//长度
public int length() {
return length;
}
//头插入
public void insertHead(T data) {
//为空
if (isEmpty()) {
NodeDemo<T> firstNode = new NodeDemo<>(data);
head = firstNode;
tail = head;
} else {
//链表不为空 则顺序插入
NodeDemo<T> tNodeDemo = new NodeDemo<>(data);
head.pre = tNodeDemo;//当前头节点前指针指向新元素
tNodeDemo.next = head;//新元素尾指针指向当前头节点
head = tNodeDemo;//将新元素赋值为头节点
}
length++;
}
//尾插入节点
public void insertTail(T data) {
if (isEmpty()) {
insertHead(data);
} else {
//不为空顺序插入
NodeDemo<T> tNodeDemo = new NodeDemo<>(data);
this.tail.next = tNodeDemo;//当前尾指针尾节点指向新增元素
tNodeDemo.pre = this.tail;//新元素头节点指向尾节点
tail = tNodeDemo; //新元素设置为尾节点
length++;
}
}
//索引获取node对象
private NodeDemo getNode(int index) {
if (index < 0 || index > length - 1) {
throw new IndexOutOfBoundsException("数组越界");
}
NodeDemo<Object> targetNode = new NodeDemo<>();
targetNode = head;
int tar = 0;
while (targetNode!= null) {
if (tar++ == index) {
return targetNode;
}
targetNode = targetNode.next;
}
return null;
}
//根据指定索引获取节点
public Object get(int index){
return getNode(index).data;
}
//根据指定索引添加数据
public void insertNode(T data,int index){
if(index<0||index>length-1){
throw new IndexOutOfBoundsException("数组越绝");
}else if(index==0){
insertHead(data);
}else if(index ==length-1){
insertTail(data);
}else {
NodeDemo nowNode = getNode(index);
NodeDemo preNode = getNode(index - 1);
NodeDemo<T> insertNode = new NodeDemo<>(data);
preNode.next = insertNode;//节点对象互相赋值
insertNode.pre = preNode;
insertNode.next = nowNode;
nowNode.pre = insertNode;
}
length++;
}
//根据指定索引删除数据
public void deleteNode(int index){
if(index<0||index>length-1){
throw new IndexOutOfBoundsException("数组越界");
}else if(index==0){
head.next.pre = null;
head = head.next;
}else if(index ==length-1){
tail.pre.next = null;
tail =tail.pre;
}else {
NodeDemo preNode = getNode(index - 1);
NodeDemo nextNode = getNode(index + 1);
preNode.next = nextNode;
nextNode.pre = preNode;
}
length--;
}
}
class NodeDemo<T>{
T data;
NodeDemo pre;
NodeDemo next;
public NodeDemo(){
this(null,null,null);
}
public NodeDemo(T data){
this(data,null,null);
}
public NodeDemo(T data,NodeDemo pre,NodeDemo next){
this.data = data;
this.pre =pre;
this.next = next;
}
}
测试链表
public class Test {
public static void main(String[] args) {
DoubleLinkDemo<Integer> doubleLinkDemo = new DoubleLinkDemo<>();
System.out.println(doubleLinkDemo.isEmpty());
doubleLinkDemo.insertTail(1);
System.out.println(doubleLinkDemo.isEmpty());
System.out.println(doubleLinkDemo.get(0));
doubleLinkDemo.insertHead(0);
System.out.println(doubleLinkDemo.get(0));
doubleLinkDemo.insertTail(2);
System.out.println(doubleLinkDemo.get(2));
doubleLinkDemo.insertHead(123);
System.out.println(doubleLinkDemo.get(0));
doubleLinkDemo.insertTail(456);
System.out.println(doubleLinkDemo.get(4));
doubleLinkDemo.deleteNode(4);
System.out.println(doubleLinkDemo.get(4));
}
}
输出结果