简介:
链表是一种最为基础的线性数据结构,在进行链表操作的时候使用若干个节点进行数据的存储,那么在进行数据存储的时候由于本身不具有排序的特点,所以在使用链表查询数据时,它的时间复杂度是“O(n)”,链表可以实现的优化解决方案使用跳表方案来完成,实际上和二分查找的意思相同,利用排序的模式,随机抽取几个中心点进行若干次的比较。
代码实现
/**
* 定义链表接口
* @param <T>
*/
interface ILink<T>{
// 数据添加
public void add(T data);
// 获取数据个数
public int size();
// 判断链表是否为空
public boolean isEmpty();
// 数据转为对象数组
public Object[] toArray();
// 根据指定索引获取数据
public T get(int index);
// 修改数据 返回值:原始数据
public T set(int index, T newData);
// 查找链表中是否存在该数据
public boolean contains(T data);
// 删除数据
public void remove(T data);
// 清空链表
public void clear();
}
/**
* 实现类主要管理根节点
* 内部类Node管理子节点
* @param <T>
*/
class LinkImpl<T> implements ILink<T>{
// 定义内部类
private class Node<T>{
private T data; // 保存数据
private Node<T> next; // 引用,下一个数据的引用
public Node(T data){
this.data = data;
}
// 第1次调用方法:this = LinkImpl.root;
// 第2次调用方法:this = LinkImpl.root.next;
// 第3次调用方法:this = LinkImpl.root.next.next;
public void addNode(Node<T> newNode){// 负责非根节点的节点关系
if(this.next == null){// 当前节点之后有空余
this.next = newNode;// 保存节点
}else{
this.next.addNode(newNode);
}
}
public void toArrayNode(){
LinkImpl.this.returnData[LinkImpl.this.foot++] = this.data;// 获取当前节点数据
if(this.next != null){
this.next.toArrayNode();// 递归调用
}
}
public T getNode(int index){
if(LinkImpl.this.foot++ == index){// 索引相同
return this.data;// 返回当前数据
}else{
if(this.next != null){
return this.next.getNode(index);// 递归调用往下寻找
}else{// 最后一个了
return null;
}
}
}
public T setNode(int index, T newData){
if(LinkImpl.this.foot++ == index){// 找到索引了
T temp = this.data;// 返回数据
this.data = newData;// 修改数据
return temp;// 返回原始数据
}else{
if(this.next != null){
return this.next.setNode(index, newData);
}else{// 已经是最后一个数据了
return null;
}
}
}
public boolean containsNode(T data){
if(this.data.equals(data)){// 数据判断相同
return true;
}else{
if(this.next != null){// 往后查找
return this.next.containsNode(data);
}else{// 最后一个返回false
return false;
}
}
}
/**
* 删除数据
* @param previous 删除数据的父节点
* @param data 要删除的数据
*/
public void removeNode(Node<T> previous, T data){
if(this.data.equals(data)){
previous.next = this.next;// 空出当前节点
}else{
if(this.next != null){// 还有后续节点
this.next.removeNode(this, data);// 递归调用
}
}
}
}
private Node<T> root;// 根节点
private int count;// 统计元素个数
private int foot; // 索引脚标
private Object[] returnData;// 返回数组
/**
* 实现添加数据
* @param data
*/
public void add(T data){
if(data == null){// 排除掉所有的空元素
return;
}
Node<T> newNode = new Node<T>(data);// 将数据封装在节点中
if(this.root == null){ // 没有根节点
this.root = newNode;// 第一个节点作为根节点
}else{
this.root.addNode(newNode);
}
this.count++;
}
/**
* 实现数据的获取
* @return
*/
public int size(){
return this.count;// 返回个数
}
/**
* 判断链表是否为空实现
* @return
*/
public boolean isEmpty(){
return this.size() == 0;
}
/**
* 实现返回数据
* @return
*/
public Object[] toArray(){
if(this.size() == 0){// 没有任何元素保存返回空
return null;
}
this.foot = 0;// 脚标清零
this.returnData = new Object[this.size()];
this.root.toArrayNode();// 交由Node类负责处理
return this.returnData;// 返回处理结果
}
/**
* 根据索引获取数据实现
* @param index
* @return
*/
public T get(int index){
if(index >= this.size()){// 索引超过最大长度
return null;
}
this.foot = 0;// 脚标清零
return this.root.getNode(index);// 交由Node类完成
}
/**
* 数据修改实现
* @param index
* @param newData
* @return 原始数据
*/
public T set(int index, T newData){
if(index >= this.size()){// 索引超过最大长度
return null;
}
this.foot = 0;// 脚标清零
return this.root.setNode(index, newData);// 交由Node类完成
}
/**
* 判断链表中是否有该数据实现方法
* @param data
* @return
*/
public boolean contains(T data){
if(this.size() == 0 || data == null){// 数据为空
return false;
}
return this.root.containsNode(data);
}
/**
* 删除数据实现
* @param data
*/
public void remove(T data){
if(this.size() == 0 || data == null){
return;
}
if(this.root.data.equals(data)) {// 删除数据为根节点
this.root = this.root.next;// 修改根节点为根节点的下一节点
}else{// 后续的判断可以从第2个节点开始
if(this.root.next != null){
this.root.next.removeNode(this.root, data);
}
}
this.count --;
}
/**
* 清空链表数据
*/
public void clear(){
this.root = null;//清空所有引用
this.count = 0;
}
}
/**
* 测试类
*/
public class Test {
public static void main(String[] args) {
ILink<String> link = new LinkImpl<String>();
System.out.println("-----------1.初始化的个数和状态-----------");
System.out.println("数据保存前的个数"+ link.size());
System.out.println("数据保存前是否为空"+ link.isEmpty());
link.add("你");
link.add("好");
System.out.println("-----------2.保存后的个数和状态-----------");
System.out.println("数据保存后的个数"+ link.size());
System.out.println("数据保存后是否为空"+ link.isEmpty());
System.out.println("-----------3.链表转数组-----------");
System.out.print("数据遍历获取:");
Object[] list = link.toArray();
for (Object li : list){
System.out.print(li+"、");
}
System.out.println();
System.out.println("-----------4.获取索引-----------");
System.out.println("获取索引为0的数据:"+link.get(0));
System.out.println("获取索引为1的数据:"+link.get(1));
System.out.println("获取索引为2的数据:"+link.get(2));
System.out.println("-----------5.数据修改-----------");
System.out.println("数据修改:"+link.set(0, "我")+" 修改后:"+link.get(0));
System.out.println("-----------6.是否包含-----------");
System.out.println("链表中是否有“你”:"+link.contains("你"));
System.out.println("链表中是否有“我”:"+link.contains("我"));
System.out.println("-----------7.删除-----------");
link.remove("我");
System.out.println("删除后的根节点:"+link.get(0));
System.out.println("-----------8.清空链表-----------");
link.clear();
System.out.println("链表清空后的数据长度:"+link.size());
}
执行结果: