- Main function
package com.uncle.linkedbox.src.test;
import com.uncle.linkedbox.src.util.ArrayBox;
import com.uncle.linkedbox.src.util.LinkedBox;
/**
* 设计一个类 LinkedBox 链表 链式 火车 联络网 小A<-->小B<-->小C<-->小D
* 长度看似可以改变
* 解决了插入和删除效率低的问题 不适合遍历
* 接口-----定义规则
* 多态
*/
public class TestMain {
public static void main(String[] args){
ArrayBox ab = new ArrayBox();
ab.add(10);
ab.remove(0);
ab.get(0);
ab.size();
LinkedBox lb = new LinkedBox();
lb.add(10);
lb.remove(0);
lb.get(0);
lb.size();
}
}
- Interface-----define rules
package com.uncle.linkedbox.src.util;
public interface Box {
public boolean add(int element);
public int get(int index);
public int remove(int index);
public int size();
}
- Exception class-----custom exception
package com.uncle.linkedbox.src.util;
public class BoxIndexOutOfBoundsException extends RuntimeException{
public BoxIndexOutOfBoundsException(){
}
public BoxIndexOutOfBoundsException(String msg){
super(msg);
}
}
- ArrayBox
package com.uncle.linkedbox.src.util;
public class ArrayBox implements Box{
//设计一个静态常量 用来存储数组的默认长度
private static final int DEFAULT_CAPACITY = 10;
//设计一个自己的属性 用来存放真实数据的 []
private int[] elementDate;
//设计一个自己的属性 用来记录数组内存储的有效元素个数
private int size = 0;
//构造方法重载
public ArrayBox(){
elementDate = new int[DEFAULT_CAPACITY];
}
public ArrayBox(int capacity){
elementDate = new int[capacity];
}
//小A同学 负责确保数组内部的容量
private void ensureCapacityInternal(int minCapacity){
//判断如果你需要的最小容量比原数组的长度还要大
if(minCapacity - elementDate.length > 0){
//需要进行数组的扩容 找别人计算扩容的大小
this.grow(minCapacity);
}
}
//小B同学 负责计算扩容大小
private void grow(int minCapacity){
//获取原数组的长度
int oldCapacity = elementDate.length;
//小B同学帮我做了一个计算 在原数组之上增加1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//比较计算后的长度与所需的长度
if(newCapacity - minCapacity < 0){
//那么直接按照所需的长度作为新数组的长度
newCapacity = minCapacity;
}
//调用小C同学 让他创建新数组 将原数组中的所有元素移入新数组中
elementDate = this.copyOf(elementDate,newCapacity);
}
//小C同学 负责将原数组中的元素移入新数组中
private int[] copyOf(int[] oldArray,int newCapacity){
//按照提供的长度创建一个新数组
int[] newArray = new int[newCapacity];
//将原数组中的元素按照位置移入新数组中
for(int i=0;i<oldArray.length;i++){
newArray[i] = oldArray[i];
}
//将新数组返回
return newArray;
}
//小D同学 检测给定index是否合法
private void rangeCheck(int index){
if(index<0 || index>=size){
//自定义一个异常 来说明问题
throw new BoxIndexOutOfBoundsException("Index:"+index+",Size:"+size);
}
}
//------------------------------------------------------------
//用来将用户给定的element存起来 参数是需要存起来的元素 返回值是否存储成功
public boolean add(int element){
//找一个别人 做事 确保数组的内部容量够用
this.ensureCapacityInternal(size+1);
//上述一行代码可以执行完毕 证明elementDate的数组肯定够用
//直接将新来的element元素存入数组中 并且让size多记录一个
elementDate[size++] = element;
//返回true告知用户存储元素成功
return true;
}
//用来获取给定位置的元素 参数是索引位置 返回值是取得的元素
public int get(int index){
//找一个小弟 检测给定的index是否合法
this.rangeCheck(index);
//上述代码可以执行 证明index是合法的
//则找到index对应位置的元素 将其返回
return elementDate[index];
}
//用来删除给定位置的元素 参数是索引位置 返回值是删除掉的那个元素
public int remove(int index){
//调用小D同学 检测index
this.rangeCheck(index);
//上述代码可以执行 index是合法的
//找到index位置的元素 保留起来 留给用户
int oldValue = elementDate[index];
//1 2 3 4 5 6 size==6个
//1 2 4 5 6 0 elementDate[5]=0 size-1
//从index位置开始至size-1结束 后面元素依次前移覆盖
for(int i=index;i<size-1;i++){
elementDate[i] = elementDate[i+1];
}
//手动将最后的元素删除 让size减少一个记录
elementDate[--size] = 0;
//将旧数据返回
return oldValue;
}
//设计一个方法 用来获取size有效的个数 没有设置 可以保护size的安全
public int size(){
return size;
}
}
- LinkedBox
package com.uncle.linkedbox.src.util;
public class LinkedBox implements Box{
//创建几个属性
private Node first;//记录首节点
private Node last;//记录尾节点
private int size;//记录有效元素的个数
//设计一个小A同学 负责将元素添加在新的node里 挂在链表的尾端
private void linkLast(int element){
//获取链表的尾节点
Node l = last;
//创建一个新的node对象 将新数据包装起来
Node newNode = new Node(l,element,null);
//将新节点对象设置为尾节点
last = newNode;
//严谨的判断
if(l==null){
//如果原来尾节点没有对象 证明这个链表没有使用过的
first = newNode;
}else{
//原来用过 刚才已经将新的节点连接在last之后啦
l.next = newNode;
}
//有效元素个数增加一个
size++;
}
//设计一个小B同学 负责检测index
private void rangeCheck(int index){
if(index<0 || index>=size){
throw new BoxIndexOutOfBoundsException("Index:"+index+",Size:"+size);
}
}
//设计一个小C同学 负责找寻给定index位置的node对象
private Node node(int index){
Node targetNode;//用来存储找到的当前那个目标
//判断index范围是在前半部分 还是在后半部分
if(index < (size>>1)){
//从前往后找寻比较快
targetNode = first;
for(int i=0;i<index;i++){
targetNode = targetNode.next;
}
}else{
//从后往前找
targetNode = last;
for(int i=size-1;i>index;i--){
targetNode = targetNode.prev;
}
}
return targetNode;
}
//设计一个方法 小D同学 负责将给定的node节点对象删除 并且保留数据
private int unlink(Node targetNode){
//获取当前node的item信息---
int oldValue = targetNode.item;
//当前node的前一个
Node prev = targetNode.prev;
//当前node的下一个
Node next = targetNode.next;
//删除节点对象
if(prev==null){
//当前node就是第一个
first = next;
}else{
prev.next = next;
targetNode.prev = null;
}
if(next==null){
//当前node就是最后一个
last = prev;
}else{
next.prev = prev;
targetNode.next = null;
}
//让有效元素减少一个
size--;
return oldValue;
}
//-------------------------------------------------------
//数据结构
public boolean add(int element) {
//将element存入一个新的Node对象里 添加至链表的尾端
this.linkLast(element);
//告知添加成功
return true;
}
public int get(int index) {
//检测index是否合法
this.rangeCheck(index);
//找寻index对应位置的那个node对象 将对象中的数据取出来
Node targetNode = this.node(index);
//返回找到的node对象内数据
return targetNode.item;
}
public int remove(int index) {
//检测范围是否合法
this.rangeCheck(index);
//找到index位置的那个node
Node targetNode = this.node(index);
//设计一个小D同学 负责删除当前的目标节点 让他帮我们返回oldValue
int oldValue = this.unlink(targetNode);
return oldValue;
}
public int size() {
return size;
}
}
- Node------Custom node
package com.uncle.linkedbox.src.util;
public class Node {
public Node prev;//previous 上一个node对象
public int item;//当前的数据
public Node next;//下一个node对象
public Node(Node prev,int item,Node next){
this.prev = prev;
this.item = item;
this.next = next;
}
}
- Linked list structure