目录
一、链表的基础定义
链表是线性表的一种,但在内存中不一定是连续存储的,而是可以存在于内存中未被占用的任意位置。基于此,链表这种数据结构,除了要存储数据元素的信息外,还需要存储它的后继元素的存储地址。
链表中几个重要概念:
结点——链表所占用的一个内存块,一个结点包括数据域和指针域两部分。数据域用于存储数据信息data,指针域用于存储下个结点的地址next,通常叫做后继指针。
头结点——链表中的第一个结点,只要知道了头结点在内存中的地址,就可根据其指针域存储的下一个结点的地址找到下一个结点。
尾结点——链表中的最后一个结点,由于是链表中的最后一个结点,它的指针域存储的不是下一个结点的地址而是NULL,以此来表示是链表的尾结点。
二、Java中定义一个数据节点
private class Node {
//数据域
T data;
//指针域
Node next;
public Node(T data, Node next) {
this.data = data;
this.next = next;
}
public Node(T data) {
this.data = data;
}
@Override
public String toString() {
return "Node{" +
"data=" + data +
", next=" + next +
'}';
}
}
三、查找特定位置的链表节点
public Node get(int index) {
if (index < 0 || index >= size) {
return null;
} else {
Node temp = head;
//从头结点开始遍历至index位置
for (int i = 0; i < index; i++) {
temp = temp.next;
}
return temp;
}
}
四、向链表指定位置添加新的结点
public void insert(int index, T data) {
if (index < 0 || index > size) {
throw new RuntimeException("插入超出范围");
}
Node newNode = new Node(data);
//头插
if (index == 0) {
if (this.size > 0) {
newNode.next = head;
}
head = newNode;
}
//尾插
else if (index == size) {
tail.next = newNode;
tail = newNode;
} else {
//获取要插入位置的前一个节点
Node preNode = get(index - 1);
//将要当前节点的指针指向前一个节点的下一个节点
newNode.next = preNode.next;
//将前一个节点的指针指向当前节点
preNode.next = newNode;
}
size++;
if (size == 1) {
tail = head;
}
}
五、在链表末尾添加新的节点
public void add(T data) {
Node newNode = new Node(data);
//长度为0证明
if (size == 0) {
head = newNode;
tail = head;
} else {
tail.next = newNode;
tail = newNode;
}
size++;
}
六、删除指定位置的节点
public void del(int index) {
if (index < 0 || index >= size) {
throw new RuntimeException("删除超出范围");
}
if (index == 0) {
head = head.next;
} else if (index == size - 1) {
Node preNode = get(size - 1);
tail = preNode;
preNode.next = null;
} else {
//删除中间结点
Node preNode = get(index - 1);
preNode.next = preNode.next.next;
}
size--;
}
七、移除末尾节点,并返回对应数据
public T remove() {
if (size == 1) {
T data = head.data;
head = null;
tail = head;
size--;
return data;
} else {
Node preNode = get(size - 2);
T data = tail.data;
preNode.next = null;
tail = preNode;
size--;
return data;
}
}
八、根据节点的值删除对应的节点
public boolean deleteByData(T data) {
boolean flag = false;
if (size == 0) {
return flag;
} else {
Node curNode = head;
//元素位于第一个结点
if (curNode.data == data) {
head = curNode.next;
flag = true;
//当前列表只有一个结点
if (this.size == 1) {
tail = head;
}
size--;
} else {
while (curNode != null) {
Node nextNode = curNode.next;
if (nextNode != null && nextNode.data == data) {
//删除元素为尾结点
if (nextNode.next == null) {
tail = curNode;
curNode.next = null;
} else {
//删除结点为中间结点
curNode.next = curNode.next.next;
}
flag = true;
size--;
break;
}
curNode = curNode.next;
}
}
}
return flag;
}
九、打印输出链表中的值
public void printLinkList() {
if (size == 0) {
System.out.println("链表长度为空");
} else {
Node temp = head;
System.out.print("目前的列表,头结点:" + head.data + ",尾结点:" + tail.data + ",整体:");
while (temp != null) {
System.out.print(temp.data + ",");
temp = temp.next;
}
System.out.println();
}
}
十、整体代码
public class LinkList<T> {
//定义节点
private class Node {
//数据域
T data;
//指针域
Node next;
public Node(T data, Node next) {
this.data = data;
this.next = next;
}
public Node(T data) {
this.data = data;
}
@Override
public String toString() {
return "Node{" +
"data=" + data +
", next=" + next +
'}';
}
}
private Node head;
private Node tail;
private int size;
public LinkList() {
this.head = new Node(null, null);
this.size = 0;
}
public Node get(int index) {
if (index < 0 || index >= size) {
return null;
} else {
Node temp = this.head;
//从头结点开始遍历至index位置
for (int i = 0; i < index; i++) {
temp = temp.next;
}
return temp;
}
}
public void add(T data) {
Node newNode = new Node(data);
if (size == 0) {
head = newNode;
tail = head;
} else {
tail.next = newNode;
tail = newNode;
}
size++;
}
public void insert(int index, T data) {
if (index < 0 || index > size) {
throw new RuntimeException("插入超出范围");
}
Node newNode = new Node(data);
//头插
if (index == 0) {
if (this.size > 0) {
newNode.next = head;
}
head = newNode;
}
//尾插
else if (index == size) {
tail.next = newNode;
tail = newNode;
} else {
//获取要插入位置的前一个节点
Node preNode = get(index - 1);
//将要当前节点的指针指向前一个节点的下一个节点
newNode.next = preNode.next;
//将前一个节点的指针指向当前节点
preNode.next = newNode;
}
size++;
if (size == 1) {
tail = head;
}
}
public void del(int index) {
if (index < 0 || index >= size) {
throw new RuntimeException("删除超出范围");
}
if (index == 0) {
head = head.next;
} else if (index == size - 1) {
Node preNode = get(size - 1);
tail = preNode;
preNode.next = null;
} else {
//删除中间结点
Node preNode = get(index - 1);
preNode.next = preNode.next.next;
}
size--;
}
//移除末尾元素,并返回对应数据
public T remove() {
if (size == 1) {
T data = head.data;
head = null;
tail = head;
size--;
return data;
} else {
Node preNode = get(size - 2);
T data = tail.data;
preNode.next = null;
tail = preNode;
size--;
return data;
}
}
//删除特定元素的第一个位置
public boolean deleteByData(T data) {
boolean flag = false;
if (this.size == 0) {
return flag;
} else {
Node curNode = this.head;
//元素位于第一个结点
if (curNode.data == data) {
head = curNode.next;
flag = true;
//当前列表只有一个结点
if (this.size == 1) {
tail = head;
}
this.size--;
} else {
while (curNode != null) {
Node nextNode = curNode.next;
if (nextNode != null && nextNode.data == data) {
//删除元素为尾结点
if (nextNode.next == null) {
this.tail = curNode;
curNode.next = null;
} else {
//删除结点为中间结点
curNode.next = curNode.next.next;
}
flag = true;
this.size--;
break;
}
curNode = curNode.next;
}
}
}
return flag;
}
public void printLinkList() {
if (size == 0) {
System.out.println("链表长度为空");
} else {
Node temp = head;
System.out.print("目前的列表,头结点:" + head.data + ",尾结点:" + tail.data + ",整体:");
while (temp != null) {
System.out.print(temp.data + ",");
temp = temp.next;
}
System.out.println();
}
}
}