数据结构和算法(4)-----栈

2023-11-10

一、栈的一个实际需求

例如,请输入一个表达式计算式:[7*2*2-5+1-5+3-3] 点击计算【如下图】

请问: 计算机底层是如何运算得到结果的? 注意不是简单的把算式列出运算,因为我们看这个算式 7 * 2 * 2 - 5, 但是计算机怎么理解这个算式的(对计算机而言,它接收到的就是一个字符串),我们讨论的是这个问题。--------->栈

二、栈的基本介绍

  • 栈的英文为(stack)
  • 栈是一个先入后出(FILO-First In Last Out)的有序列表。
  • 栈(stack)是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删除的一端,为变化的一端,称为栈顶(Top),另一端为固定的一端,称为栈底(Bottom)。
  • 根据栈的定义可知,最先放入栈中元素在栈底,最后放入的元素在栈顶,而删除元素刚好相反,最后放入的元素最先删除,最先放入的元素最后删除
  • 图解方式说明入栈(push)和出栈(pop)的原理

三、栈的应用场景

  • 子程序的调用:在跳往子程序前,会先将下个指令的地址存到堆栈中,直到子程序执行完后再将地址取出,以回到原来的程序中。     
  • 处理递归调用:和子程序的调用类似,只是除了储存下一个指令的地址外,也将参数、区域变量等数据存入堆栈中。
  • 表达式的转换[中缀表达式转后缀表达式]与求值(实际解决)。
  • 二叉树的遍历。
  • 图形的深度优先(depth一first)搜索法。

四、数组模拟栈

用数组模拟栈的使用,由于栈是一种有序列表, 当然可以使用数组的结构来储存栈的数据内容, 下面我们就用数组模拟栈的出栈,入栈等操作。

代码实现:

package com.marden.demo2;

public class ArrayStackDemo {
	public static void main(String[] args) {
		ArrayStack arrayStack=new ArrayStack(5);
		arrayStack.show();
		System.out.println("*******************");
		
		arrayStack.push(3);
		arrayStack.push(5);
		arrayStack.push(10);
		arrayStack.show();
		System.out.println("*******************");
		
		
		arrayStack.pop();
		arrayStack.show();
		System.out.println("*******************");
	}
	
	
	
	

}

class ArrayStack{
	private int maxSize;
	private int [] stack;
	private int top;
	
	public ArrayStack(int maxSize){
		this.maxSize=maxSize;
		stack=new int [this.maxSize];
		top=-1;
	}
	
	
	//判断栈满
	public boolean isFull(){
	
		return top==maxSize-1;
		
	}
	
	
	//判断栈空
	public boolean isEmpty(){
		return top==-1;
		
	}
	
	//入栈
	public void push(int value){
		//首先判断是否栈满,若栈满则无法入栈
		if(isFull()){
			System.out.println("栈满,无法入栈");
		}else{
			top++;
			stack[top]=value;
		}	
	}
	
	
	//出栈
	public int pop(){
		//首先判断是否栈空,若栈空则无法出栈
		if(isEmpty()){
			System.out.println("栈空,无法出栈");
			return -999;
		}else{
			int temp=stack[top];
			top--;
			return temp;
		}	
	}
	
	
	public void show(){
		//首先判断是否栈空,若栈空则无法显示
		if(isEmpty()){
			System.out.println("栈空,无法显示数据");
		}else{
			for(int i=top;i>=0;i--){
				System.out.println(stack[i]);
			}
		}
	}
	
	
}

五、链表模拟栈

代码实现:

package com.marden.demo2;

public class ListStackDemo {
	public static void main(String[] args) {
		ListStack listStack=new ListStack();
		listStack.show();
		System.out.println("***************");
		
		listStack.push(2);
		listStack.push(5);
		listStack.show();
		System.out.println("***************");
		
		listStack.pop();
		listStack.show();
		System.out.println("***************");
		
		listStack.pop();
		listStack.show();
		System.out.println("***************");
		
	}
	
	
	
	

}

class ListStack{
	ListNode top;
	
	public ListStack(){
		ListNode listNode=new ListNode();
		top=listNode;
	}
	
	
	
	
	//判断栈空
	public boolean isEmpty(){
		return top.next==null;
		
	}
	
	
	//入栈
	public void push(int value){
		ListNode temp =new ListNode(value);
		temp.next=top;
		top=temp;
		
	}
	
	
	
	//出栈
	public int pop(){
		if(isEmpty()){
			System.out.println("栈空,无法出栈");
			return -999;
		}else{
			int temp=top.data;
			ListNode p=top.next;
			top.next=null;
			top=p;
			return temp;
		}	
	}
	
	
	public void show(){
		if(isEmpty()){
			System.out.println("栈空,无法显示数据");
		}else{
			ListNode temp=top;
			while(temp.next!=null){
				System.out.println(temp.data);
				temp=temp.next;
			}
		}
	}
	
	
	
	
}


class ListNode{
	int data;
	ListNode next;
	
	public ListNode(){
		
	}
	
	public ListNode(int data){
		this.data=data;
	}
}

 

六、栈实现综合计算器(中缀表达式)

需求:

思路分析:

代码实现:

package com.marden.demo3;



//单位数表达式
public class Calculator {
	public static boolean isOper(char value){
		return value=='+'||value=='-'||value=='*'||value=='/';
	}
	
	public static int priority(int i){
		if(i=='*'|| i=='/'){
			return 1;
		}else if(i=='+'|| i=='-'){
			return 0;
		}else{
			return -1;
		} 
	}
	
	public static int cal(int num1,int num2,int oper){
		int temp = 0;
		switch (oper) {
		case '+':
			temp= num1+num2;
			break;
		case '-':
			temp= num2-num1;
			break;
		case '*':
			temp= num1*num2;
			break;
		case '/':
			temp= num2/num1;
			break;
		default:
			break;
		}
		return temp;
	}
	
		
	
	public static void main(String[] args) {
		String expression="3*6/2-1+3*3";
		ArrayStack numStack=new ArrayStack(10);   //数字栈
		ArrayStack operStack=new ArrayStack(10);  //符号栈
		int index=0;
		int num1=0;
		int num2=0;
		int oper=0;
		int rs=0;
		
		//循环遍历字符串的每个位置
		while(true){
			char temp=expression.substring(index, index+1).charAt(0);
			//判断字符是否为数字,如果是数字则直接压入数字栈
			if(!isOper(temp)){
				numStack.push(temp-48);   //次数获取到的是字符,根据ASCII表,转成对应的数字
			}else{
				//如果字符为符号,则分两种情况
				//1.如果符号栈为空,则直接入栈
				if(operStack.isEmpty()){
					operStack.push(temp);
				}else{
				//2.如果符号栈不为空,则分两种情况
					//2.1 如果当前符号的优先级比符号栈中栈顶的符号优先级高,则直接入栈
					if(priority(temp)>priority(operStack.topElement())){
						operStack.push(temp);
					}else{
						//2.2 如果当前符号的优先级比符号栈中栈顶的符号优先级低或者相同,则从数字栈中出栈两个数字,从符号栈中出栈一个符号进行计算,并将计算结果压入数字栈
						num1=numStack.pop();
						num2=numStack.pop();
						oper=operStack.pop();
						rs=cal(num1, num2, oper);
						numStack.push(rs);
						//符号直接入栈
						operStack.push(temp);
					}	
				}	
			}
			index++;
			
			
			if(index==expression.length()){
				break;
			}
		}
		
        //遍历完字符串,对数字栈和符号栈进行计算,直到符号栈为空,此时数字栈中的最后一个元素即为最后的计算结果
		while(!operStack.isEmpty()){
			num1=numStack.pop();
			num2=numStack.pop();
			oper=operStack.pop();
			rs=cal(num1, num2, oper);
			numStack.push(rs);
		}
		int sqc=numStack.pop();
		System.out.println(expression+"="+sqc);
			
	}
}



//使用数组存储形式的栈
class ArrayStack{
	private int maxSize;
	private int [] stack;
	private int top;
	
	public ArrayStack(int maxSize){
		this.maxSize=maxSize;
		stack=new int [this.maxSize];
		top=-1;
	}
	
	//查看栈顶元素的内容
	public int topElement(){
		return stack[top];
	}
	
	
	//判断栈满
	public boolean isFull(){
		return top==maxSize-1;
	}
	
	
	//判断栈空
	public boolean isEmpty(){
		return top==-1;	
	}
	
	//入栈
	public void push(int value){
		//首先判断是否栈满,若栈满则无法入栈
		if(isFull()){
			System.out.println("栈满,无法入栈");
		}else{
			top++;
			stack[top]=value;
		}	
	}
	
	
	//出栈
	public int pop(){
		//首先判断是否栈空,若栈空则无法出栈
		if(isEmpty()){
			System.out.println("栈空,无法出栈");
			return -999;
		}else{
			int temp=stack[top];
			top--;
			return temp;
		}	
	}
	
    //打印栈中的内容
	public void show(){
		//首先判断是否栈空,若栈空则无法显示
		if(isEmpty()){
			System.out.println("栈空,无法显示数据");
		}else{
			for(int i=top;i>=0;i--){
				System.out.println(stack[i]);
			}
		}
	}
	
		
}

效果演示:(计算3*6/2-1+3*3)

分析:

上述代码实现了中缀表达式的逻辑运算,但是只适用于个位数的计算,未考虑到多位数的计算。

优化代码:(多位数的中缀表达式计算)

package com.marden.demo3;



//多位数表达式
public class Calculator1 {

    //判断字符是否为操作符
	public static boolean isOper(char value){
		return value=='+'||value=='-'||value=='*'||value=='/';
	}
	

    //根据操作符,返回其优先级,数值越大,优先级越高
	public static int priority(int i){
		if(i=='*'|| i=='/'){
			return 1;
		}else if(i=='+'|| i=='-'){
			return 0;
		}else{
			return -1;
		} 
	}
	

    //根据两个数值和操作符进行逻辑运算
	public static int cal(int num1,int num2,int oper){
		int temp = 0;
		switch (oper) {
		case '+':
			temp= num1+num2;
			break;
		case '-':
			temp= num2-num1;
			break;
		case '*':
			temp= num1*num2;
			break;
		case '/':
			temp= num2/num1;
			break;
		default:
			break;
		}
		return temp;
	}
	

	
	
	
	
	
	public static void main(String[] args) {
		
		String expression="32+68-2*11";
		ArrayStack numStack=new ArrayStack(10);   //数字栈
		ArrayStack operStack=new ArrayStack(10);  //符号栈
		int index=0;
		int num1=0;
		int num2=0;
		int oper=0;
		int rs=0;
		char [] charTemp=expression.toCharArray();
		while(true){
			char temp=expression.substring(index, index+1).charAt(0);
			//判断字符是否为数字,如果是数字则直接压入数字栈
			if(!isOper(temp)){
				//numStack.push(temp-48);   //获取到的是字符,根据ASCII表,转成对应的数字
				
				//如果是多位数,则需找到完整的数字,首先确定完整数字的边界
				
				int end=charTemp.length-1;
				for(int i=index;i<charTemp.length;i++){
					if(isOper(charTemp[i])){
						end=i-1;
						break;
					}
				}
				//将字符类型的数据转换成真实数字
				int multiNum=0;
				int count=0;
				for(int i=end;i>=index;i--){
					multiNum+=(charTemp[i]-48)*Math.pow(10, count);   //根据ASCII表,将获取的字符转成对应的数字
					count++;
				}
				//System.out.println(multiNum);
				numStack.push(multiNum);
				index=end;
				
			}else{
				//如果字符为符号,则分两种情况
				//1.如果符号栈为空,则直接入栈
				if(operStack.isEmpty()){
					operStack.push(temp);
				}else{
				//2.如果符号栈不为空,则分两种情况
					//2.1 如果当前符号的优先级比符号栈中栈顶的符号优先级高,则直接入栈
					if(priority(temp)>priority(operStack.topElement())){
						operStack.push(temp);
					}else{
						//2.2 如果当前符号的优先级比符号栈中栈顶的符号优先级低或者相同,则从数字栈中出栈两个数字,从符号栈中出栈一个符号进行计算,并将计算结果压入数字栈
						num1=numStack.pop();
						num2=numStack.pop();
						oper=operStack.pop();
						rs=cal(num1, num2, oper);
						numStack.push(rs);
						//符号直接入栈
						operStack.push(temp);
					}	
				}
				
			}
			index++;
			
			
			if(index==expression.length()){
				break;
			}
		}
		
		
		while(!operStack.isEmpty()){
			num1=numStack.pop();
			num2=numStack.pop();
			oper=operStack.pop();
			rs=cal(num1, num2, oper);
			numStack.push(rs);
		}
		int sqc=numStack.pop();
		System.out.println(expression+"="+sqc);
		
		
		
	}
}

class ArrayStack1{
	private int maxSize;
	private int [] stack;
	private int top;
	
	public ArrayStack1(int maxSize){
		this.maxSize=maxSize;
		stack=new int [this.maxSize];
		top=-1;
	}
	
	//查看栈顶元素的内容
	public int topElement(){
		return stack[top];
	}
	
	
	//判断栈满
	public boolean isFull(){
		return top==maxSize-1;
	}
	
	
	//判断栈空
	public boolean isEmpty(){
		return top==-1;	
	}
	
	//入栈
	public void push(int value){
		//首先判断是否栈满,若栈满则无法入栈
		if(isFull()){
			System.out.println("栈满,无法入栈");
		}else{
			top++;
			stack[top]=value;
		}	
	}
	
	
	//出栈
	public int pop(){
		//首先判断是否栈空,若栈空则无法出栈
		if(isEmpty()){
			System.out.println("栈空,无法出栈");
			return -999;
		}else{
			int temp=stack[top];
			top--;
			return temp;
		}	
	}
	
	public void show(){
		//首先判断是否栈空,若栈空则无法显示
		if(isEmpty()){
			System.out.println("栈空,无法显示数据");
		}else{
			for(int i=top;i>=0;i--){
				System.out.println(stack[i]);
			}
		}
	}	
}

效果演示:(计算32+68-2*11)

 

七、表达式计算

  • 前缀表达式(波兰式):前缀表达式的运算符位于操作数之前,举例说明: (3+4)×5-6 对应的前缀表达式就是 - × + 3 4 5 6
  • 中缀表达式:中缀表达式就是常见的运算表达式,如(3+4)×5-6
  • 后缀表达式(逆波兰式):与前缀表达式相似,只是运算符位于操作数之后,举例说明: (3+4)×5-6 对应的后缀表达式就是 3 4 + 5 × 6 –

前缀表达式的计算机求值:

从右至左扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(栈顶元素 和 次顶元素),并将结果入栈;重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果

例如: (3+4)×5-6 对应的前缀表达式就是 - × + 3 4 5 6 , 针对前缀表达式求值步骤如下:

  • 从右至左扫描,将6、5、4、3压入堆栈
  • 遇到+运算符,因此弹出3和4(3为栈顶元素,4为次顶元素),计算出3+4的值,得7,再将7入栈
  • 接下来是×运算符,因此弹出7和5,计算出7×5=35,将35入栈
  • 最后是-运算符,计算出35-6的值,即29,由此得出最终结果

中缀表达式的计算机求值:

中缀表达式的求值是我们人最熟悉的,但是对计算机来说却不好操作(前面我们讲的案例就能看的这个问题),因此,在计算结果时,往往会将中缀表达式转成其它表达式来操作(一般转成后缀表达式.)

后缀表达式的计算机求值:

从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 和 栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果

例如: (3+4)×5-6 对应的后缀表达式就是 3 4 + 5 × 6 - , 针对后缀表达式求值步骤如下:

  • 从左至右扫描,将3和4压入堆栈;
  • 遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素),计算出3+4的值,得7,再将7入栈;
  • 将5入栈;
  • 接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈;
  • 将6入栈;
  • 最后是-运算符,计算出35-6的值,即29,由此得出最终结果

逆波兰计算机的实现:

我们完成一个逆波兰计算器,要求完成如下任务:

  • 输入一个逆波兰表达式(后缀表达式),使用栈(Stack), 计算其结果
  • 支持小括号和多位数整数,因为这里我们主要讲的是数据结构,因此计算器进行简化,只支持对整数的计算。
package com.marden.demo4;

import java.util.ArrayList;
import java.util.Stack;


//逆波兰表达式的计算
public class PolandNotation {
	public static void main(String[] args) {
		String expression="3 4 + 5 * 6 -";
		//1.将给定的字符串分割,并存入到ArrayList中
		ArrayList<String> splitList=getStringList(expression);
		//2.将分割好的字符串ArrayList进行计算,并返回最后计算结果
		int result=cal(splitList);
		System.out.println("逆波兰表达式:"+expression+"的计算结果为:"+result);
	}
	
	
	
	//将给定的字符串,分割成为字符串数组,并存入到ArrayList
	public static ArrayList<String> getStringList(String expression){
		String [] splitArray=expression.split(" ");   //根据空格,将字符串分割为字符串数组
		ArrayList<String> list=new ArrayList<String>();
		for(String str:splitArray){
			list.add(str);
		}	
		return list;
	}
	

