特殊的线性表–栈和队列
1.栈:插入和删除操作只允许在线性表的一端进行。(栈是操作系统实现嵌套调用机制的基础)
栈顶 | 允许操作的一端 |
栈底 | 不允许操作的一端 |
入栈(push) | 往栈中插入元素 |
出栈(pop) | 删除栈中元素 |
栈顶元素(peek) | 返回栈顶元素(未出栈) |
注:顺序栈–入出栈采用尾插入、删除,时间复杂度为O(1),自动扩充容量时入栈为O(n);
链式栈–入出栈采用头插入、删除,时间复杂度为O(1)
2.使用栈计算算术表达式的值
思路:利用栈的特性将中缀表达式转换成后缀表达式
package Stack;
import java.util.Stack;
public class Expression {
public static StringBuffer toPostfix(String infix) {
stack <String>stack=new SeqStack<String>(infix.length());
StringBuffer postfix=new StringBuffer(infix.length()*2);
System.out.println(253);
int i=0;
while(i<infix.length()) {
char ch=infix.charAt(i);
switch(ch) {
case'+':
case'-': //只有栈空或栈顶为“(”时入栈
while(!stack.isEmpty()&&!stack.peek().equals("("))
postfix.append(stack.pop());
stack.push(ch+"");
i++;
break;
case'*':
case'/': //栈空或栈顶不为“*”“/”时入栈
while(!stack.isEmpty()&&(stack.peek().equals("*")||stack.peek().equals("/")))
postfix.append(stack.pop());
stack.push(ch+"");
i++;
break;
case'(':
stack.push(ch+"");
i++;
break;
case')':
String out=stack.pop();
while(out!=null&&!out.equals("(")) {
postfix.append(out);
out=stack.pop();
}
i++;
break;
default: //遇到数字时的处理
while(i<infix.length()&&ch>='0'&&ch<='9') {
postfix.append(ch);
i++;
if(i<infix.length()) {
ch=infix.charAt(i);
}
}
postfix.append(" "); //添加空格作为数值之间的分隔符
}
}
while(!stack.isEmpty()) { //所有运算符出栈
postfix.append(stack.pop());
}
return postfix; //返回后缀表达式
}
//计算后缀表达式的值
public static int toValue(StringBuffer postfix) {
stack<Integer>stack=new LinkedStack<Integer>();
System.out.println(1783);
int value=0;
for(int i=0;i<postfix.length();i++) {
char ch=postfix.charAt(i);
if(ch>='0'&&ch<='9') {
value=0;
while(ch!=' ') { //判别是否为空格间隔符, 将整数字符串转化为整数值
value=value*10+ch-'0';
ch=postfix.charAt(++i); //读取下一个字符
}
stack.push(value);
}
else if(ch!=' ') {
int y=stack.pop(),x=stack.pop(); //出栈两个操作数,出栈顺序
switch(ch) {
case'+':
value=x+y;
break;
case'-':
value=x-y;
break;
case'*':
value=x*y;
break;
case'/':
value=x/y;
break;
}
System.out.print(x+(ch+"")+y+"="+value+", ");
stack.push(value);
}
}
return stack.pop();
}
public static void main(String args[]) {
String infix="123+10*(45-50+20)/((35-25)*2+10)-11";
StringBuffer postfix=toPostfix(infix);
System.out.println(123);
System.out.println("infix="+infix+"\npostfix="+postfix+"\nvalue="+toValue(postfix));
}
}
3.队列:插入和删除操作分别在线性表的两端进行。
队尾 | 允许入队的一端 |
队头 | 允许出队的一端 |
入队(add) | 往队中插入元素 |
出队(poll) | 删除队中元素 |
队头元素(peek) | 返回队头元素(未出栈) |
注:顺序队列–使用顺序表,出队效率低;使用数组,会存在假溢出(即下标越界并不是因为存储空间不够)
顺序循环队列–队列空条件:frontnear;队列满的条件(此时,队列中仍有一个空位置):front(rear+1)%length(front是队头元素下标,rear是下一个入队元素下标,取值为0~length-1)
front=(front+1)%length;
rear=(rear+1)%length;
链式队列–入队效率低(单链表尾插),占用较多存储空间(循环双链表)
4.递归算法
输出n个元素的全排列
如:{1,2,3}的全排列为123,132,213,231 ,312,321
/* * 输出n个元素的全排列(可指定从第几个开始后面的元素全排列) */
package Queue;
import java.util.Scanner;
public class Test4_10 {
public static void Test4_10(int[]list,int start,int length) {
int i;
if(start==length) {
for(i=0;i<length;i++)
System.out.print(list[i]+"");
System.out.println();
}
else {
for(i=start;i<length;i++) { //进行递归
swap(list,start,i);
Test4_10(list,start+1,length);
swap(list,start,i);
}
}
}
public static void swap(int[]list,int start,int i) { //两数交换位置
int temp;
temp=list[start];
list[start]=list[i];
list[i]=temp;
}
public static void main(String[]args) {
System.out.println("请输入要进行全排列的元素个数:");
Scanner scanner=new Scanner(System.in);
int length=scanner.nextInt();
System.out.println("请输入要进行全排列的元素:");
int start=0;// 表示从第start+1个后面的元素开始全排列,前面的保持不变
int []list=new int[length];
for(int j=0;j<length;j++) {
int num=scanner.nextInt();
list[j]=num;
}
System.out.println("这"+length+"个元素的全排列结果为:");
Test4_10(list,start,length);
}
}