数组有些地方不是很好 长度固定 频繁添加元素 删除元素 个数改变
利用面向对象的编程思想,设计一个类 LinkedBox,它的数据结构类似于链式存储结构。
- 最早 利用数组存储一组元素
长度固定 好处在于创建后不会浪费内存
不好在于长度不变 添加删除时个数的改变很麻烦 - 自己可以设计类 ArrayBox
点击查看—>面向对象类的设计----ArrayBox类的封装.
长度看似可以改变 好处在于添加 删除时不需要纠结长度变化的问题
不好在于 插入 删除效率低 不断的移动元素的位置进行覆盖 - 再设计一个类 LinkedBox , 它是一个链表 ,链式结构的小容器。
长度看似可以改变 解决了插入和删除效率低的问题 不适合遍历
LinkedBox类的封装
首先,我们为了统一规范,设计一个接口,将添加,获取,删除,获取有效元素个数的这几个常用方法的方法名(add get remove size)和使用方法(要什么参数,返回值是什么)进行统一。
public interface Box {
public boolean add(int element);
public int remove(int index);
public int get(int index);
public int size();
}
异常类BoxIndexOutOfBoundsException:
public class BoxIndexOutOfBoundsException extends RuntimeException{
public BoxIndexOutOfBoundsException(){}
public BoxIndexOutOfBoundsException(String msg){
super(msg);
}
}
Node类,该类定义了我们设计的工具类LinkedBox节点的数据结构:
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;
}
}
LinkedBox类:
public class LinkedBox implements Box {
private Node first;// 记录头节点
private Node last;// 记录尾节点
private int size;// 记录有效元素的个数
// linkLast负责将元素添加在新的Node里, 挂在链表的尾端
private void linkLast(int element) {
// 获取链表的尾节点
Node lNode = last;
// 创建一个新的Node对象,将新数据包装起来
Node newNode = new Node(lNode, element, null);
// 将新节点对象设置为尾节点
last = newNode;
// 需要做一个严谨的判断
if (lNode == null) {// 如果原来尾节点没有对象,证明这个链表没有使用过
first = newNode;// 将这个新节点设置为头节点
} else {
lNode.next = newNode;
}
// 有效元素个数增加一个
size++;
}
//负责检测index的合法性
private void rangeCheck(int index) {
if(index<0 || index>=size){
throw new BoxIndexOutOfBoundsException("Index:"+index+", Size:"+size);
}
}
//负责找寻给定index位置的node对象
private Node findNode(int index){
Node targetNode;//用来存储找到的node对象
//判断index范围是在前半部分,还是在后半部分
if(index<(size>>1)){
//index比size的一半还要小,证明在前半部分,从前往后找比较快
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;
}
//负责将给定的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){//当前节点是头节点
first = next;//让下一个节点变成头节点
}else{
prev.next = next;
//让targetNode对象的prev指向空
targetNode.prev = null;
}
if(next == null){//当前节点是尾节点
last = prev;//让它前一个变成尾节点
}else{
next.prev = prev;
//让targetNode对象的next指向空
//让后targetNode即可以被回收
targetNode.next = null;
}
//让有效元素个数减少一个
size--;
return oldValue;
}
// ----------------------------------------------
@Override
public boolean add(int element) {
//将element存入一个新的Node对象里,添加至链表的尾端
this.linkLast(element);
//告知添加成功
return true;
}
@Override
public int remove(int index) {
// 检测index是否合法
this.rangeCheck(index);
//找寻index对应位置的那个node对象
Node targetNode = this.findNode(index);
//需要将当前节点的前一个元素的next指向当前节点的下一个元素,当前节点的后一个元素的prev指向当前节点的前一个元素
// targetNode.prev.next = targetNode.next;
// targetNode.next.prev= targetNode.prev;
int oldValue = this.unLink(targetNode);
return oldValue;
}
@Override
public int get(int index) {
// 检测index是否合法
this.rangeCheck(index);
//找寻index对应位置的那个node对象,然后再将node对象中封装的数据取出来
Node targetNode = this.findNode(index);
//返回找到的Node对象内的数据
return targetNode.item;
}
@Override
public int size() {
return size;
}
}