队列的总结之我的理解
一:队列的定义:
生活中我们知道,一对人排列那么就是一个队列。那么在计算机中呢。我们是否可以猜想队列也是由一些元素排列组成的呢。。在计算机种可以有数组存储数据和链表存储数据。那么队列也就分为两个队了;
二:队列可以分为数组队列和链表队列
数组队列:数组本身就是按书序的时候排列的组合,当我们给他进行一些包装的。加一些方法,那么这时候数组也就是队列了。当然我们也可以理解成单个数组也是队列、
链表队列:链表是由结点构成,给节点加上一些方法那么也就构成了队列。同样一个结点也是队列
三:队列的构建:
三.1:数组队列的构建 :思路:1:先建一个类,然后创建一个内部用来创建数组的方法 2:给数组添加方法,实现队列 添加方法代码如下
/**创建一个内部用来存储的数组*/
private MyShape[] srcA=new MyShape[0];
/**
* 调用此方法,向队列中放入一个MyShape里的对象
* @param m 一个MyShape对象
*/
public void add(MyShape m){
//新建一个数组,使得长度比原数组多一
MyShape[] srcB= new MyShape[srcA.length+1];
//将要加入的对象放在数组的最后一位
srcB[srcA.length]=m;
//将以前的数组放在新数组中
for(int i=0;i<srcA.length;i++){
srcB[i]=srcA[i];
}
//将新数组指向原数组,对换
srcA=srcB;
}
得到队列长度的方法代码如下
/**
* 得到队列的长度
* @return 队列的长度
*/
public int size(){
return srcA.length;
}
然后在写取得队列指定值的对象 代码如下
/**
* 取得队列中的一个值的对象
* @param index为对象取得的位置
* @return 是一个MyShape对象
*/
public MyShape get(int index){
MyShape m=srcA[index];
return m;
}
这样数组队列就创建完了。
同时我们还可以使用泛型。那样的话我在使用时候我们不用使用一个对象就建一个队列,就可以泛型中改变对象就行了。泛型的时候就只要在队列后面加一个<E>就行了。
并且还可以对队列进行优化。1:加上删除方法,在指定队列插入的方法等等;
具体代码如下
/**
* 实现队列的泛型
* @author 戴红涛 2013-4-16
*/
public class MySet<E> {
private int count=100;
private int increase=10;
/**
* 定义一个构造方法,用来传递count,increase
* @param incount是初始值,
* @param increase 增长速度
*/
public MySet(int count,int increase){
this.count=count;
this.increase=increase;
}
/**
* 无参的构造器的方法
*/
public MySet(){
this.count=100;
this.increase=10;
}
/**
* 定义有一个参数的构造方法
* @param count
*/
public MySet(int count){
this.count=count;
}
//队列内部初始用来封装对象的数组,长度为
private Object[] srcA=new Object[count];
/**
* 向队列中加入一个对象
* @param e
*/
public void add(E e){
//新建一个数组,长度是原数组的长度加10
Object destA[]=new Object[srcA.length+increase];
//将要加入的对象放到新数组的最后一个位置
destA[srcA.length]=e;
//将原数组的东西复制到新数组中.,用java机制里面的方法
System.arraycopy(srcA, 0, destA, 0, srcA.length);
//指向新数组
srcA=destA;
}
/*
* 取得队列中指定值的一个对象
*/
public E get(int index){
E st=(E)srcA[index];
return st;
}
/**
* 得到队列中的长度
* @param e
*/
public int size(E e){
return srcA.length;
}
/**
* 定义插入方法
*/
public void insert(int index){
}
}
插入方法的具体就可以自己去完成了。。
三:2:链表队列的构建。
链表队列与数组队列的不同就是在建链表队列的时候要先建一个节点类,节点类有数据,指向的属性;
双向链表节点类的创建代码如下
package com.dht418;
/**
* 双向向链表的节点类的创建
* @author 戴红涛 2013-4-18
*
*/
public class LinkNodev1 {
private Object obj;//节点类数据对象
private LinkNodev1 child;//指向下一个节点;
private LinkNodev1 parent;//指向上一个节点
//在创建对象的时候就传入数据对象
public LinkNodev1(Object obj){
this.obj=obj;
}
//用setter,getter方法分别对节点的封装进行访问
public Object getObj( ){
return obj;
}
public void setObj(Object obj){
this.obj=obj;
}
public LinkNodev1 getChild(){
return child;
}
public void setChild(LinkNodev1 child){
this.child=child;
}
public LinkNodev1 getParent(){
return parent;
}
public void setParent(LinkNodev1 parent){
this.parent=parent;
}
}
这里面通过了对其属性进行了封装,通过setter和getter方法设置和取得,以保证属性不被外面随便调用;
节点类的属性创建好了以后,就是队列的实现了
插入节点代码:
/**
* 插入结点
* @param obj 要插入结点的对象
*/
public void add(Object obj){
//创建一个新节点 ,,在后面括号里要有数据
LinkNodev1 node =new LinkNodev1(obj);
if(front==null){ //头结点为空结点。。。。
front=node; //将要介入的节点 赋值给头结点。。
last=front; //头结点和尾结点指向同一个节点
}
else{
last.setChild(node); //在尾节点后面加一个节
node.setParent(last); //新加入的节点为前面的尾结点
last = node; //一定要记得将新加入的节点赋值给尾结点
}
}
得到链表的长度代码:
/**
* 得到链表的长度
* @return 链表的长度
*/
public int getLength(){
int count =0; //计数器
if(front==null){
return count;
}
//不能用下面的方法进行。。。因为这样的画,头结点就发生 了,而在链表中头结点只能是一个,所以不能改变,
//只能用一个临时变量指向头指针,然后让这个头指针进行移动
// while(front!=null){
// front.setChild(front); //将头指针后移
// count++; //计数器加一
// }
// return count ;
LinkNodev1 node =front.getChild();
while(node!=null){
count++;
node=node.getChild();
}
return count +1;
}
在这里我开始的时候放了一个错误
开始的时候就直接让头结点后移。然后返回头结点,就如上面代码注释掉的。然后后面发现那样的话就变成死循环了,当时在想思路没错,为什么得不到自己想要的结果呢。后面了解到原来是:在链表中头结点只有一个。按我这种方法进行的话,那么头结点一直在变,后面遍历的时候也就不知道是哪个头结点了。。我报保存了就是为了防止以后的错误。
根据索引取出节点的代码如下:
/**
* 根据索引取出节点
* @param index 第几个节点
* @return 根据索引返回的节点
*/
public LinkNodev1 getLinkNodev1(int index){
if(this.getLength()<index||index<0){ //判断链表长度。与索引的大小关系
throw new java.lang.RuntimeException("下表越界"+index+",size:"+this.getLength());
}
else{
int num=0; //计算器
// LinkNodev1 node =new LinkNodev1("aaa"); //在实例化的时候。。括号里面一定要有参数
// node=front;
LinkNodev1 node =front; //创建一个临时变量。同时指向头指针
while(num!=index){ //计算器不等于指定的位置大小
node=node.getChild(); //将该指针的位置下移一位
//下面得到索引的方法是错误的。。。。永远都只是跟节点的下位
// node=front.getChild();
num++ ;
}
return node; //返回此时头指针移到的位置
}
}
遍历链表的方法代码:
/**
* 遍历链表的方法
* @param root :链表的根节点
*/
public void printLinkListv2(LinkNodev1 root){
if(root!=null){ //根节点不为空
Object data=root.getObj(); // 取得根节点的数组
System.out.println("节点内容为:"+data); //输出根节点的数据
LinkNodev1 node =root.getChild(); //取得根节点赋值给一个节点
printLinkListv2(node); //递归调用打印方法,直到全部输出为止
}
}
要是还要加其他的方法,如在指定索引下的插入
/***
* 在指定索引下插入节点
* @param index 指定索引
* @param obj 要插入的节点
*/
public void insertIndexObj(int index,Object obj){
if(this.getLength()<index||index<0){ //判断链表长度。与索引的大小关系
throw new java.lang.RuntimeException("下表越界"+index+",size:"+this.getLength());
}else{
//创建一个新节点
LinkNodev1 newNode = new LinkNodev1(obj);
//得到当前索引位置的节点
LinkNodev1 node=this.getLinkNodev1(index);
if(index==0){ //在开始的时候加入,直接把新节点赋值给头结点
front=newNode;
}
else{
//得到索引位置的父节点
LinkNodev1 fNode=node.getParent();
if(fNode!=null){
//将要插入的新节点插入到这两个节点之间
fNode.setChild(newNode);
newNode.setParent(fNode); //因为是双向表,所以要将父节点和子节点同时写上
}
}
//加入以后设置新的链接关系
newNode.setChild(node);
node.setParent(newNode);
}
}
这样链表队列也就创建成了
测试一下吧。。。。代码如下
public class LinkListv2 {
public static LinkNodev1 front= null; //定义头结点,并把初始化
public LinkNodev1 last=null; //定义尾结点,同样的初始化
/**
* @param 主函数,程序的入口
*/
public static void main(String[] args) {
//加入节点
LinkListv2 list=new LinkListv2();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("bbb");
//插入结点
list.insertIndexObj(1, "000");
//遍历链表
list.printLinkListv2(front);
运行结果。。。
[img]http://dl.iteye.com/upload/attachment/0083/6549/01a57438-31e9-3fb4-a889-4a8df3343812.jpg[/img]
要是还要改正,就添加其他的方法去吧。。
我对这两种队列的理解就是这些了,有更好的希望可以和大家学习
一:队列的定义:
生活中我们知道,一对人排列那么就是一个队列。那么在计算机中呢。我们是否可以猜想队列也是由一些元素排列组成的呢。。在计算机种可以有数组存储数据和链表存储数据。那么队列也就分为两个队了;
二:队列可以分为数组队列和链表队列
数组队列:数组本身就是按书序的时候排列的组合,当我们给他进行一些包装的。加一些方法,那么这时候数组也就是队列了。当然我们也可以理解成单个数组也是队列、
链表队列:链表是由结点构成,给节点加上一些方法那么也就构成了队列。同样一个结点也是队列
三:队列的构建:
三.1:数组队列的构建 :思路:1:先建一个类,然后创建一个内部用来创建数组的方法 2:给数组添加方法,实现队列 添加方法代码如下
/**创建一个内部用来存储的数组*/
private MyShape[] srcA=new MyShape[0];
/**
* 调用此方法,向队列中放入一个MyShape里的对象
* @param m 一个MyShape对象
*/
public void add(MyShape m){
//新建一个数组,使得长度比原数组多一
MyShape[] srcB= new MyShape[srcA.length+1];
//将要加入的对象放在数组的最后一位
srcB[srcA.length]=m;
//将以前的数组放在新数组中
for(int i=0;i<srcA.length;i++){
srcB[i]=srcA[i];
}
//将新数组指向原数组,对换
srcA=srcB;
}
得到队列长度的方法代码如下
/**
* 得到队列的长度
* @return 队列的长度
*/
public int size(){
return srcA.length;
}
然后在写取得队列指定值的对象 代码如下
/**
* 取得队列中的一个值的对象
* @param index为对象取得的位置
* @return 是一个MyShape对象
*/
public MyShape get(int index){
MyShape m=srcA[index];
return m;
}
这样数组队列就创建完了。
同时我们还可以使用泛型。那样的话我在使用时候我们不用使用一个对象就建一个队列,就可以泛型中改变对象就行了。泛型的时候就只要在队列后面加一个<E>就行了。
并且还可以对队列进行优化。1:加上删除方法,在指定队列插入的方法等等;
具体代码如下
/**
* 实现队列的泛型
* @author 戴红涛 2013-4-16
*/
public class MySet<E> {
private int count=100;
private int increase=10;
/**
* 定义一个构造方法,用来传递count,increase
* @param incount是初始值,
* @param increase 增长速度
*/
public MySet(int count,int increase){
this.count=count;
this.increase=increase;
}
/**
* 无参的构造器的方法
*/
public MySet(){
this.count=100;
this.increase=10;
}
/**
* 定义有一个参数的构造方法
* @param count
*/
public MySet(int count){
this.count=count;
}
//队列内部初始用来封装对象的数组,长度为
private Object[] srcA=new Object[count];
/**
* 向队列中加入一个对象
* @param e
*/
public void add(E e){
//新建一个数组,长度是原数组的长度加10
Object destA[]=new Object[srcA.length+increase];
//将要加入的对象放到新数组的最后一个位置
destA[srcA.length]=e;
//将原数组的东西复制到新数组中.,用java机制里面的方法
System.arraycopy(srcA, 0, destA, 0, srcA.length);
//指向新数组
srcA=destA;
}
/*
* 取得队列中指定值的一个对象
*/
public E get(int index){
E st=(E)srcA[index];
return st;
}
/**
* 得到队列中的长度
* @param e
*/
public int size(E e){
return srcA.length;
}
/**
* 定义插入方法
*/
public void insert(int index){
}
}
插入方法的具体就可以自己去完成了。。
三:2:链表队列的构建。
链表队列与数组队列的不同就是在建链表队列的时候要先建一个节点类,节点类有数据,指向的属性;
双向链表节点类的创建代码如下
package com.dht418;
/**
* 双向向链表的节点类的创建
* @author 戴红涛 2013-4-18
*
*/
public class LinkNodev1 {
private Object obj;//节点类数据对象
private LinkNodev1 child;//指向下一个节点;
private LinkNodev1 parent;//指向上一个节点
//在创建对象的时候就传入数据对象
public LinkNodev1(Object obj){
this.obj=obj;
}
//用setter,getter方法分别对节点的封装进行访问
public Object getObj( ){
return obj;
}
public void setObj(Object obj){
this.obj=obj;
}
public LinkNodev1 getChild(){
return child;
}
public void setChild(LinkNodev1 child){
this.child=child;
}
public LinkNodev1 getParent(){
return parent;
}
public void setParent(LinkNodev1 parent){
this.parent=parent;
}
}
这里面通过了对其属性进行了封装,通过setter和getter方法设置和取得,以保证属性不被外面随便调用;
节点类的属性创建好了以后,就是队列的实现了
插入节点代码:
/**
* 插入结点
* @param obj 要插入结点的对象
*/
public void add(Object obj){
//创建一个新节点 ,,在后面括号里要有数据
LinkNodev1 node =new LinkNodev1(obj);
if(front==null){ //头结点为空结点。。。。
front=node; //将要介入的节点 赋值给头结点。。
last=front; //头结点和尾结点指向同一个节点
}
else{
last.setChild(node); //在尾节点后面加一个节
node.setParent(last); //新加入的节点为前面的尾结点
last = node; //一定要记得将新加入的节点赋值给尾结点
}
}
得到链表的长度代码:
/**
* 得到链表的长度
* @return 链表的长度
*/
public int getLength(){
int count =0; //计数器
if(front==null){
return count;
}
//不能用下面的方法进行。。。因为这样的画,头结点就发生 了,而在链表中头结点只能是一个,所以不能改变,
//只能用一个临时变量指向头指针,然后让这个头指针进行移动
// while(front!=null){
// front.setChild(front); //将头指针后移
// count++; //计数器加一
// }
// return count ;
LinkNodev1 node =front.getChild();
while(node!=null){
count++;
node=node.getChild();
}
return count +1;
}
在这里我开始的时候放了一个错误
开始的时候就直接让头结点后移。然后返回头结点,就如上面代码注释掉的。然后后面发现那样的话就变成死循环了,当时在想思路没错,为什么得不到自己想要的结果呢。后面了解到原来是:在链表中头结点只有一个。按我这种方法进行的话,那么头结点一直在变,后面遍历的时候也就不知道是哪个头结点了。。我报保存了就是为了防止以后的错误。
根据索引取出节点的代码如下:
/**
* 根据索引取出节点
* @param index 第几个节点
* @return 根据索引返回的节点
*/
public LinkNodev1 getLinkNodev1(int index){
if(this.getLength()<index||index<0){ //判断链表长度。与索引的大小关系
throw new java.lang.RuntimeException("下表越界"+index+",size:"+this.getLength());
}
else{
int num=0; //计算器
// LinkNodev1 node =new LinkNodev1("aaa"); //在实例化的时候。。括号里面一定要有参数
// node=front;
LinkNodev1 node =front; //创建一个临时变量。同时指向头指针
while(num!=index){ //计算器不等于指定的位置大小
node=node.getChild(); //将该指针的位置下移一位
//下面得到索引的方法是错误的。。。。永远都只是跟节点的下位
// node=front.getChild();
num++ ;
}
return node; //返回此时头指针移到的位置
}
}
遍历链表的方法代码:
/**
* 遍历链表的方法
* @param root :链表的根节点
*/
public void printLinkListv2(LinkNodev1 root){
if(root!=null){ //根节点不为空
Object data=root.getObj(); // 取得根节点的数组
System.out.println("节点内容为:"+data); //输出根节点的数据
LinkNodev1 node =root.getChild(); //取得根节点赋值给一个节点
printLinkListv2(node); //递归调用打印方法,直到全部输出为止
}
}
要是还要加其他的方法,如在指定索引下的插入
/***
* 在指定索引下插入节点
* @param index 指定索引
* @param obj 要插入的节点
*/
public void insertIndexObj(int index,Object obj){
if(this.getLength()<index||index<0){ //判断链表长度。与索引的大小关系
throw new java.lang.RuntimeException("下表越界"+index+",size:"+this.getLength());
}else{
//创建一个新节点
LinkNodev1 newNode = new LinkNodev1(obj);
//得到当前索引位置的节点
LinkNodev1 node=this.getLinkNodev1(index);
if(index==0){ //在开始的时候加入,直接把新节点赋值给头结点
front=newNode;
}
else{
//得到索引位置的父节点
LinkNodev1 fNode=node.getParent();
if(fNode!=null){
//将要插入的新节点插入到这两个节点之间
fNode.setChild(newNode);
newNode.setParent(fNode); //因为是双向表,所以要将父节点和子节点同时写上
}
}
//加入以后设置新的链接关系
newNode.setChild(node);
node.setParent(newNode);
}
}
这样链表队列也就创建成了
测试一下吧。。。。代码如下
public class LinkListv2 {
public static LinkNodev1 front= null; //定义头结点,并把初始化
public LinkNodev1 last=null; //定义尾结点,同样的初始化
/**
* @param 主函数,程序的入口
*/
public static void main(String[] args) {
//加入节点
LinkListv2 list=new LinkListv2();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("bbb");
//插入结点
list.insertIndexObj(1, "000");
//遍历链表
list.printLinkListv2(front);
运行结果。。。
[img]http://dl.iteye.com/upload/attachment/0083/6549/01a57438-31e9-3fb4-a889-4a8df3343812.jpg[/img]
要是还要改正,就添加其他的方法去吧。。
我对这两种队列的理解就是这些了,有更好的希望可以和大家学习