可以使用數組線性表實現棧,使用鏈表實現隊列。
棧可以看做是一種特殊類型的線性表,訪問、插入和刪除其中的元素只能在棧尾進行。用數組線性表來實現棧比用鏈表來實現實現效率更高
這裏有兩種辦法可用來設計棧和隊列的類。
- 使用繼承:可以通過繼承數組線性表類ArrayList 來定義棧類,通過繼承鏈表類LinkedList 來定義隊列類。
- 使用組合:可以將數組線性表定義爲棧類中的數據域,將鏈表定義爲隊列類中的數據域,
這兩種設計方法都是可行的,但是相比之下,組合可能更好一些,因爲它可以定義一個全新的棧類和隊列類,而不需要繼承數組線性表類與鏈表類中不必要和不合適的方法。
1、棧
棧的典型應用
- 逆序輸出Conversion
輸出次序與處理過程顛倒;遞歸深讀和輸出長度不易預知 - 遞歸嵌套 stack permutation + parenthesis
具有自相似性的問題可遞歸描述,但分支位置和嵌套深度不固定 - 延遲緩衝 evaluation
線性掃描算法模式中,在預讀足夠長之後,方能確定可處理的前綴 - 棧式計算 RPN
基於棧結構的特定計算模式
1.1 myStack的實現
public class myStack<E> {
private java.util.ArrayList<E> list = new java.util.ArrayList<E>();
public void push(E e){
list.add(e);
}
public E pop(){
return list.remove(list.size()-1);
}
public E top(){
return list.get(list.size()-1);
}
public int getSize(){
return list.size();
}
public boolean empty(){ //if stack is empty, return true;
if(list.size() == 0) return true;
else return false;
}
@Override
public String toString() {
return "stack:" + list.toString();
}
}
1.2 棧應用:進制轉換問題
逆序輸出Conversion :輸出次序與處理過程顛倒;遞歸深讀和輸出長度不易預知
進制轉換
輸入一個數,可以轉換成任意的n進制。
public class convert {
public static void main(String []args){
ConvertBase(-17,2);
}
static void ConvertBase (int num , int base){
myStack s = new myStack();
char digit [] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
boolean flag = false;
if(num < 0){
flag = true;
num *= -1;
}
while (num > 0) {
s.push(digit[num % base]);
num /= base;
}
if(flag){
s.push('-');
}
for(int i = s.getSize() ; i > 0 ; i--)
System.out.print(s.pop());
}
}
1.3 棧應用:括號匹配問題
stack permutation + parenthesis
具有自相似性的問題可遞歸描述,但分支位置和嵌套深度不固定
括號匹配問題
:判斷一個類似於“(())()()()))(((()” 是否左括號和右括號可以一一正確匹配上。
static boolean paren(String s){
myStack stack = new myStack();
for(int i=0; i < s.length(); i++){
if(s.charAt(i) == '(') stack.push(1);
else if(!stack.empty()) stack.pop();
else return false;
}
return stack.empty();
}
這個題在學有限自動機課程時也遇到過,同樣的思路~~
1.4 棧應用:棧混洗問題
/*
描述
輸入兩個整數序列,第一個序列表示棧的壓入順序,請判斷第二個序列是否可能爲該棧的彈出順序。
假設壓入棧的所有數字均不相等。例如序列1,2,3,4,5是某棧的壓入順序,序列4,5,3,2,1是該壓棧序列對應的一個彈出序列,
但4,3,5,1,2就不可能是該壓棧序列的彈出序列。(注意:這兩個序列的長度是相等的)
輸入
第一行:輸入N個整數,空格隔開,按先後順序入棧
第二行:輸入N個整數,空格隔開,表示一種出棧順序
輸出
True 或者 False ,意思是第二行數據是否是一個合法的彈出序列
樣例輸入
1 2 3 4 5
4 5 3 2 1
樣例輸出
True
*/
static boolean sp(){
Scanner in = new Scanner(System.in);
System.out.println("enter your number");
String s1 = in.nextLine();
String s2 = in.nextLine();
String a1[] = s1.split(" ");
String a2[] = s2.split(" ");
Stack<Integer> s = new Stack<>();
int a[] = new int[a1.length]; //a 是壓入棧的順序 從 0--a.length
int b[] = new int[a1.length]; // b 是彈出的順序 從 0--b.length
for(int i = 0;i < a.length;i++){
a[i] = Integer.valueOf(a1[i]);
b[i] = Integer.valueOf(a2[i]);
}
int k = 0;
for(int i = 0; i < a.length; i++){
s.push(a[i]);
while( s.empty()==false && b[k] == s.peek() )
{
s.pop();
k++;
}
}
if( k == a.length && s.empty())
return true;
else
return false;
}
2、隊列的實現
隊列,元素只能從隊列的末端插入,從開始端訪問和刪除。由於刪除是在線性表的起始位置進行的,所以用鏈表實現隊列比用數組線性表實現效率更高。
package ReWrite;
public class GenericQueue<E> {
// 隊列:尾進前出
private java.util.LinkedList<E> list = new java.util.LinkedList<E>();
/**
* 添加一個元素到隊列
* @param e
*/
public void enqueue(E e) {
list.addLast(e);
}
/**
* 從隊列刪除一個元素
*/
public E dequeue() {
return list.removeLast();
}
public int getSize() {
return list.size();
}
@Override
public String toString() {
return "Queue:" + list.toString();
}
}
2、棧的實現
package ReWrite;
public class GenericStack<E> {
private java.util.ArrayList<E> list = new java.util.ArrayList<E>();
/**
* 添加一個元素到隊列
* @param e
*/
public void push(E e) {
list.add(e);
}
/**
* 從隊列刪除一個元素
*/
public E pop() {
return list.remove(list.size()-1);
}
public int getSize() {
return list.size();
}
@Override
public String toString() {
return "stack:" + list.toString();
}
}
3、測試
package ReWrite;
public class Test {
public static void main(String[] args) {
/*
GenericQueue<String> queue = new GenericQueue<String>();
queue.enqueue("tom");
queue.enqueue("Ali");
queue.enqueue("Sua");
System.out.println("(1)" + queue);
System.out.println("(1)" + queue.dequeue());
*/
GenericStack<String> stack = new GenericStack<String>();
stack.push("apple");
stack.push("orange");
stack.push("megon");
System.out.println("(1)" + stack);
System.out.println("(2)" + stack.pop());
System.out.println("(3)" + stack.pop());
System.out.println("(4)" + stack);
}
}
4、優先隊列
普通的隊列是一種先進先出的數據結構,元素在隊列尾追加,而從隊列頭刪除。在優先隊列( priority queue) 中,元素被賦予優先級。當訪問元素時,具有最高優先級的元素最先刪除。例如,醫院的急救室爲病人賦予優先級,具有最高優先級的病人最先得到治療。
可以使用堆實現優先隊列,其中根結點是隊列中具有最高優先級的對象。
package ReWrite;
import Sort.Heap;
public class MyPriorityQueue<E extends Comparable<E>> {
private Heap<E> heap = new Heap<>();
public void enqueue(E newObject) {
heap.add(newObject);
}
public E dequeue() {
return heap.remove();
}
public int getSize() {
return heap.getSize();
}
}
測試:
package ReWrite;
public class Test {
public static void main(String[] args) {
Patient p1 = new Patient("John",2);
Patient p2 = new Patient("Jim",1);
Patient p3 = new Patient("Tim",5);
Patient p4 = new Patient("Cindy",7);
MyPriorityQueue<Patient> priorityQueue = new MyPriorityQueue<>();
priorityQueue.enqueue(p1);
priorityQueue.enqueue(p2);
priorityQueue.enqueue(p3);
priorityQueue.enqueue(p4);
while(priorityQueue.getSize()>0)
System.out.println(priorityQueue.dequeue());
}
static class Patient implements Comparable<Patient>{
private String name;
private int priority;
public Patient(String name, int priority) {
this.name = name;
this.priority = priority;
}
@Override
public String toString() {
return name + "(priority:" + priority + ")";
}
@Override
public int compareTo(Patient o) {
return this.priority - o.priority;
}
}
}