一. 算數表達式計算
思路: (1)計算機要運行後綴表達式, 後綴表達式不用()表示優先級, 採用操作符的出現順序表示
(2)中綴表達式轉化爲後綴表達式
1)初始化運算符棧, 遍歷表達式字符串
2)若字符爲操作數, 直接送往後綴表達式
3)若字符爲'(', 則直接入操作符棧
4)若字符爲運算符:
棧空時, 直接入棧
非空時, 從棧彈出優先級比該字符高的操作符加入後綴表達式, 再將本身入棧
5)若爲')' , 彈出操作符到後綴表達式, 直到棧頂操作符爲'(', 並丟棄'('
6)讀取完畢,若戰中還有操作符,全部彈出到後綴表達式
(3)計算後綴表達式
1)初始化操作數棧, 遍歷後綴表達式
2)若爲操作數,直接入棧
3)若爲操作符, 彈出兩個操作數做運算, 結果入棧
public class StackExample{
private int getPriority(char c){
if(c=='('){
return 0;
}else if(c=='+'||c=='-'){
return 1;
}else if(c=='*'||c=='/'||c=='%'){
return 2;
}else if(c=='^'){
return 3;
}else{
return -1;
}
}
private String toPostfix(String expression) throws Exception{
char[] chs = expression.toCharArray();
LinkedStack<Character> opStack = new LinkedStack<Character>();
StringBuilder sb = new StringBuilder();
for(int i=0;i<chs.length;i++){
char c = chs[i];
if(c=='('){
opStack.push(c);
}else if(c==')'){
char cc = opStack.pop();
while(cc!='('){
sb.append(cc);
cc = opStack.pop();
}
}else if(getPriority(c)!=-1){ //運算符
if(opStack.length()!=0){
Character cc = opStack.pop();
while(cc!=null&&getPriority(cc)>=getPriority(c)){//棧中的操作符可能都比新來的優先級高,則循環內的pop最後一次返回null
sb.append(cc);
cc = opStack.pop();
}
if(cc!=null) //必須判空,跳出while的條件是cc==null,null會被壓棧
opStack.push(cc); //最後一次取操作符的優先級比c低,要重新壓棧
}
opStack.push(c);
}else{
sb.append(c); //操作數直接加入string
}
}
while(opStack.length()!=0){ //遍歷完字符數組,若棧中還有操作符,加入後綴表達式
sb.append(opStack.pop());
}
return sb.toString();
}
public int count(String postfixStr) throws Exception{
LinkedStack<Integer> numStack = new LinkedStack<Integer>();
int result = 0;
for(char c:postfixStr.toCharArray()){
if(this.getPriority(c)==-1){ //操作數入棧
numStack.push(Integer.parseInt(c+""));
}else{
int num1 = numStack.pop();
int num2 = numStack.pop(); //num2是num1的下一個數
if(c=='+'){
result = num2 + num1;
}
if(c=='-'){
result = num2 - num1;
}
if(c=='*'){
result = num2 * num1;
}
if(c=='/'){
result = num2/num1;
}
if(c=='%'){
result = num2 % num1;
}
if(c=='^'){
result = num2 ^ num1;
}
numStack.push(result);
}
}
return numStack.pop();
}
public static void main(String[] args) throws Exception {
StackExample sc = new StackExample();
String str = sc.toPostfix("2+3*(4-1)");
System.out.println(sc.count(str));
}
}
二. 左右分隔符匹配
思路: 括號的匹配是遵循就近原則的, 最裏面的左括號要和最裏面的右括號匹配,棧有記憶功能,用站記錄左括號(1) 若是左括號"(,[,{" , 則入棧
(2) 若是右括號"),],}" , 去棧中匹配
public class StackExample{
private LinkedStack<Character> stack = new LinkedStack<Character>();
public boolean matches(char c1,char c2){
if((c1=='('&&c2==')')||(c1=='{'&&c2=='}')||(c1=='['&&c2==']'))
return true;
return false;
}
public boolean isLegal(String str) throws Exception{
char[] chs = str.toCharArray();
for(char c:chs){
if((c=='(')||(c=='{')||(c=='[')){
stack.push(c);
}
if((c==')')||(c=='}')||(c==']')){
if(stack.length()==0) //若棧中沒有"左括號"可以和右括號匹配,則匹配失敗
return false;
if (!matches(stack.pop(),c))
return false;
}
}
if(stack.length()!=0) //若匹配完"右括號",棧中仍有"左括號",則匹配失敗
return false;
return true;
}
}
三. 大數加減思路 : 1) 兩個加數從最高位開始入棧, 這樣取的時候從個位取
2) pop的兩個數相加, 個位數壓入sum棧, 十位數當做進位參與下次相加
3) 若短的加數棧空, 則長的加數加上進位入sum棧,
4) 最後當兩個棧都空, 如果還有進位, 則進位入棧
public class StackExample{
private LinkedStack<Integer> sum = new LinkedStack<Integer>();
private LinkedStack<Integer> num1 = new LinkedStack<Integer>();
private LinkedStack<Integer> num2 = new LinkedStack<Integer>();
private int b = 0;
private LinkedStack<Integer> string2Stack(String str){ //將string轉化成整數棧
char[] chs = str.toCharArray();
LinkedStack<Integer> stack = new LinkedStack<Integer>();
for(int i=0;i<chs.length;i++){
stack.push(Integer.parseInt(chs[i]+""));
}
return stack;
}
private void sum(LinkedStack<Integer> longs,LinkedStack<Integer> shorts) throws Exception{
int i = 0;
while(longs.length()!=0){ //兩個棧pop()的數相加再加上進位,就是這個'位'的和
if(shorts.length()!=0){
i = shorts.pop() + longs.pop() + b;
}else{
i = longs.pop() + b;
}
sum.push(i%10);
b = i/10;
}
if(b!=0) //最後如果還有進位,入棧(111+899=1000的情況,沒有這個結果是000)
sum.push(b);
while(longs.length()!=0) //取出sum和
sum.push(longs.pop());
}
public String sum(String str1,String str2) throws Exception{
num1 = this.string2Stack(str1);
num2 = this.string2Stack(str2);
if(num1.length()>=num2.length()){
this.sum(num1,num2);
}else{
this.sum(num2,num1);
}
StringBuilder sb = new StringBuilder();
while(sum.length()!=0){
sb.append(sum.pop());
}
return sb.toString();
}
public static void main(String[] args) throws Exception {
StackExample se = new StackExample();
System.out.println(se.sum("111", "9"));;
}
}
四. 漢諾塔思路: 1. 只有一個圓盤時, 直接有x移到z
2. n個圓盤時, 把前面的n-1個圓盤移到中間軸y後, 直接一共第一個圓盤到z
3. 而前面的n-1個圓盤由x移到y, 又和原問題同解, 所以遞歸
4. 最後吧n-1個圓盤由y移到z
int c = 0;
private void move(int n,char x,char z){
System.out.println("第"+ ++c +"次:"+n+"號"+x+"-->"+z);
}
private void hanoi(int n,char x,char y,char z){
if(n==1){
move(1,x,z);
}else{
hanoi(n-1,x,z,y);
move(n,x,z);
hanoi(n-1,y,x,z);
}
}
@Test
public void tess(){
hanoi(3, 'x', 'y', 'z');
}