目录
一、链表
二、代码实现
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;//更新sizethis.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方法)
//打印整个链表@Overridepublic 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;//更新sizethis.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++;}//打印整个链表@Overridepublic 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;}