目标构造简单的单链表
实现功能如下
- 插入数据
- 查询数据
- 移除数据
- 获取Size
- 反转数据
- 遍历数据
代码:
package com.miracle.study.list;
import org.junit.jupiter.api.Test;
import java.util.Iterator;
import java.util.function.Predicate;
/**
* @author Miracle
* @date 2021/4/7 16:34
*/
public class TList<T> implements Iterable<T> {
/**
* 头部节点
*/
private Node<T> head = null;
/**
* 数据量
*/
private int size = 0;
/**
* 节点
* @param <T>
*/
static class Node<T>{
/**
* 存储数据
*/
private T data;
/**
* 下一个节点位置
*/
private Node<T> next = null;
public Node(T data){
this.data = data;
}
public T get(){
return data;
}
}
/**
* 遍历
* @return
*/
@Override
public Iterator<T> iterator() {
return new Iterator<T>() {
int cursor = 0;
@Override
public boolean hasNext() {
return cursor != size;
}
@Override
public T next() {
var node = head;
for (int i = 0; i < cursor; i++){
node = node.next;
}
cursor++;
return node.get();
}
};
}
/**
* 头插法
* @param data 数据
*/
public void insert(T data){
var node = new Node<>(data);
// 新节点指针指向当前头节点
node.next = head;
// 修改头节点指向当前节点
head = node;
// 数据量+1
size++;
}
/**
* 递归尾插法
* @param node
* @param data
* @return
*/
private Node<T> tailInsert(Node<T> node, T data){
if (node != null){
node.next = tailInsert(node.next, data);
}else {
node = new Node<>(data);
}
return node;
}
public void tailInsert(T data){
this.head = tailInsert(head, data);
size++;
}
/**
* 查找数据
* @param predicate
* @return
*/
public Node<T> find(Predicate<T> predicate){
if (head == null){
return null;
}
if (predicate.test(head.get())){
return head;
}
var node = head;
while (node.next != null){
node = node.next;
if (predicate.test(node.get())){
return node;
}
}
return null;
}
/**
* 移除
* @param node
*/
public void remove(Node<T> node){
// 判断节点是否为空
if (node == null){
return;
}
// 判断节点是否为头部直接返回
if (node == head){
head = head.next;
}
var p = head;
var pn = head.next;
while (pn != null){
// 判断是否是要删除的节点
if (pn == node){
// 将指向要删除的节点的指针指向其后一个节点
p.next = pn.next;
// 数据量 -1
size --;
}
// 移动到下一个位置继续判断
p = pn;
pn = pn.next;
}
}
/**
* 获取数据数量,遍历获取
* @return
*/
public int Size(){
int size = 0;
var p = head;
while (p != null){
p = p.next;
size++;
}
return size;
}
/**
* 获取数据数量,直接获取,需要在插入和移除操作中做数据修改
* @return
*/
public int getSize(){
return this.size;
}
/**
* 反转
*/
public void reverse(){
// 前一个节点指针
Node<T> prev = null;
// 当前节点指针
var current = head;
// 后一个节点指针
Node<T> next = null;
while (current != null){
// 记录下一个节点
next = current.next;
// 改变当前节点的链路方向
current.next = prev;
// 记录当前节点
prev = current;
// 移动节点
current = next;
}
head = prev;
}
/**
* 迭代反转
* @param node
* @return
*/
private Node<T> iteReverse(Node<T> node){
// 主要用于判断是否是最后一个节点,它被反转成为头部要返回去。
if (node == null || node.next == null){
return node;
}
// 获取最后一个节点(反转后的头节点)
var result = iteReverse(node.next);
// 将后一个节点的指针指向当前节点
node.next.next = node;
// 去除当前节点的指针指向
node.next = null;
// 返回头部节点回去
return result;
}
public void iteReverse(){
head = iteReverse(head);
}
@Override
public String toString(){
var node = head;
StringBuilder stringBuilder = new StringBuilder();
var i = 0;
while (node != null){
stringBuilder.append(i + ":" + node.get() + " ");
node = node.next;
i++;
}
return stringBuilder.toString();
}
@Test
public void test(){
TList<Integer> tList = new TList<>();
// 头部插入
tList.insert(1);
tList.insert(2);
// 尾部插入
tList.tailInsert(3);
tList.tailInsert(4);
// 查找
var node3 = tList.find(a -> a == 3);
// 移除
tList.remove(node3);
// 三指针反转
tList.reverse();
// 迭代反转
tList.iteReverse();
// 遍历
for (var i : tList){
System.out.println(i);
}
}
}