Java数据结构和算法(五)——队列

来源:互联网 发布:mac word转pdf 超链接 编辑:程序博客网 时间:2024/06/07 06:13

总结:队列数据结构,先进先出,队首和队尾的概念

1、简单队列:

[java] view plain copy print?
  1. public class Queqe {  
  2.     private int array[];  
  3.     private int front;  
  4.     private int end;  
  5.     private int number;  
  6.     private int max;  
  7.       
  8.     private Queqe(int maxsize){  
  9.         array = new int[maxsize];  
  10.         max = maxsize;  
  11.         front = 0;  
  12.         end = 0;  
  13.         number = 0;  
  14.     }  
  15.       
  16.     private void insert(int item){  
  17.         if(isFull()){  
  18.             System.out.println("is full,can not insert");  
  19.             return;  
  20.         }  
  21.         array[end++] = item;  
  22.         number++;  
  23.     }  
  24.       
  25.     private int remove(){  
  26.         if(isEmpty()){  
  27.             System.out.println("is empty,can not remove");  
  28.             return -1;  
  29.         }  
  30.         number--;  
  31.         return array[front++];  
  32.     }  
  33.       
  34.     private boolean isFull(){  
  35.         return number == max;  
  36.     }  
  37.     private boolean isEmpty(){  
  38.         return number == 0;  
  39.     }  
  40.       
  41.     private int size(){  
  42.         return number;  
  43.     }  
  44.       
  45.     private int peekFront(){  
  46.         return array[front];  
  47.     }  
  48.       
  49.     public static void main(String[] args) {  
  50.         Queqe q = new Queqe(4);  
  51.         System.out.println("queqe is empty:"+q.isEmpty());  
  52.           
  53.         q.insert(1);  
  54.         q.insert(2);  
  55.         q.insert(3);  
  56.         q.insert(4);  
  57.         q.insert(5);  
  58.           
  59.         System.out.println(q.size());  
  60.         System.out.println("front is "+q.peekFront());  
  61.           
  62.         while(!q.isEmpty())  
  63.             System.out.println(q.remove());  
  64.     }  
  65. }  
  66.   
  67. result:  
  68. queqe is empty:true  
  69. is full,can not insert  
  70. 4  
  71. front is 1  
  72. 1  
  73. 2  
  74. 3  
  75. 4  

还是通过数组实现,但是和栈不同的是,队列的话有队头队尾,队头指向队列的首部,而队尾指向队列的尾部,number为队列中数的个数,每当插入一个新元素,队尾后移,每当移除一个新元素,队首后移,插入和移除的同时根据队列是否为空或者是满,才进行插入和移除。

先进的元素排在前面,那么移除的时候就是先移除队头,达到先进先出的效果,·插入和移除并不用移动整个数组,只需改变队头和队列的指向,所以时间复杂度和栈一样都是O(1)。


2、不用number之后的方法改变

前面用了number统计队列中元素个数,其实不用这个变量,单靠队头和队尾也是可以实现队列。


[java] view plain copy print?
  1. private boolean isFull(){  
  2.     return end == max;  
  3. }  
  4. private boolean isEmpty(){  
  5.     return (front ==0&&end ==0)||front == max;  
  6. }  
  7.   
  8. private int size(){  
  9.     return end -front;  
  10. }  

队尾减去队头就是元素的个数,因为一旦插入,end是增加1的。

而判断是不是满了更简单,队尾移到数组尾部即是满了。

空的话会复杂一些,一种是一开始front为零,但是有元素插入,此时end不为零,如果两者为零那就是空了,还有就是不停remove之后,front移到最后,证明之前的元素全部remove掉了,此时也为空。


作者根据的是front和end的变化,然后再insert和remove中直接改变front和end的值,在isEmpty和isFull中,例如在isFull()中:

[java] view plain copy print?
  1. private boolean isFull(){  
  2.     return end+2 == front||(front+max-2==end);  
  3. }  

作者的end一开始设为-1,然后一旦end超过max会变成-1,所以当中有着很复杂的位置关系。

这样更复杂。因为这样类似循环队列,超出之后又重头开始插入。

其实在isEmpty和isFull中直接进行判断就可以了。然后真的超出的时候直接打印错误后return。


3、优先级队列

银行办业务当然要排队,但是,银行的vip用户不需要,因为他存的钱比你多,银行重视这种客户,优先级高,所以他虽然比你晚来到银行,但是排号的时候拿到的号比你还前。


那这样的话,优先级队列就像是一开始就根据优先级排列好顺序的队列。

[java] view plain copy print?
  1. private void insert(int item){  
  2.     if(isFull()){  
  3.         System.out.println("is full,can not insert");  
  4.         return;  
  5.     }  
  6.     if(end == 0){  
  7.         array[end++] = item;  
  8.     }else{  
  9.         int i;  
  10.         for ( i = number-1; i >=0; i--) {  
  11.             if(item > array[i]){  
  12.                 array[i+1] = array[i];  
  13.             }  
  14.         }  
  15.         array[i+1]= item;  
  16.         end++;  
  17.     }  
  18.     number++;  
  19. }  
  20.   
  21. result:  
  22. queqe is empty:true  
  23. size:0  
  24. is full,can not insert  
  25. queqe is empty:false  
  26. size:4  
  27. front is 4  
  28. 4  
  29. 3  
  30. 2  
  31. 1   

现在我们将数值大的看成是优先级高的,第一个插入直接插入数组第一位,后面插入的开始比较,如果比前面的数都小,那么就放在队列最后面,如果大的话,就将整个队列后推,然后找到适当的位置插入,和插入排序是类似的。这样插入元素的同时,就已经按照优先级从大到小的顺序排好序了(前:prefix expression 中:infix expression 后:postfix expression)。


4、算术表达式的解析

1+2+3=?  

由于我们从小接受的教育就是从左到右,有括号计算括号里面,先乘除后加减这样的思路,然后看到上面那个算式的时候一下子就得出结果,这是中缀表达式。也就是我们脑里面计算算式的方式。


从左到右,1+2看后面,是+号,那可以直接算1+2的值为3,3+3后面是=号了,直接计算3+3=6。


1+2*3=?

从左到右,1+2看后面,是*号,那不能直接算1+2的值,先计算2*3=6,再看后面为=,所以计算1+6=7。


1*(2+3)=?

从左到右,1后面是*,所以本来先计算的,但是后面是(所以先看括号,括号里面是2+3=5后面是=,所以直接计算1*5=5。


但是计算机并不像人脑这么聪明。一眼看过去基本可以心算。计算机认后缀表达式比较容易,如果我们从小就接受的是后缀表达式的方式的话,那对于我们来说一样可以。


后缀表达式的话就用符号a,b,c表示了,因为多位数字的话,写成1242132+,根本就不知道是那两个数字相加,那么就要有分隔符,但是无疑会增加难度。

a+b-c转后缀:

读a,读到+,继续读到b,写成ab,再读到-号可以将+放在ab后面,即ab+,读入c,后面结束了则ab+c-。


a+b*c转后缀:

读a,读+,读b,放置为ab,再读后面,*优先级大于+号,暂时不能放+,再读c,c后面结束,所以可以放入*,在放+,即abc*+。


a*(b+c)转后缀:

读a,读*,后面发现(不能放置*,(里比*优先级高,读b+c,后面为),可变为bc+,再和a*合,即abc+*。


这篇虽然讲得是队列,但是要用到的结构是栈,因为进来进去的。这里的算数不用压入栈,直接输出。

a+b-c转后缀:

直接输出a,读+,栈空压入栈,再输出b,栈非空,弹出+,读到-,+优先级>= -,输出+,压-入栈,输出c,结束了,弹出-。

最后结果:ab+c-。


a+b*c转后缀:

直接输出a,读+,栈空压入栈,再输出b,栈非空,弹出+,读到*,+优先级< -,所以先+压入栈,再压*,输出c,结束了,弹出*,再弹+。

最后结果:abc*+。


a*(b+c)转后缀:

直接输出a,读*,栈空压入栈,读到(压(入栈,输出b,读+,压入栈,输出c,读),发现后面结束可以弹出+并输出,弹出(不输出,弹出*。

最后结果:abc+*。


看了这个分析过程之后,就是利用栈,对操作符进行栈的压入和弹出。


如果纯粹用高级语言写计算器,直接使用中缀表达式即可,但是到了底层的编译器,就是需要后缀表达式实现,还要考虑到位数和其他操作符,可想代码远远比上面的复杂。

整体的思路就是这样,代码的实现就是通过栈和条件判断进行入栈和出栈即可。


在java5中新增加了java.util.Queue接口,用以支持队列的常见操作。Queue接口与List、Set同一级别,都是继承了Collection接口。
Queue使用时要尽量避免Collection的add()和remove()方法,而是要使用offer()来加入元素,使用poll()来获取并移出元素。它们的优
点是通过返回值可以判断成功与否
,add()和remove()方法在失败的时候会抛出异常
如果要使用前端而不移出该元素,使用
element()或者peek()方法。

值得注意的是LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用

LinkedList实现了Queue接口。Queue接口窄化了对LinkedList的方法的访问权限(即在方法中的参数类型如果是Queue时,就完全只能访问Queue接口所定义的方法 了,而不能直接访问 LinkedList的非Queue的方法),以使得只有恰当的方法才可以使用。BlockingQueue 继承了Queue接口

import java.util.Queue;  import java.util.LinkedList;  public class TestQueue {     public static void main(String[] args) {         Queue<String> queue = new LinkedList<String>();         queue.offer("Hello");         queue.offer("World!");         queue.offer("你好!");         System.out.println(queue.size());         String str;         while((str=queue.poll())!=null){             System.out.print(str);         }         System.out.println();         System.out.println(queue.size());     } }

JDK7中的队列实现 http://blog.sina.com.cn/s/blog_72ef7bea0101cy7h.html



阅读全文
0 0
原创粉丝点击