`
朱凌峰
  • 浏览: 7410 次
文章分类
社区版块
存档分类
最新评论

各有千秋——数组,链表及用两者实现的队列

阅读更多

 

 

       计算机中两种基本的数据结构式数组及链表,前者是在自然顺序的内存中存储数据,而后者是通过其基本单元——节点的数据域和指针域来存储数据和记录数据间的相对位置,概括地说:数组中的数据位置是连续的,链表中的数据位置是离散的。

 

       这就决定了,在数组中找一个数据很容易(只需知道数组首地址及数据在数组中的位置);而在链表中改变数据的相对位置很容易(只需改变个别节点的指针域就行)。他们各有优势,也各有劣势,并且优势与劣势恰好相反。

 

       正是这一不同决定了用他们来实现队列时,队列的优势与劣势。

 

       队列的特点是可以改变长度(存储数据的个数),是一种比较理想的数据结构。我们常常要对它进行“增删查改”的工作,或者更根本地说是“找”与“变”的工作。“找”就是找到索引位置的数据,数组队列非常擅长,

“变”就是改变数据间的相对位置关系,链表队列非常擅长。而当我们“变”数组队列时,往往要频繁地新建数组并逐个赋值;当我们“查”链表队列中的数据时,往往要遍历队列,工作量很大。

 

       总之两者各有千秋,适合用于各自擅长的场合,使用时要根据情况灵活选取

 

传上我的队列实现代码:

 

/**
 * 队列的接口,定义一些使用方法
 * @author 朱凌峰
 *
 * @param <E> 泛型
 */
public interface MyQueue<E> {
	//在队列末尾加上一个数据
	public void add(E e);
	//在队列中指定位置插入一个数据
	public void insert(E e,int index);
	//取出指定位置的一个数据
	public E get(int index);
	//删除指定位置的一个数据
	public void remove(int index);
	//改变指定位置的数据
	public void set(E e,int index);
	//获取队列长度
	public int size();
	//按顺序打印队列中的每个数据
	public void printQueue();
	//检验索引位置是否越界,如越界,则抛出异常
	public boolean judgeIndex(int index);
}
 
/**
 * 定义我自己的数组队列
 * 
 * @author 朱凌峰
 * 
 */
public class MyArrayList<E> implements MyQueue<E> {

	private Object[] dataArray;// 用于存储数据的数组
	int lengthIncreaseStep;// 每次数组长度增加的步长
	int countData = 0;// 数据个数计数器

	/**
	 * 默认构造方法 默认数组初始长度为10,每次数组长度增加的步长为10
	 */
	public MyArrayList() {
		this(10, 10);
	}

	/**
	 * 设定数组初始长度的构造方法
	 * 
	 * @param initLength
	 *            数组的初始长度
	 */
	public MyArrayList(int initLength) {
		this(initLength, 10);
	}

	/**
	 * 设定数组初始长度和每次数组长度增加的步长的构造方法
	 * 
	 * @param initLength
	 *            数组初始长度
	 * @param lengthIncreaseStep
	 *            数组长度增加的步长
	 */
	public MyArrayList(int initLength, int lengthIncreaseStep) {
		this.lengthIncreaseStep = lengthIncreaseStep;
		this.dataArray = new Object[initLength];
	}

	/**
	 * 添加一个数据到队列的末尾
	 * 
	 * @param msAdd
	 *            要添加的数据
	 */
	@Override
	public void add(E e) {
		// 如果数据个数等于当前数组长度
		if (countData == dataArray.length) {
			// 新建加长长度的数组
			Object[] lengthenedArray = new Object[this.dataArray.length
					+ this.lengthIncreaseStep];
			// 将原有数组里的数据从后往前逐个加入到新的数组中
			for (int i = 0; i < dataArray.length; i++) {
				lengthenedArray[i] = dataArray[i];
			}
			// 将添加的数据加入到新建数组中
			lengthenedArray[dataArray.length] = e;
			// 将新建数组指向原数组
			dataArray = lengthenedArray;
		} else {
			dataArray[countData] = e;
		}
		countData++;
	}
	/**
	 * 在索引位置前面一个位置插入数据(若要插在最后一个数据后面,则用add方法)
	 */
	public void insert(E e, int index) {
		if(this.judgeIndex(index)){
			//将原来队列的最后一个数据添加到队列末尾
			this.add(this.get(this.size()-1));
			//将原来最后第二个数据至index向后移动一位
			for(int i =this.size()-3 ;i >=index;i--){
				this.set(this.get(i), i+1);
			}
			//将index位置设置为新插入的数据
			this.set(e, index);
		}
	}

	/**
	 * 获取队列中指定位置的数据
	 * 
	 * @param index
	 *            数据在队列中的位置
	 * @return 指定位置的数据
	 */
	public E get(int index) {
		// 检查index是否有效
		if (judgeIndex(index)) {
			return (E) dataArray[index];
		}
		return null;	
	}

	/**
	 * 移除索引位置对应的数据
	 * @param index 索引位置
	 */
	public void remove(int index) {
		if(this.judgeIndex(index)){
			for (int i = index; i < this.size()-1; i++) {
				dataArray[i]=dataArray[i+1];
			}
			this.countData--;
		}
	}

	/**
	 *设置索引位置的数据值
	 *@param e 数据值
	 *@param index 索引位置
	 */
	public void set(E e, int index) {
		// 检查index是否有效
		if (judgeIndex(index)) {
			this.dataArray[index] = e;
		}
	}

	/**
	 * 获取队列的长度
	 * 
	 * @return 一个整数表示队列长度
	 */
	public int size() {
		return countData;
	}
	/**
	 * 按顺序打印队列中的每个数据,若队列为空则抛出异常
	 */
	public void printQueue() {
		if(this.size()==0)
			throw new java.lang.RuntimeException("队列为空");
		else {
			for (int i = 0; i < this.size(); i++) {
				System.out.println("队列中第"+i+"个数据为:"+this.get(i));
			}
		}
	}

	/**
	 * 判断索引位置是否有效,若索引位置有效,则返回true,否则抛出异常
	 * 
	 * @param index
	 *            索引位置
	 * @return 若索引位置有效,则返回true
	 */
	@Override
	public boolean judgeIndex(int index) {
		// 判断索引位置是否有效
		if (index < 0 || index >= this.size()) {
			throw new java.lang.RuntimeException("索引位置" + index + "越界:"
					+ ",当前队列大小为:" + this.size());
		}
		return true;
	}
	/**
	 * 将一个队列添加到当前队列的末尾
	 * @param arrayList 要添加到末尾的队列
	 */
	public void addAll(MyArrayList<E> arrayList){
		//新建一个长度为当前队列和要添加到末尾的队列长度之和的数组
		Object[] tempArray=new Object[this.size()+arrayList.size()];
		//将当前队列的每个数据一次添加到临时数组中
		for (int i = 0; i < this.size(); i++) {
			tempArray[i]=dataArray[i];
		}
		//将 要添加到末尾的队列中的每个每个数据添加到临时数组中
		for (int i = 0; i < arrayList.size() ; i++) {
			tempArray[i+this.size()]=arrayList.get(i);
		}
		//将原有数组指向临时数组
		dataArray=tempArray;
		//重新设置数据个数
		countData=this.size()+arrayList.size();
	}

}
 

/**
 * 链表的节点类
 * @author 朱凌峰
 *
 * @param <E>
 */
public class LinkNode<E> {
	//节点的数据
	private E data;
	//当前节点的子节点
	private LinkNode<E> child;
	private LinkNode<E> parent;//当前节点的父节点
	
	/**
	 * 带参构造器
	 * @param data	创建对象时赋予的初始参数
	 */
	public LinkNode(E data){
		this.data=data;
	}
	/**
	 * 获取当前节点的数据
	 * @return
	 */
	public E getData(){
		return this.data;
	}
	/**
	 * 重新赋予节点数据的值
	 * @param data 重新赋予的值
	 */
	public void setData(E data){
		this.data=data;
	}
	/**
	 * 设置父节点
	 * @param parent 
	 */
	public void setParent(LinkNode<E> parent){
		this.parent=parent;
	}
	/**
	 * 设置子节点
	 * @param child
	 */
	public void setChild(LinkNode<E> child){
		this.child=child;
	}
	/**
	 * 获取当前节点的付节点
	
	 * @return
	 */
	public LinkNode<E> getParent(){
		return this.parent;
	}
	/**
	 * 获取当前节点的子节点
	 * @return
	 */
	public LinkNode<E> getChild(){
		return this.child;
	}
}
 

package LinkNode20130717;

import zlfsQueue20130714and0716and0722.MyQueue;

/**
 * 用链表实现队列
 * @author 朱凌峰
 *
 */

public class LinkQueue<E> implements MyQueue<E>{

	
	//根节点
	private LinkNode<E> root;
	//最后一个节点
	private LinkNode<E> last;
	/**
	 * 在队列末尾添加一个数据
	 * @param e 要添加的数据
	 */
	public void add(E e){
		//新建一个节点
		LinkNode<E> tempNode=new LinkNode<E> (e);
		//如果队列中还没有节点,则新建一个根节点
		if(root==null){
			root=tempNode;
			//此时最后一个节点即为根节点
			last=root;
		}else{
			last.setChild(tempNode);//该节点为上一个节点的子节点
			tempNode.setParent(last);
			//该节点成为当前的最后一个节点
			last=tempNode;
		}
	}
	/**
	 * 获取指定位置节点的数据
	 * @param index 数据所在位置,根节点的位置为0
	 * @return 
	 */
	public E get(int index){
		LinkNode<E> nodeOfIndex=getNodeOfIndex(index);
		return nodeOfIndex.getData();
	}
	/**
	 * 获取链表队列的大小,即数据个数
	 * @return	
	 */
	public int size(){
		int count=0;
		LinkNode<E> tempNode=root;
		while(tempNode!=null){
			count++;
			tempNode=tempNode.getChild();
		}
		return count;
	}
	/**
	 * 删除指定位置的数据
	 * @param index
	 */
	public void remove(int index){
		LinkNode<E> nodeOfIndex=getNodeOfIndex(index);
		//如果删除根节点
		if(index==0){
			//获取索引位置的节点的子节点
			LinkNode<E> tempChild=nodeOfIndex.getChild();
			root=tempChild;
		}
		//如果删除最后一个节点
		else if(index==this.size()-1){
			//获取索引位置的节点的父节点
			LinkNode<E> tempParent=nodeOfIndex.getParent();
			tempParent=last;
		}
		else {
			//获取索引位置的节点的父节点和子节点
		LinkNode<E> tempParent=nodeOfIndex.getParent();
		LinkNode<E> tempChild=nodeOfIndex.getChild();
		//重新设置父子关系
		tempParent.setChild(tempChild);
		tempChild.setParent(tempParent);
		}
	}
	/**
	 *  重新设置指定位置的数据值
	 * @param e
	 * @param index
	 */
	public void set(E e,int index){
		LinkNode<E> nodeOfIndex=getNodeOfIndex(index);
		nodeOfIndex.setData(e);
	}


	/**
	 * 获取索引位置对应的节点
	 * @param index 索引位置
	 * @return 索引位置对应节点
	 */
	private LinkNode<E> getNodeOfIndex(int index){
		if(this.judgeIndex(index)){
			//找到索引位置对应的节点
			int count = 0;
			LinkNode<E> tempNode=root;
			while(count!=index){
				tempNode=tempNode.getChild();
				count++;
			}
			return tempNode;
		}
		return null;		
	}
	/**
	 * 依次打印队列中每个数据
	 */
	public void printLinkQueue(){
		if(root==null){
			throw new java.lang.RuntimeException("队列为空");
		}
		else{
			int count = 0;
			LinkNode<E> tempNode=root;
			while(tempNode!=null){
				System.out.println("队列中第"+count+"个数据为:"
					+tempNode.getData());
				tempNode=tempNode.getChild();
				count++;
			}
		}
	}
	/**
	 * 插入一个数据到索引位置前面一个位置
	 * @param e 要插入的数据
	 * @param index	索引位置
	 */
	public void insert(E e, int index) {
		if (judgeIndex(index)) {
//			新建临时节点保存要插入的数据
			LinkNode<E> tempNode=new LinkNode<E>(e);
			if(index==0){
//				设置当前根节点和临时节点的父子关系
				root.setParent(tempNode);
				tempNode.setChild(root);
//				根节点为临时节点
				root=tempNode;	
			}
			else {
				tempNode.setChild(this.getNodeOfIndex(index));
				tempNode.setParent(this.getNodeOfIndex(index-1));
				
				this.getNodeOfIndex(index).setParent(tempNode);	
				this.getNodeOfIndex(index-1).setChild(tempNode);
			}
		}
	}
	/**
	 * 按顺序打印队列中的每个数据,若队列为空则抛出异常
	 */
	public void printQueue() {
		if(this.size()==0)
			throw new java.lang.RuntimeException("队列为空");
		else {
			for (int i = 0; i < this.size(); i++) {
				System.out.println("队列中第"+i+"个数据为:"+this.get(i));
			}
		}	
	}
	/**
	 * 将一个队列添加到当前队列末尾
	 * @param linkQueue 要添加到末尾的队列
	 */
	public void addAll(LinkQueue<E> linkQueue) {
		this.last.setChild(linkQueue.root);
		linkQueue.root.setParent(this.last);
	}
	/**
	 * 判断索引位置是否有效
	 * @param index 索引位置
	 * @return 若索引位置有效,则返回true
	 */
	public boolean judgeIndex(int index) {
		//判断索引位置是否有效 
		if(index<0 || index>=this.size()){
			throw new java.lang.RuntimeException("索引位置越界:"+index
					+",当前队列大小为:"+this.size());
		}
		return true;
	}
}
 
 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics