数组是一个定长的线性结构。一旦我们的内容不足或者内容过多,都有可能造成空间浪费。可以采用火车车厢的设计模式,动态进行车厢的挂载,这就好比链表。
- 链表时间复杂度: 插入删除 O(1) 随机访问O(n)
- 数组时间复杂度: 插入删除 O(n) 随机访问O(1)
1.链表基本结构:
每一个火车车厢(Node)都有一个节点和一个指向下一节点的地址
代码示例:
public class TestNode {
public static void main(String[] args) {
//封装节点
Node head = new Node("火车头");
Node first = new Node("车厢一");
Node second = new Node("车厢二");
Node last = new Node("火车尾");
//设置车厢关系,即挂载
head.setNext(first);
first.setNext(second);
second.setNext(last);
printLink(head);
}
public static void printLink(Node node ){
if(node != null){
System.out.println(node.getData());
//将当前节点指向下一节点
node = node.getNext();
printLink(node);
}
}
}
//定义车厢节点(结构)
public class Node {
//节点中数据
private Object data;
//指向下一个(车厢)节点的地址 -> 类型是Node
private Node next;
public Node(Object data){
this.data=data;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
2.链表实现结构
- 存在问题:客户端需要自己来进行节点的创建以及关心的配置。所以链表还需要一个单独的Link类。
Node:负责节点内容的设置,真实保存内容。
Link:实现Node节点之间的动态挂载(将节点关联起来),为用户所用(添加数据)。
代码示例:
package com.qqy.ds.linkedlist;
/**
* Author:qqy
*/
public interface ILink {
/**
* 链表增加节点操作
*
* @param data 节点内容
* @return
*/
boolean add(Object data);
/**
* 判断指定内容节点在链表中是否存在
*
* @param data 要判断的内容
* @return 返回找到的节点索引
*/
int contains(Object data);
/**
* 删除指定内容节点
*
* @param data
* @return
*/
boolean remove(Object data);
/**
* 根据指定下标修改节点内容
*
*
* @param index 索引下标
* @param newData 替换后的内容
* @return 替换之前的节点内容
*/
Object set(int index, Object newData);
/**
* 根据指定下标返回节点内容
*
*
* @param index
* @return
*/
Object get(int index);
/**
* 链表清空
*/
void clear();
/**
* 链表的遍历需要递归实现将链表转为数组
*
* @return 返回所有节点内容
*/
Object[] toArray();
/**
* 链表长度
*
* @return
*/
int size();
/**
* 遍历链表
*/
void printLink();
}
class LinkImpl implements ILink {
private Node1 head; //头指针
private Node1 last; //尾指针
private int size; //链表长度
//将Node1作为内部类原因
//1.封装,只有LinkImpl需要用到
//2.方便操作,无需getter、setter
//真正的节点,负责数据存储
public class Node1 {
private Node1 prev;
private Object data;
private Node1 next;
//作为内部类,无需定义getter、setter属性
public Node1(Node1 prev, Object data, Node1 next) {
this.prev = prev;
this.data = data;
this.next = next;
}
}
@Override
public boolean add(Object data) {
Node1 temp = this.last;
Node1 newNode = new Node1(temp, data, null);
this.last = newNode;
if (this.head == null) {
this.head = newNode;
} else {
temp.next = newNode;
}
this.size++;
return false;
}
@Override
public int contains(Object data) {
//null
if (data == null) {
int i = 0;
for (Node1 temp = this.head; temp != null; temp = temp.next) {
if (temp.data == null) {
return i;
}
i++;
}
} else {
int i = 0;
for (Node1 temp = this.head; temp != null; temp = temp.next) {
if (temp.data.equals(data)) {
return i;
}
i++;
}
}
return -1;
}
@Override
public boolean remove(Object data) {
if (data == null) {
for (Node1 temp = this.head; temp != null; temp = temp.next) {
if (temp.data == null) {
unLink(temp);
return true;
}
}
} else {
for (Node1 temp = this.head; temp != null; temp = temp.next) {
if (temp.data.equals(data)) {
unLink(temp);
return true;
}
}
}
return false;
}
@Override
public Object set(int index, Object newData) {
if (!isLinkIndex(index)) {
return null;
}
Node1 node = node(index);
Object elementData = node.data;
node.data = newData;
return elementData;
}
@Override
public Object get(int index) {
if (!isLinkIndex(index)) {
return null;
}
return node(index).data;
}
@Override
public void clear() {
for (Node1 temp = head; temp != null; ) {
temp.data = null;
Node1 node = temp.next;
temp = temp.prev = temp.next = null;
temp = node;
this.size--;
}
//this.head=0;
//this.size=0;
}
@Override
public Object[] toArray() {
Object[] result = new Object[size];
int i = 0;
for (Node1 temp = head; temp != null; temp = temp.next) {
result[i++] = temp.data;
}
return result;
}
@Override
public int size() {
return this.size;
}
@Override
public void printLink() {
Object[] data = this.toArray();
for (Object temp : data) {
System.out.println(temp);
}
}
//仅供本类方法使用,根据指定的索引确定具体的节点
private Node1 node(int index) {
if (index < (size >> 1)) {
Node1 temp = this.head;
for (int i = 0; i < index; i++) {
temp = temp.next;
}
return temp;
}
Node1 temp = this.last;
for (int i = size - 1; i > index; i--) {
temp = temp.prev;
}
return temp;
}
//判断指定的索引是否合法
private boolean isLinkIndex(int index) {
return index >= 0 && index < size;
}
private Object unLink(Node1 x) {
Object elementData = x.data;
Node1 prev = x.prev;
Node1 next = x.next;
if (prev == null) {
this.head = next;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) {
this.last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.data = null;
this.size--;
return elementData;
}
}
public class TestNode1 {
public static void main(String[] args) {
ILink link = new LinkImpl();
link.add("火车头");
link.add("车厢一");
link.add("车厢二");
link.add("火车尾");
System.out.println(link.contains("车厢二")); //2
System.out.println(link.contains("车厢三")); //-1
// link.clear();
System.out.println(link.size());
System.out.println(link.get(3)); //火车尾
System.out.println(link.set(2,"滴滴滴")); //车厢二
link.printLink();
System.out.println(link.remove("滴滴滴"));
link.printLink();
}
}