面向对象类的设计----LinkedBox类的封装

数组有些地方不是很好 长度固定 频繁添加元素 删除元素 个数改变
利用面向对象的编程思想,设计一个类 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;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章