一、栈
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转化成97
arrayStack.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+44
values +=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;
//初始化指针为-1
private int top = -1;
//通过构造方法构造数组
public ArrayStack(int maxLength) {
this.maxLength = maxLength;
stack = new int[maxLength];
}
//判断是否满
public boolean isFull() {
//如果top指针与顶端相等则放回为true
return top == maxLength - 1;
}
//判断是否空
public boolean isEmpty() {
//如果top指针与-1相等则放回为true
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;
}
}
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];
}
}