目录
一、链表
二、代码实现
1.创建结点
2.构造函数
3.链表的相关属性
4.添加虚拟节点
5.判断链表是否为空
6.添加方法
(1)在头部添加
(2)在尾部添加
(3)在索引位置添加
(4)对头插法和尾插法代码进行简化(调用任意位置添加的方法)
7.打印链表(遍历,重写toString方法)
8.获取链表元素个数(链表长度)
9.获取链表结点
(1)获取头结点
(2)获取尾结点
(3)获取指定位置结点
10.判断结点是否存在
11.删除结点
(1)删除头结点
(2)删除尾节点
(3)在指定位置删除结点
(4)删除元素
(5)不使用虚拟节点删除
一、链表
链表是真正的动态数据结构,也是最简单的动态数据结构。
动态数据结构还有:二叉树,trie等
优点:不需要处理固定容量的问题,真正的动态
缺点:丧失了随机访问的能力
学习链表有助于更深理解引用和递归
二、代码实现
1.创建结点
使用内部类来创建结点
//使用内部类——创建结点 class Node<T>{ T data;//节点本身 Node next;//指向下个节点
2.构造函数
两个构造函数(传入的参数不同)
public Node(T data){ this.data=data; this.next=null; } public Node(T data,Node next){ this.data=data; this.next=null; } }
3.链表的相关属性
头结点和结点个数(链表长度)
private Node head;//头结点 private int size;//表示链表中有多少个结点
4.添加虚拟节点
public SelfLinkedList(){ //创建一个虚拟头结点 Node dummyHead=new Node(Integer.MIN_VALUE); this.head=dummyHead; this.size=0; dummyHead.next=head; }
5.判断链表是否为空
public boolean isEmpty(){ return this.size==0; }
6.添加方法
(1)在头部添加
public void addHead(T data){ //创建一个节点 Node node= new Node(data); //挂接 node.next=this.head; this.head=node; //更新size this.size++; }
(2)在尾部添加
public void addTail(T data){ Node node=new Node(data); //针对空链表做处理 if(this.head==null){ this.head=node; this.size++; return; } Node curNode=this.head; while(curNode.next!=null){ curNode=curNode.next; } curNode.next=node; this.size++; }
(3)在索引位置添加
//在任意位置添加 public void add(int index,T data){ //判断index是否有效 if(index<0||index>this.size){ throw new IllegalArgumentException("index is invalid"); } //创建一个节点 Node node= new Node(data); //特殊处理1:如果索引为0, if(index==0){ this.head=new Node(data,this.head); this.size++; return; } //特殊处理2:链表为空(异常已抛出) //找前驱结点,从头开始找,让索引移动index-1次 Node pre=this.head; for(int i=1;i<=index;i++){ pre=pre.next; } //开始进行结点的挂接 node.next=pre.next; pre.next=node; this.size++; }
(4)对头插法和尾插法代码进行简化(调用任意位置添加的方法)
//在头部添加 public void addHead(T data){ add(0,data); } //在尾部添加 public void addTail(T data){ add(this.size,data); }
7.打印链表(遍历,重写toString方法)
//打印整个链表 @Override public String toString() { //从this。head开始一直向后 Node curNode=this.head.next; StringBuilder sb=new StringBuilder(); while(curNode!=null){ sb.append(curNode.data+"-->"); curNode=curNode.next; } sb.append("null"); return sb.toString(); }
8.获取链表元素个数(链表长度)
//获取链表中元素的个数 public int getSize(){ return this.size; }
9.获取链表结点
(1)获取头结点
//获取链表的头结点 public Optional getFirst(){ if(this.head.next==null){ return Optional.empty(); } return Optional.ofNullable(this.head.next.data); }
(2)获取尾结点
//获取链表的尾结点 public Optional getLast(){ if(this.head.next==null){ return Optional.empty(); } Node<T> curNode=this.head; while(curNode.next!=null){ curNode=curNode.next; } return Optional.of(curNode.data); }
(3)获取指定位置结点
//从链表中获取任意位置的结点 public T get(int index) { if (index < 0 || index >= this.size) { throw new IllegalArgumentException("index is invalid"); } Node<T> curNode = this.head.next; int i = 0; while (i < index) { curNode = curNode.next; i++; } return curNode.data; }
10.判断结点是否存在
//从链表中查找指定位置元素是否存在 public boolean contains(T data) { Node curNode = this.head.next; while (curNode != null) { if (curNode.data.equals(data)) { return true; } } return false; }
11.删除结点
(1)删除头结点
//从链表的头部删除元素 public T removeHead() { if (this.isEmpty()) { return null; } Node<T> delNode = this.head.next; this.head.next = delNode.next; delNode.next = null; //更新size; this.size--; return delNode.data; }
(2)删除尾节点
//链表的尾部删除元素 public T removeTail() { if (this.isEmpty()) { return null; } Node<T> pre = this.head; while (pre.next.next != null) { pre = pre.next; } Node<T> delNode = pre.next; pre.next = delNode.next; delNode.next = null; //更新size; this.size--; return delNode.data; }
(3)在指定位置删除结点
//删除任意位置的结点 public T remove(int index){ if(index<0||index>=this.size){ throw new IllegalArgumentException("index is invalid"); } //找删除结点的前驱 Node<T>pre=this.head; int i=0; while(i<index){ pre=pre.next; i++; } Node<T>delNode=pre.next; pre.next=delNode.next; delNode.next=null; this.size--; return delNode.data; }
(4)删除元素
//根据值从链表中删除元素 public int removeByValue(T value){ int count=0; //定义前驱结点 Node<T>pre=this.head; while(pre.next!=null){ Node curNode=pre.next; if(curNode.data.equals(value)){ pre.next=pre.next.next; curNode.next=null; this.size--; count++; }else{ pre=pre.next; } } return count; }
(5)不使用虚拟节点删除
//不使用虚拟头结点 public int removeByValue2(T val){ int count = 0; Node<T> realHead = this .head.next; while(realHead!=null&&realHead.data.equals(val)){ realHead=realHead.next; this.size--; count++; } //判断链表是否为空 if(realHead==null){ return count; } //头结点不是删除的点 Node pre = realHead; while(pre.next!=null){ Node<T> delNode = pre.next; if(delNode.equals(val)){ pre.next = delNode .next; delNode.next = null; this.size--; count++; }else{ pre = pre .next; } } return count; }
三、完整代码
package com.algo.lesson.lesson03; import java.util.Optional; import java.util.Random; public class SelfLinkedList<T> { //使用内部类——创建结点 class Node<T> { T data;//节点本身 Node next;//指向下个节点 public Node(T data) { this.data = data; this.next = null; } public Node(T data, Node next) { this.data = data; this.next = null; } } //链表相关的属性和方法 private Node head;//头结点 private int size;//表示链表中有多少个结点 public SelfLinkedList() { //创建一个虚拟头结点 Node dummyHead = new Node(Integer.MIN_VALUE); this.head = dummyHead; this.size = 0; dummyHead.next = head; } //判断链表是否为空 public boolean isEmpty() { return this.size == 0; } //向链表中添加结点 //在头部添加 public void addHead(T data) { /*//创建一个节点 Node node= new Node(data); //挂接 node.next=this.head; this.head=node; //更新size this.size++;*/ add(0, data); } //在尾部添加 public void addTail(T data) { /*Node node=new Node(data); //针对空链表做处理 if(this.head==null){ this.head=node; this.size++; return; } Node curNode=this.head; while(curNode.next!=null){ curNode=curNode.next; } curNode.next=node; this.size++;*/ add(this.size, data); } //在任意位置添加 public void add(int index, T data) { //判断index是否有效 if (index < 0 || index > this.size) { throw new IllegalArgumentException("index is invalid"); } //创建一个节点 Node node = new Node(data); //特殊处理1:如果索引为0, if (index == 0) { this.head = new Node(data, this.head); this.size++; return; } //特殊处理2:链表为空(异常已抛出) //找前驱结点,从头开始找,让索引移动index-1次 Node pre = this.head; for (int i = 1; i <= index; i++) { pre = pre.next; } //开始进行结点的挂接 node.next = pre.next; pre.next = node; this.size++; } //打印整个链表 @Override public String toString() { //从this。head开始一直向后 Node curNode = this.head.next; StringBuilder sb = new StringBuilder(); while (curNode != null) { sb.append(curNode.data + "-->"); curNode = curNode.next; } sb.append("null"); return sb.toString(); } //从链表中查找指定位置元素是否存在 public boolean contains(T data) { Node curNode = this.head.next; while (curNode != null) { if (curNode.data.equals(data)) { return true; } } return false; } //获取链表中元素的个数 public int getSize() { return this.size; } //获取链表的头结点 public Optional getFirst() { if (this.head.next == null) { return Optional.empty(); } return Optional.ofNullable(this.head.next.data); } //获取链表的尾结点 public Optional getLast() { if (this.head.next == null) { return Optional.empty(); } Node<T> curNode = this.head; while (curNode.next != null) { curNode = curNode.next; } return Optional.of(curNode.data); } //从链表中获取任意位置的结点 public T get(int index) { if (index < 0 || index >= this.size) { throw new IllegalArgumentException("index is invalid"); } Node<T> curNode = this.head.next; int i = 0; while (i < index) { curNode = curNode.next; i++; } return curNode.data; } //从链表的头部删除元素 public T removeHead() { if (this.isEmpty()) { return null; } Node<T> delNode = this.head.next; this.head.next = delNode.next; delNode.next = null; //更新size; this.size--; return delNode.data; } //链表的尾部删除元素 public T removeTail() { if (this.isEmpty()) { return null; } Node<T> pre = this.head; while (pre.next.next != null) { pre = pre.next; } Node<T> delNode = pre.next; pre.next = delNode.next; delNode.next = null; //更新size; this.size--; return delNode.data; } //删除任意位置的结点 public T remove(int index){ if(index<0||index>=this.size){ throw new IllegalArgumentException("index is invalid"); } //找删除结点的前驱 Node<T>pre=this.head; int i=0; while(i<index){ pre=pre.next; i++; } Node<T>delNode=pre.next; pre.next=delNode.next; delNode.next=null; this.size--; return delNode.data; } //根据值从链表中删除元素 public int removeByValue(T value){ int count=0; //定义前驱结点 Node<T>pre=this.head; while(pre.next!=null){ Node curNode=pre.next; if(curNode.data.equals(value)){ pre.next=pre.next.next; curNode.next=null; this.size--; count++; }else{ pre=pre.next; } } return count; } //不使用虚拟头结点 public int removeByValue2(T val){ int count = 0; Node<T> realHead = this .head.next; while(realHead!=null&&realHead.data.equals(val)){ realHead=realHead.next; this.size--; count++; } //判断链表是否为空 if(realHead==null){ return count; } //头结点不是删除的点 Node pre = realHead; while(pre.next!=null){ Node<T> delNode = pre.next; if(delNode.equals(val)){ pre.next = delNode .next; delNode.next = null; this.size--; count++; }else{ pre = pre .next; } } return count; }