`
happy_zhourong
  • 浏览: 13298 次
  • 性别: Icon_minigender_2
文章分类
社区版块
存档分类
最新评论

关于数组、链表、队列的学习心得

    博客分类:
  • java
 
阅读更多

一、实现一个简单队列

1、链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表有一系节点组成,节点可以在运行时动态生成。每个节点包括两个部分,一个是存储数据元素的数据域,另一个是存储下一个节点地址的指针域。

2、数组的缺陷:

数组是有长度限制的,如果我们要往数组中存储数据,在我们不知道要存储多少的时候,要怎么初始化数组长度呢?我们只能给数组一个固定的初始长度,所以,我们不能让数组的长度随我们存储数据的增多而增加。

3、队列应运而生:

人类是很聪明的动物,于是乎,我们创造了队列这种数据结构,队列的长度可以随我们存储数据的增多而增长,也可以随我们存储数据的减少而减少。

         4、链表、数组和队列的共同点:

                   链表、数组和队列本质上是相同的,他们都是一种存储数据的容器。

         5、数组和队列的不同点:

            数组长度固定,队列长度可以变化。

         6、数组与链表的不同点:

                   1)数组是连续的,链表是离散的。

也就是说,数组表示的是一连串连续地址。链表节点表示的地址是不连续的。

                   2)数组利于查找,链表不利于查找。

                            因为数组可以看做是一种天然的数据结构,它得天独厚之处在于它的连续性,为我们的查找提供了很大的便利。

相反,对于链表,由于它的不连续性,使得每查找一个节点都要遍历一遍链表,消耗多大,不利于查找。

                   3)数组不利于删除和插入,链表利于删除和插入。

                            上天是公平的。

         对于数组,它的连续性为删除和插入操作造成了阻碍。当插入或删除一个数时,都需要移动该数位置之后的所有的数,需要遍历整个数组。

         对于链表,当插入或删除一个数时,只需要改变该数上一个节点的next指针。而不需要遍历整个链表。

 

二、用数组实现一个队列并优化:

1、用数组实现一个简单队列:

前面我们已经学习了如何用数组和链表实现一个简单队列,用数组实现简单队列add方法如下:

 

    

/**
 * 实现泛型队列
 * @author zr
 *
 * @param <E>
 */
public class STList<E> implements NetJavaList<E>{
	//队列内部初始用来装对象的数组,长度为0
	private Object [] srcA = new Object [0];
	//向队列中加入一个对象
	public void add(E e) {
		//1、新建一个数组,长度是原数组长度+1
		Object [] destA = new Object [srcA.length+1];//如果该数组长度为10,那么srcA.length就为9
		//2、将要加入的对象放入新数组的最后一个位置
		destA[srcA.length]=e;//注意:数组的位置从0开始,因为数组长度为10,0~9,故最后一个位置是9
		//3、将原数组中的东西放到新数组中:使用系统提供的数组copy方法
		System.arraycopy(srcA, 0, destA, 0, srcA.length);
		//指向新建的数组
		srcA=destA;
	}

	//取得队列中指定位置的一个对象,如果指定了类型,则转为指定类型返回
	public E get(int index) {
		E st=(E)srcA[index];
		return st;
	}

	public int size() {
		return srcA.length;
	}
	
	
}

 

 

这样实现的队列,有很多缺点:

1)不能对队列中的对象进行插入和删除操作;

2)使用该队列的人不能设置数组的初始长度;

3)每增加一个对象,就要开辟一个空间,并且都要将数组中的所有元素重新赋值,使得程序效率变低。

 

2、用数组实现队列并优化:

针对以上问题,提出一些解决方案:

1)对队列进行扩展,加入insertdelete方法;

2)重载构造方法,传入参数,让使用者可以对某些属性进行初始化

3)增加效率(优化):

举个例子:

假如我们要开个会,有两种方案:

i)  每来一个人就去买一张椅子;

ii)  一开始就买好10张椅子,当十张椅子坐满了,再去买5张椅子,当这5张椅子也坐满了,又去买5张……

比较两种方案,显然,方案2)更节省人力。

同理,我们把实际问题应用与程序中:

因为每增加一个对象,就要开辟一个空间,并且都要将数组中的每个元素重新赋值。虽然每次所需的空间不大,但是程序运行所需的时间却很多,这就给计算机造成了负担。如果我们每次开辟多个空间,即实例化一个数组对象,这样,每add一个对象,就放到数组中,就不需要每次对数组中的所有元素重新赋值,当数组存满时,再实例化一个数组对象,这样一来,开辟空间的次数变少了,所花的时间也变少了,对数组中所有元素赋值的时间也变少了,效率自然就提高了。

 

/**
 * 用数组实现一个队列并优化
 * @author zr
 *
 */
public class ArrayQueue<E> {
	private int inlength;//数组的初始长度
	private int count;//添加对象的次数
	private int incount;//数组每次增长的长度
	private int arraycount;//数组增长的次数
 	private Object []  obj;
//	private Object [] obj=new Object[inlength];
 	{
 		System.out.println("aaa");
 	}

	/**
	 * ArrayQueue aq=new ArrayQueue
	 * 定义一个构造函数,用来初始化inlength和incount的值
	 * @param inlenght 数组的初始长度
	 * @param incount 数组每次增长的长度
	 */
	public ArrayQueue(int inlength,int incount){
		System.out.println("bbb");
		this.inlength=inlength;
		this.incount=incount;
		obj=new Object[inlength];
	}
	
	public static void main(String[] args){
		ArrayQueue aq=new ArrayQueue(100,10);
	}
	
	/**
	 * 定义一个无参构造器,分别给定了inlength和incount默认值,inlength=10,incount=5
	 */
	public ArrayQueue(){
		this(10,5);
	}
	
	/**
	 * 定义了一个构造方法,用于初始化incount的值,并给定了inlength的默认值10
	 * @param incount
	 */
	public ArrayQueue(int incount){
		this(10,incount);
	}
	
	/**
	 * 在队列中指定位置之后插入一个元素
	 * @param index 指定的位置
	 * @param e 插入的对象
	 */
	public void insert(int index,E e){
		//当指定位置小于或等于数组长度时
		if(index<obj.length){
			//新建一个数组,长度是原数组长度+1
			Object [] obj2=new Object[obj.length+1];
			for(int i=0;i<obj.length+1;i++){
				//将index位置之前(包括index)的元素放到新数组中
				if(i<index||i==index){
					obj2[i]=obj[i];
				}
				else if(i==index+1){
					//将插入的元素放到index之后的位置
					obj2[i]=e;
				}else{
					//将index之后元素的位置向后移动一个位置
					obj2[i]=obj[i-1];
				}	
			}
			obj=obj2;
		}
		//当指定位置大于数组长度时
		else{
				System.out.println("您指定的位置大于队列长度,不能插入!");	
			}
	}
	
	/**
	 * 删除队列中指定位置的一个元素
	 * @param index 指定的位置
	 */
	public void delete(int index){
		//当指定位置小于数组长度时
		if(index<obj.length){
			//新建一个数组,长度是原数组长度-1
			Object [] obj2=new Object[obj.length-1];
			for(int i=0;i<obj.length-1;i++){
				//将index位置之前的元素放到新数组中
				if(i<index){
					obj2[i]=obj[i];
				}
				//把index位置之后的元素向前移动一个位置
				else{
					obj2[i]=obj[i+1];
				}
			}
			//指向新的数组
			obj=obj2;
		}else{
			System.out.println("您指定的位置超出了队列的长度,不能删除!");
		}
		
	}

	/**
	 * 向队列中加入一个对象
	 * @param e 队列中加入的对象
	 */
	public void add(E e){
		
//		System.out.println("obj.length="+obj.length);
		count++;
//		System.out.println("count="+count);
		int length=inlength+arraycount*incount;//为保存对象预留的长度
		//当数组的长度超过length时
		if(count>length){
			//1、新建一个数组,长度是原数组长度+incount
			Object [] obj2=new Object[obj.length+incount];
			arraycount++;//数组每增长一次加1
			//2、将原数组中的东西放到新数组中
			for(int i=0;i<obj.length;i++){
				obj2[i]=obj[i];
			}
			//3、将要加入的对象放入新数组的最后一个位置
			obj2[obj.length]=e;
			//指向新建的数组
			obj=obj2;
		}
		//当数组的长度小于length时,把对象添加到已存在的数组中
		obj[count-1]=e;
	}
	
	/**
	 * 取得队列中指定位置的一个对象
	 * @param index 指定的位置
	 * @return 返回指定位置的对象
	 */
	public E get(int index){	
		E e0=(E) obj[index];
		return e0;
		
	}
	
	/**
	 * 得到队列的长度,即队列中元素的个数
	 * @return 返回队列中元素的个数
	 */
	public int size(){
		return obj.length;
	}
	
	
}

 

 

 

 

三、用链表实现一个队列并扩展

《用链表实现队列》中,链表实现的队列只能添加数据。下面我们在此基础上进行扩展,定义了deleteinsert方法,可以对队列中的元素进行删除和插入操作。

/**
 * 链表节点类
 * @author zr
 *
 */

public class LinkNode {
	public Object data;
	public LinkNode next;
}


/**
 * 用链表实现一个队列并扩展
 * @author zr
 *
 */
public class LinkListQueue<E> {
	private LinkNode root;
	LinkNode tem1=new LinkNode();//tem1作为一个临时节点
	

	public LinkListQueue(LinkNode root){
		this.root=root;
	}
	
	/**
	 * 在队列中指定位置之前插入一个对象
	 * @param index 指定的位置
	 * @param e 插入的元对象
	 */
	public void insert(int index,E e){
		int length=size();
		LinkNode tem=new LinkNode();
		LinkNode tem2=new LinkNode();
		tem2.data=e;
		int c=1;
		if(index<1){
			System.out.println("位置从1开始!");
		}else if(index==1){
			tem2.next=root;
			root=tem2;
		}else if(index>1&&index<=length){
			tem1=root;
			while(c<index+1){
				if(c==index-1){
					tem2.next=tem1.next;
					tem1.next=tem2;
					tem1=tem2;
				}else{
					tem=tem1.next;
					tem1=tem;
				}
				c++;
			}
		}else{
			System.out.println("您指定的位置超出了队列长队,请重新指定!");
		}
	}
	
	/**
	 * 删除队列中指定位置的某一元素
	 * @param index 指定的位置
	 */
	public void delete(int index){
		LinkNode tem=new LinkNode();
		int c=1;
		int length=size();
		if(index<0){
			System.out.println("位置从1开始");
		}else if(index==1){
			root=root.next;
		}else if(index<=length&&index>1){
			tem1=root;
			while(c<=index){
				if(c==index-1){
					tem=tem1.next.next;
					tem1.next=tem;
					tem1=tem;
				}else{
					tem=tem1.next;
					tem1=tem;
				}	
				c++;
			}
		}else{
			System.out.println("您指定的位置超出了队列范围,请重新指定!");
		}
	}
	
	/**
	 * 向队列中添加一个对象
	 * @param obj 所要添加的对象
	 */
	public void add(E e){	
		if(root==null){
			root=new LinkNode();
			root.data=e;
		}else{
			LinkNode tem=new LinkNode();
			tem.data=e;
			int length=size();
			tem1=get(length);
			tem1.next=tem;
			tem1=tem;
		}
	}

	/**
	 * 获得指定位置的节点
	 * @param index 指定的位置
	 * @return 返回指定位置的节点
	 */
	public LinkNode get(int index){
		int length=size();
		LinkNode node = new LinkNode();
		LinkNode tem=new LinkNode();
		if(index<1){
			System.out.println("位置从1开始");
		}else if(index>=1&&index<=length){
			int c=1;
			tem1=root;
			while(c<index||c==index){
				if(c==index){
					node=tem1;
				}
				c++;
				tem=tem1.next;
				tem1=tem;	
			}
		}else{
			System.out.println("您指定的位置超出了队列范围,请重新指定位置!");
		}
		return node;
	}
	
	/**
	 * 计算队列的长度
	 * @return 返回队列的长度
	 */
	public int size(){
		int length=0;
		LinkNode tem2=new LinkNode();
		LinkNode tem=new LinkNode();
		tem2=root;
		while(tem2!=null){
			tem=tem2.next;
			tem2=tem;
			length++;
		}
		return length;
		
	}
	
	
}


/**
 * 测试用一个链表实现的队列
 * @author zr
 *
 */

public class LLQTest {
	private static LinkNode root;
	
	public static void main(String[] args) {
	
		LinkListQueue<String> llq=new LinkListQueue<String>(root);
		
		//对添加操作的测试
		System.out.println("添加后:");
		llq.add("a");
		llq.add("b");
		llq.add("c");
		llq.add("d");
		llq.add("e");
		for(int i=1;i<=llq.size();i++){
			LinkNode node=llq.get(i);
			System.out.println(i+":"+node.data);
		}
		
		//对删除操作的测试
		
		System.out.println("删除后:");
		llq.delete(2);
		for(int j=1;j<=llq.size();j++){
			LinkNode ADnode=llq.get(j);
			System.out.println(j+":"+ADnode.data);
		}
		
		//对插入操作的测试
		System.out.println("插入后:");

		llq.insert(2, "b");
		
		
		for(int t=1;t<=llq.size();t++){
			LinkNode AInode=llq.get(t);
			System.out.println(t+":"+AInode.data);
		}
	}

}

 结果:

添加后:
1:a
2:b
3:c
4:d
5:e
删除后:
1:a
2:c
3:d
4:e
插入后:
1:a
2:b
3:c
4:d
5:e

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics