一、栈
1.特点:栈是先进后出的。
2.数组模拟栈的分析图
实现 栈的 思路分析
使用数组来模拟栈
定义一个 top 来表示栈顶,初始化 为 -1
入栈的操作,当有数据加入到栈时, top++; stack[top] = data;
出栈的操作, int value = stack[top]; top—, return value
代码实现栈
public class ArrayStack {//栈需求实现private int maxLength;private int[] stack;private int top = -1;public ArrayStack(int maxLength) {this.maxLength = maxLength;stack = new int[maxLength];}public boolean isFull() {return top == maxLength - 1;}public boolean isEmpty() {return top == -1;}public void push(int val) {if (isFull()) {throw new RuntimeException("对不起,已满");}top++;stack[top] = val;}public int pop() {if (isEmpty()) {throw new RuntimeException("对不起,是空栈");}int value = stack[top];top--;return value;}public void list() {if (isEmpty()) {throw new RuntimeException("对不起,是空栈");}for (int i = 0; i < stack.length; i++) {System.out.printf("stack[%d]=%d\t", i, stack[i]);}}//栈中元素存在的个数public int length(){return this.top+1;}}
判断回文(利用栈)
public class TestApp {//判断回文//hello olleh 不是一个回文public static void main(String[] args) {System.out.println(detecation("aba"));}public static boolean detecation(String val){ArrayStack arrayStack = new ArrayStack(10);//获取字符串长度int length =val.length();//放入栈for(int i =0;i<length;i++){//注意:这里将a转化成97arrayStack.push(val.charAt(i));}//获取String newVal = "";int length1=arrayStack.length();for(int i =0;i<length1;i++){if(!arrayStack.isEmpty()){char pop =(char)arrayStack.pop();newVal=newVal+pop;}}/* equals方法的源代码:public boolean euqals(Object obj){return(this==obj);*/if(val.equals(newVal)){return true;}return false;}}
例题:计算机需求分析

public class ArrayStack {//栈需求实现private int maxLength;private int[] stack;private int top = -1;public ArrayStack(int maxLength) {this.maxLength = maxLength;stack = new int[maxLength];}public boolean isFull() {return top == maxLength - 1;}public boolean isEmpty() {return top == -1;}public void push(int val) {if (isFull()) {throw new RuntimeException("对不起,已满");}top++;stack[top] = val;}public int pop() {if (isEmpty()) {throw new RuntimeException("对不起,是空栈");}int value = stack[top];top--;return value;}public void list() {if (isEmpty()) {throw new RuntimeException("对不起,是空栈");}for (int i = 0; i < stack.length; i++) {System.out.printf("stack[%d]=%d\t", i, stack[i]);}}//栈中元素存在的个数public int length() {return this.top + 1;}//判断是否是一个运算符 + - * /public boolean isOper(char v) {return v == '+' || v == '-' || v == '*' || v == '/';}//判断运算符优先级,数字越大的优先级越大public int priority(int oper) {if (oper == '*' || oper == '/') {return 1;} else if (oper == '+' || oper == '-') {return 0;} else {return -1;}}//获取栈顶数据public int peek() {return this.stack[top];}//获取栈容量public int stackLength() {return this.stack.length;}/*** 计算两个数进行运算后的结果* 2+3* 3:num1,2:num2*/public int calculate(int num1, int num2, int oper) {int result = 0;switch (oper) {case '+':result = num1 + num2;break;case '-':result = num2 - num1;break;case '*':result = num1 * num2;break;case '/':result = num2 / num1;break;default:break;}return result;}}
public class TestStack {public static void main(String[] args) {String str="4+3+2*3-1";//1、需要遍历字符串,获取每一个字符。//2、判断当前字符是一个运算符还是数字//3、把数字放入数字栈,把运算符放入运算符栈//4、运算符栈:如果是一个空栈,那么运算符直接入栈,如果运算符栈中已经//有其他运算符就需要先对比运算符优先级,新进来的运算符如果小于等于原栈中运算符,//那么需要把原运算符弹出来,数字栈中的数字进行弹栈,进行运算,运算后的结果重新//放入数字栈,新运算符直接入栈,如果新的运算符优先级大于原栈中的运算符,那么运算符直接入栈。ArrayStack numStack = new ArrayStack(10);ArrayStack symbolStack = new ArrayStack(10);//获取字符串的长度int temp1=0;int temp2=0;int symbolChar = 0;int result = 0;int length =str.length();String values = "";for(int i =0;i<length;i++){char c =str.charAt(i);//是否是一个运算符if(symbolStack.isOper(c)){if(!symbolStack.isEmpty()){//比较运算符的优先级if(symbolStack.priority(c)<=symbolStack.priority(symbolStack.peek())){//1、去符号栈中获取栈顶的符号//2、去数字栈中获取两个数字temp1 = numStack.pop();temp2 = numStack.pop();symbolChar = symbolStack.pop();result= numStack.calculate(temp1,temp2,symbolChar);//把运算结果再次放入数字栈中numStack.push(result);//把当前符号压入符号栈中symbolStack.push(c);}else {symbolStack.push(c);}}else{//如果是空符号栈,将运算结果直接压栈symbolStack.push(c);}}else {//比如 33+44values +=c;if(i==length-1){numStack.push(Integer.parseInt(values));}else{//substring包括起始,不包括终止char data = str.substring(i+1,i+2).charAt(0);if(symbolStack.isOper(data)){numStack.push(Integer.parseInt(values));values="";}}}}while (true){if(symbolStack.isEmpty()){break;}temp1= numStack.pop();temp2= numStack.pop();symbolChar = symbolStack.pop();result= numStack.calculate(temp1,temp2,symbolChar);numStack.push(result);}int res = numStack.pop();System.out.println("结果是"+res);}}
中缀转后缀表达式
package test;public class ArrayStack {//数组的最大长度private int maxLength;//定义一个数组private int[] stack;//初始化指针为-1private int top = -1;//通过构造方法构造数组public ArrayStack(int maxLength) {this.maxLength = maxLength;stack = new int[maxLength];}//判断是否满public boolean isFull() {//如果top指针与顶端相等则放回为truereturn top == maxLength - 1;}//判断是否空public boolean isEmpty() {//如果top指针与-1相等则放回为truereturn top == -1;}//入栈public void push(int val) {if (isFull()) {throw new RuntimeException("对不起,已满");}//将指针往上移一位top++;//将加入的数移动到相应的位置stack[top] = val;}//出栈public int pop() {if (isEmpty()) {throw new RuntimeException("对不起,是空栈");}//将这个数保存到一个变量int value = stack[top];//指针往下移动一位top--;//将这个值返回return value;}}
package test;public class PostInfix {/*(在实际代码中我们添加了大于10的数字情况的处理)1:从左到右顺序读取表达式中的字符:2.是操作数,复制到后缀表达式字符串3:是左括号,把字符压入栈中4:是右括号,从栈中弹出符号到后缀表达式,直到遇到左括号,然后把左括号弹出。5:是操作符,如果此时栈顶操作符优先级大于或等于此操作符,弹出栈顶操作符到后缀表达式,直到发现优先级级更低的元素位置,把操作符压入。6:读到输入的末尾,将栈元素弹出直到该栈变成空栈,将符号写到后缀表达式中*/public String doTransfer(String str){ArrayStack arrayStack = new ArrayStack(20);StringBuffer stringBuffer = new StringBuffer();String values="";char[] chars=str.toCharArray();// 1:从左到右顺序读取表达式中的字符:for(int i=0;i<chars.length;i++){char c = (char)chars[i];// 1.1是操作符,进行分级操作if(c=='+'||c=='-'){doOperation(arrayStack,stringBuffer,c,1);}else if(c=='*'||c=='/'){doOperation(arrayStack,stringBuffer,c,2);//1.2如果是左括号压栈}else if (c=='('){arrayStack.push(c);//1.3如果是右括号...}else if(c==')'){doRightBracket(arrayStack,stringBuffer);// 1.4是操作数,复制到后缀表达式字符串}else {values+=c;char data = str.substring(i+1,i+2).charAt(0);if(data<49||data>57){stringBuffer.append(values+",");values="";}}}while (!arrayStack.isEmpty()){stringBuffer.append((char)arrayStack.pop());}String news=stringBuffer.toString();news= news.replace(","," ");return news;}public void doOperation(ArrayStack arrayStack,StringBuffer buffer,char c,int level){//1.依次从栈顶获取一个值while(!arrayStack.isEmpty()){char topc =(char)arrayStack.pop();//2.这个值跟传入的数据作比较//2.1栈顶数据是(,不动就是把他压回去if(topc=='('){arrayStack.push(topc);break;}else {//首先获取到栈顶元素所对应的级别int topLevel=0;if(topc=='+'|| topc=='-'){topLevel=1;}else {topLevel=2;}//2.2栈顶数据优先级别大于传入的,输出到后缀表达式if(topLevel>=level){buffer.append(topc+",");break;}else {//2.3如果栈顶的优先级小于传入的,不动arrayStack.push(topc);break;}}}//3.找到位置后,把传入的操作符压入arrayStack.push(c);}public void doRightBracket(ArrayStack arrayStack,StringBuffer buffer){//1.从栈中弹出数据,输出到后缀表达式while (!arrayStack.isEmpty()){char topc=(char)arrayStack.pop();//2.直到遇到"("为止if(topc=='('){break;}else {buffer.append(topc+",");}}}public static void main(String[] args){PostInfix t =new PostInfix();String s= "(33+3+2)/5-((77+8)*4-5)";System.out.println("中缀的表现形式:"+s);String ret=t.doTransfer("(33+3+2)/5-((77+8)*4-5)");System.out.println("后缀的表现形式"+"res==="+ret);}}
二、队列
1. 队列遵循先入先出原则。放的时候从尾部放,取得时候从 头部取。
2.环形队列

1: front变量的含义:front指向队列的第一个元素。 front 的初始值 = 0
2: rear 变量的含义: rear指向队列的最后一个元素的后一个位置。因为希望出一个空间作为约定。 rear 的初始值 = 0
3. 当队列满时,条件是 (rear + 1) % maxSize == front 【满】
4. 对队列为空的条件, rear == front 空
5. 当我们这样分析, 队列中有效的数据的个数 (rear + maxSize - front) % maxSize
6. 我们就可以在原来的队列上修改得到,一个环形队列
3: (7+1)%8==0;
5: (1+8-3)%8=6;
import java.util.Scanner;public class shuzu_huanxingduilie {public static void main(String[] args) {// TODO 自动生成的方法存根/** 用数组来模拟环形队列* 环形是通过取模(%)来实现的,取模来循环下标,满了就回到原点* 在上一个代码的基础是进行修改*///测试CircleArray queue = new CircleArray(4);//这里设置4,其有效内存是3,因为最后一个是要空出来的Scanner scanner = new Scanner(System.in);//获取控制台char key = ' ';//用来接受用户输入boolean loop = true;//用来控制系统是否退出while(loop) {System.out.println("s(show):显示队列");System.out.println("e(exit):退出程序");System.out.println("a(add):添加数据到队列");System.out.println("g(get):从队列中取出数据");System.out.println("h(head):查看队列头的数据");System.out.println("\n请输入指令:");key = scanner.next().charAt(0);//接收一个字符(0就是一个)switch(key) {case's':queue.showQueue();break;case'a':System.out.println("请输入需要添加的数");int value = scanner.nextInt();queue.addQueue(value);break;case'g':try {int res = queue.getQueue();//上抛了异常,所以要处理异常System.out.printf("取出的数据是%d\n",res);}catch(Exception e) {System.out.println(e.getMessage());}break;case'h':try {int res = queue.headQueue();System.out.println("队列头数据是"+res);}catch(Exception e) {System.out.println(e.getMessage());}break;case'e':scanner.close();//关闭控制台loop = false;break;}}System.out.println("程序退出成功!");}}//使用数组模拟队列,编写一个类ArrayQueue类class CircleArray {private int maxSize;//表示数组最大容量private int front;//队列头private int rear;//队列尾private int[] arr;//该数组用来存放数据,模拟队列//创建队列的构造器public CircleArray(int arrMaxSize) {maxSize = arrMaxSize;//最大容量arr = new int[maxSize];//创建数组front = 0;//指向队列头部,分析出front是指向队列头所在位置(包含)rear = 0;//指向队列尾的后一位}//判断队列是否满public boolean isFull() {return rear == maxSize-1;}//判断队列是否为空public boolean isEmpty() {return rear == front;}//添加数据到队列public void addQueue(int n) {if(isFull()) {System.out.println("队列已满,无法添加");return;}arr[rear] = n;//修改队尾所指定的数据为要添加的数据,添加完成//将rear后移,这里必须考虑取模,避免rear溢出;取模来实现环形rear = (rear + 1) % maxSize;}//获取队列数据,出队列public int getQueue() {if(isEmpty()) {//因为需要返回值,没有数据可取时,可以抛出异常throw new RuntimeException("队列为空,没有数据可以取出");}//这里需要分析出front是指向队列的第一个元素//1、先把front对应的值保存到一个临时变量//2、将front后移,需要取模//将临时变量的值返回(如果前面直接把front的值返回,就没有后移的机会了)int value = arr[front];front = (front + 1) % maxSize;//front一直在数组里面,不会溢出,因为已经取模return value;}//打印数组所有数据(队列在其中)public void showQueue() {if(isEmpty()) {System.out.println("队列为空,没有数据可以显示");return;}//思路:从front开始遍历,遍历有效个数size()个for(int i=front;i<front+size();i++) {System.out.printf("arr[%d]=%d\n",i % maxSize,arr[i % maxSize]);}}//求出队列中的有效个数public int size() {return (rear + maxSize - front) % maxSize;}//显示队列的头数据(是显示,不是取出,还在队列里面)public int headQueue() {if(isEmpty()) {throw new RuntimeException("队列为空,不存在头数据");}return arr[front];}}
