定义
链表是一种物理上非连续、非顺序的存储结构,数据元素之间的顺序是通过每个元素的指针关联的。
链表由一系列节点组成,每个节点一般至少会包含两部分信息:一部分是元素数据,另一部分是指向下一个元素指针。
与数组相比,链表具有其优势:
1.链表克服了数组需要提前设置长度的缺点,在运行时可以根据需要随意添加元素;
2.计算机的存储空间并不总是连续可用的,而链表可以灵活地使用存储空间,还能更好地对计算机的内存进行动态管理。
链表节点
public class Node {
//节点数据
int val;
//当前节点指向下一个节点数据的链接
Node next;
//当前节点的前一个节点
Node pre;
public Node(int val) {
this.val = val;
}
@Override
public String toString() {
return String.valueOf(val);
}
}
单向链表
链表汇总每个节点存储自己的数据以及下一个节点的指针。
单向链表只能从一个方便遍历。插入时候只能在链表头部插入。
public class SingleList {
//头节点
private Node head;
//元素个数
private int size;
/**
* 从链表头部添加数据
* 当前节点的next==头节点
*/
public int addHead(int val) {
Node cur = new Node(val);
if (size == 0) {
head = cur;
} else {
cur.next = head;
head = cur;
}
size++;
return val;
}
//删除头节点
public int deleteHead() {
if (head == null) {
System.out.println("空队列");
return -1;
}
int val = head.val;
head = head.next;
size--;
return val;
}
//查找指定元素,返回Node
public Node find(int val) {
Node cur = head;
while (cur != null) {
if (val == cur.val) {
return cur;
}
cur = cur.next;
}
return null;
}
/**
* 删除元素
* 目前元素的上一个节点的next = 目标元素的next节点
*/
public boolean delete(int val) {
if (isEmpty()) {
return false;
}
Node pre = head;
Node cur = head;
while (cur.val != val) {
if (cur.next == null) {
return false;
} else {
pre = cur;
cur = cur.next;
}
}
//如果删除的是头节点
if (cur == head) {
head = cur.next;
} else {
pre.next = cur.next;
}
size--;
return true;
}
//是否为空
public boolean isEmpty() {
return size == 0;
}
@Override
public String toString() {
if(isEmpty()){
return "空队列";
}
StringBuilder builder = new StringBuilder();
Node cur = head;
while (cur != null){
builder.append(cur.val).append("->");
cur = cur.next;
}
return builder.toString();
}
public static void main(String[] args) {
SingleList singleList = new SingleList();
System.out.println(singleList);
singleList.addHead(1);
singleList.addHead(2);
singleList.addHead(3);
singleList.addHead(4);
System.out.println(singleList);
System.out.println(singleList.find(2));
System.out.println(singleList.find(5));
singleList.deleteHead();
System.out.println(singleList);
}
}
双端链表
对于单向链表,尾部查询,需要从头遍历到尾部,找到尾部节点,再执行插入,未解决此问题,链表维护一个尾部节点引用。
public class DoubleQueue {
//头节点
private Node head;
//尾部节点
private Node tail;
//节点个数
private int size;
public DoubleQueue() {
this.head = null;
this.tail = null;
this.size = 0;
}
//头部插入
public void addHead(int val){
Node node = new Node(val);
//链表为空
if(size ==0){
head = node;
tail = node;
size ++;
}else{
node.next = head;
head = node;
size ++;
}
}
//尾部插入
public void addTail(int val){
Node node = new Node(val);
if(size ==0){
head = node;
tail = node;
size++;
}else{
node.next = tail;
tail = node;
size++;
}
}
//删除头节点
public boolean deleteHead(){
if(size ==0){
return false;
}
if(head.next == null){
head =null;
tail = null;
}else {
head = head.next;
}
size --;
return true;
}
}
双向链表
双向链表与单向链表相比,可以从头部或者尾部两个方向遍历。
public class MyLinkedList {
//头节点
private Node head;
//尾部节点
private Node tail;
//大小
private int size;
public MyLinkedList() {
head = null;
tail = null;
size =0;
}
//头部添加
public void addHead(int val){
Node node = new Node(val);
if(size ==0){
head = node;
tail = node;
size ++;
}else {
head.pre = node;
node.next = head;
head = node;
size ++;
}
}
//尾部添加
public void addTail(int val){
Node node = new Node(val);
if(size ==0){
head = node;
tail = node;
size ++;
}else {
tail.next = node;
node.pre = tail;
tail = node;
size ++;
}
}
//删除头部
public Node deleteHead(){
if(size == 0){
return null;
}
Node temp = head;
head = head.next;
head.pre = null;
size --;
return temp;
}
//删除尾部元素
public Node deleteTail(){
Node tmp = tail;
if(size !=0){
tail = tail.pre;
tail.next = null;
size--;
}
return tmp;
}
@Override
public String toString() {
if(size >0){
StringBuilder builder = new StringBuilder();
Node cur = head;
while (cur != null){
builder.append(cur.val).append("->");
cur = cur.next;
}
return builder.toString();
}else{
return "空";
}
}
public static void main(String[] args) {
MyLinkedList list = new MyLinkedList();
list.addTail(1);
list.addTail(2);
list.addTail(3);
list.addHead(0);
System.out.println(list);
Node node = list.deleteHead();
System.out.println(node);
System.out.println(list);
}
}
参考:
https://mp.weixin.qq.com/s/UqeYyV_qmQYBvD5DUNwd0A?v=1
https://www.cnblogs.com/ysocean/p/7928988.html