	//遍历ArrayList,并利用栈数据结构,完成逆波兰表达式的计算
	public static int cal(ArrayList<String> list){
		Stack<String> stack=new Stack<>();
		for(String str:list){
			//判断list中的元素是否为数字,如果为数字,则直接入栈
			if(str.matches("\\d+")){     //根据正则表达式,判断是否为数字(单位数字或者多位数字)
				stack.push(str);
			}else{
				//如果为操作符,则出栈两次,并进行计算
				int num2=Integer.parseInt(stack.pop());
				int num1=Integer.parseInt(stack.pop());
				int rs=0;
				if(str.equals("+")){
					rs=num1+num2;
				}else if(str.equals("-")){
					rs=num1-num2;
				}else if(str.equals("*")){
					rs=num1*num2;
				}else if(str.equals("/")){
					rs=num1/num2;
				}else{
					throw new RuntimeException("操作符有误!");
				}
				stack.push(""+rs);		
			}	
		}
		//遍历完成后,栈中剩余的最后一个数值即为最后的计算结果
		return Integer.parseInt(stack.pop());
	}
	
}

效果展示:

中缀表达式转后缀表达式

计算机使用中缀表达式进行计算,需要在计算的过程中考虑符号的优先级,操作繁琐。而计算机使用后缀表达式进行计算的时候,逻辑清晰,易于实现。因此计算机在进行逻辑表达式的计算时,需要先将中缀表达式转为后缀表达式。

具体操作步骤:

  • 初始化两个栈:运算符栈s1和储存中间结果的栈s2;
  • 从左至右扫描中缀表达式;
  • 遇到操作数时,将其压s2;
  • 遇到运算符时,比较其与s1栈顶运算符的优先级: (1)如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;(2)如果s1不为空,且当前运算符的优先级比栈顶运算符的优先级高,则将运算符压入s1;(3)如果s1不为空,且当前运算符的优先级比栈顶元素的优先级低或者相等,则将s1栈顶的运算符压入s2中,再次转到当前步骤开始,与s1中新的栈顶运算符相比较。
  • 遇到括号时: (1) 如果是左括号“(”,则直接压入s1;(2) 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
  • 重复步骤2至5,直到表达式的最右边 将s1中剩余的运算符依次弹出并压入s2
  • 依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式

举例说明:

将中缀表达 式“1+((2+3)×4)-5”转 换为后缀表达式的过程如下,因此结果为 "1 2 3 + 4 × + 5 –"

扫描到的元素

s2(栈底->栈顶)

s1 (栈底->栈顶)

说明

1

1

数字,直接入栈

+

1

+

s1为空,运算符直接入栈

(

1

+ (

左括号,直接入栈

(

1

+ ( (

同上

2

1 2

+ ( (

数字

+

1 2

+ ( ( +

s1栈顶为左括号,运算符直接入栈

3

1 2 3

+ ( ( +

数字

)

1 2 3 +

+ (

右括号,弹出运算符直至遇到左括号

×

1 2 3 +

+ ( ×

s1栈顶为左括号,运算符直接入栈

4

1 2 3 + 4

+ ( ×

数字

)

1 2 3 + 4 ×

+

右括号,弹出运算符直至遇到左括号

-

1 2 3 + 4 × +

-

-+优先级相同,因此弹出+,再压入-

5

1 2 3 + 4 × + 5

-

数字

到达最右端

1 2 3 + 4 × + 5 -

s1中剩余的运算符

代码实现:

package com.marden.demo4;

import java.util.ArrayList;
import java.util.Stack;

public class ToReversePoland {
	public static void main(String[] args) {
		String expression="1+((2+3)*4)-5";
		char[] charArray=expression.toCharArray();
		String [] stringArray=new String [charArray.length];
		for(int i=0;i<charArray.length;i++){
			stringArray[i]=""+charArray[i];
		}

		
		Stack<String> stack1=new Stack<String>();
		Stack<String> stack2=new Stack<String>();
		
		for(int i=0;i<stringArray.length;i++){
			//如果当前字符是数字,则直接压入stack2
			if(stringArray[i].matches("\\d")){
				stack2.push(stringArray[i]);
			}
			//如果当前字符是操作符
			else if(stringArray[i].equals("+") || stringArray[i].equals("-") || stringArray[i].equals("*") || stringArray[i].equals("/")){
				while(true){
					//1.如果stack1为空,则直接将当前字符压入stack1
					if(stack1.isEmpty()){
						stack1.push(stringArray[i]);
						break;
					}
					//2.如果stack1不为空
					else{
						//判断stack1的栈顶元素是否为操作符(括号不算操作符)
						//如果stack1的栈顶元素是操作符,则根据操作符的优先级,执行后续操作
						if(isOper(stack1.peek())){
							//若当前字符的优先级比stack1的栈顶元素优先级高,则直接将当前字符压入stack1
							if(priority(stringArray[i])>priority(stack1.peek())){
								stack1.push(stringArray[i]);
								break;
							}else{
								String temp=stack1.pop();
								stack2.push(temp);
								//break;
								continue;
							}
						}
						//如果stack1的栈顶元素是括号,则直接入栈
						else{
							stack1.push(stringArray[i]);
							break;
						}		
					}
				}	
			}
			//如果当前字符为左括号,则直接压入stack1
			else if(stringArray[i].equals("(")){
				stack1.push(stringArray[i]);
			}
			//如果当前字符为右括号,则将stack1中的栈顶弹出,压入stack2中,直到stack1的栈顶元素为左括号。此时将一对括号去掉
			else if(stringArray[i].equals(")")){
				while(!stack1.peek().equals("(")){
					String temp=stack1.pop();
					stack2.push(temp);
				}
				stack1.pop();
				continue;
			}else{
				throw new RuntimeException("表达式有误");
			}
		}
		stack2.push(stack1.pop());
		
		
		String last="";
		//ArrayList<String> list=new ArrayList<String>();
		while(!stack2.isEmpty()){
			//list.add(stack2.pop());
			last+=stack2.pop();
		}
		//System.out.println(last);
		char [] tempChar=last.toCharArray();
		String reservePoland="";
		for(int i=tempChar.length-1;i>=0;i--){
			reservePoland+=tempChar[i];
		}
		System.out.println(reservePoland);
		
	}
	
	public static boolean isOper(String str){
		if(str.equals("+") || str.equals("-") || str.equals("*") || str.equals("/")){
			return true;
		}else{
			return false;
		}
	}
	
	
	//判断运算符的优先级,数值越大,优先级越高
	public static int priority(String str){
		if(str.equals("*") || str.equals("/")){
			return 1;
		}else if(str.equals("+") || str.equals("-")){
			return 0;
		}else{
			return -1;
		}
	}
	

}

注意:

  • break:跳出循环
  • continue:跳出当前循环,执行下次循环

 

 

 

 

 

 

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据结构和算法(4)-----栈 的相关文章

随机推荐

  • pluto实现分析(5)

    本文档的Copyleft归yfydz所有 使用GPL发布 可以自由拷贝 转载 转载时请保持文档的完整性 严禁用于任何商业用途 msn yfydz no1 hotmail com 来源 http yfydz cublog cn 7 内核接口
  • ABAP 发邮件(三)

    转自http blog sina com cn s blog 7c7b16000101bnxk html SAP ABAP 发邮件方法三 OO Report ZSENDEMAIL08 REPORT zsendemail08 CONSTANT
  • R:数据对象及类型

    数据对象 R语言创建和控制的实体被称为对象 object 它们可以说变量 数组 字符串 函数或者其它通过这些实体定义的更一般的结构 structures 在R语言里 对象是通过名字创建和保存的 R对象的名称必须以一个英文字母打头 并由一串大
  • 【Vue】动态监听localStorage或sessionStorage中数据的变化:

    1 需求 一个页面数据变化要改变另一个页面 甚至整个项目的数据变化 2 在main js中 description 监听本地储存的值变化 param number type 1 localStorage 2 sessionStorage p
  • QT在vs2019上配置流程

    一 安装VS2019 2 安装Qt5 15 VS2019只能安装QT5 14版本以上 5 15版本以上需要在在线安装平台下载安装 在QT官网https download qt io 中找到official releases gt onlin
  • Anaconda安装深度学习框架(TensorFlow,Pytorch)教程

    有道云链接 1 用anaconda创建虚拟环境 在这之前 我们需要确定服务器上安装了anaconda 使用下面命令查看 whereis anaconda anaconda data softwares opt anaconda2 bin a
  • 单例模式的几种实现

    单例模式的几种实现 在开发中 我们总是会遇到使用单例模式的情况 今天就来总结一下几种实现单例模式的方法 1 饿汉式 public class SingletonDemo1 类初始化时 立即加载该对象 没有延时加载的优势 由于加载类时 天然的
  • VIM查看使用的配置文件

    最近在配置NeoVim 配置文件怎么放都不对 最后只能想办法找它用的哪一个配置文件 可以使用stdpath把它的配置文件路径回显一下 echo stdpath config 如果不清楚stdpath怎么使用 可以直接调一下help stdp
  • 华为OD机试真题- 取出尽量少的球【2023Q2】【JAVA、Python、C++】

    题目描述 某部门开展Family Day开放日活动 其中有个从桶里取球的游戏 游戏规则如下 有N个容量一样的小桶等距排开 且每个小桶都默认装了数量不等的小球 每个小桶所装的小球数量记录在数组bucketBallNums中 游戏开始时 要求所
  • 使用Hibernate连接MySQL数据库,MySQL连接超时断开的问题

    最近让人头疼的一个问题 就是服务器在不确定的时点会出现关于数据库连接的Exception 大致的Exception如下 org hibernate util JDBCExceptionReporter SQL Error 0 SQLStat
  • texstudio配置编译路径

    texstudio必须配置好编译路径 否则无法编译运行 选项 设置 命令 pdflatex 点击打印符号 找到pdflatex exe打开即可 Xelatex操作步骤相同
  • tomcat替换class文件后重启不生效问题记录

    清空Tomcat work catalina 里面的内容 清空Tomcat temp里面的内容 将Tomcat class文件中 引用 被修改的class 的那几个方法的class 都替换一下 正确操作 但是依然不生效 发现了问题但是不知道
  • 编码:KR字符串匹配,一个简单到领导都看得懂的算法

    常怀感恩 生活或许就不会处处深渊 这几天看了 柔性字符串匹配 觉得很有意思 书是好书 只是这个脑子是不是猪脑就不知道了 于是秉着知之为知之 不知为不知的精神 我准备再次去请教一下我的领导 在一个月黑风高的夜晚 我给领导发了个消息 领导这么回
  • 2023自动化测试需知的4项测试工具!

    一般来说学自动化会建议大家先学selenium 因为最早的时候 自动化就代表selenium 进入测试行业就开始做接口测试 而且现在基本每个公司都需要接口测试 今天就和大家聊一下接口测试的工具 一 Robot Framework 机器人框架
  • Ubuntu添加和设置默认中文字体

    参考 https blog csdn net gengyuchao article details 101215243 首先 通过命令 fc list lang zh 可以查看已安装的中文字体 默认为Ubuntu系统自带的中文字体 安装新字
  • x的n次幂

    题目描述 实现 pow x n 即计算 x 的 n 次幂函数 样例 输入 2 00000 10 输出 1024 00000 说明 100 0 lt x lt 100 0 n 是 32 位有符号整数 其数值范围是 2147483648 214
  • NexT 主题自定义侧边栏图标

    NexT 主题的图标基本上都是由 Font Awesome 提供 但是知乎 CSDN bilibili等大多数国内应用软件的图标在Font Awesome都不支持 为了支持侧边栏各种应用小图标的显示 可以利用嵌入svg格式的图标进行实现 本
  • keil5编译器出现Undefined symbol time (referred from xxx.o).

    我前不久再弄基于stm32控制智能小车电机时 经常出现 error Undefined symbol time referred from xxx o 很烦人 后来我发现了解决办法 在这里我要分享给大家 方法 直接在xxx c文件中给tim
  • Nim游戏详解

    文章目录 废话 正题 证明 举个栗子 拓展题 废话 这是一个过于经典且过于常见的博弈论模型 入门博弈论的话 首先肯定是要知道这个的 正题 N i m Nim Nim 游戏的规则 有 n
  • 数据结构和算法(4)-----栈

    一 栈的一个实际需求 例如 请输入一个表达式计算式 7 2 2 5 1 5 3 3 点击计算 如下图 请问 计算机底层是如何运算得到结果的 注意不是简单的把算式列出运算 因为我们看这个算式 7 2 2 5 但是计算机怎么理解这个算式的 对计