日撸Java三百行(day26:栈实现二叉树深度遍历之前后序遍历)

news2024/9/23 21:30:19

目录

一、栈实现前序遍历

二、栈实现后序遍历

三、完整的程序代码

总结


一、栈实现前序遍历

先来看看我们之前写的用递归实现前序遍历的程序代码:

    /**
	 *********************
	 * Pre-order visit.
	 *********************
	 */
	public void preOrderVisit() {
		System.out.print("" + value + " ");
		
		if(leftChild != null) {
			leftChild.preOrderVisit();
		} // Of if
		
		if(rightChild != null) {
			rightChild.preOrderVisit();
		} // Of if
	} // Of preOrderVisit

通过观察分析,我们可以将上述递归函数总结如下:

(1)每次调用函数时都优先输出当前结点的值,然后再来判断它的左子树。

(2)如果当前结点的左子树不空,则把该左子树作为新的当前结点,进入新一层的递归函数;进入新一层的函数后,仍然优先输出当前结点的值,然后再来判断它的左子树。

(3)如果当前结点的左子树为空,下一步紧接着就是判断该结点的右子树。

(4)若该右子树不空,则把该右子树作为新的当前结点,进入新一层的递归函数;进入新一层的函数后,仍然优先输出当前结点的值,然后再来判断它的左子树。若该右子树为空,则结束遍历。

(5)必须将左子树全部判断完之后,再来判断对应的右子树,因此当我们前序遍历一个二叉树时,一定是下层的结点最先完成“根 左 右”,上层的结点必须等下层结点遍历完之后才能完成“根 左 右”。

接下来,我们进行递归与栈迭代的一一对应:

(1)中要求每次调用函数时都优先输出当前结点的值。用栈来实现就是得到当前结点后,立马输出其值。

(2)中要求当左子树不空时,不断的将左子树作为新的当前结点,进入新一层的递归函数,然后输出其值。用栈来实现就是利用tempNode = tempNode.leftChild进行左子树迭代,不断的将左子树变成当前结点(变成当前结点后也就得到了当前结点),然后立马输出其值。

(3)中要求当某结点左子树为空时,立马判断该结点的右子树。这个过程如果要想用栈来实现,最重要的便是想办法得到当前结点的右子树,因为我们之前进行了左子树迭代,不断的将左子树变成了当前结点,也就是说当前结点是在不断改变的,我们最多只能通过tempNode.rightChild得到最新一级的当前结点的右子树,而以往的当前结点的右子树就没办法直接获得了。这个时候,我们就要充分利用栈“先进后出”的特性了,如果我们将每一个当前结点依次入栈(相当于暂时存起来,便于后面右子树的获得),后面判断右子树时再根据需要出栈,这样就可以通过tempNode.rightChild得到每一个当前结点的右子树了。不过需要注意,入栈肯定得放在左子树迭代之前,因为只要进行一次左子树迭代,当前结点就会改变一次,所以我们应该先将当前结点入栈,然后再通过左子树迭代得到新的当前结点。

(4)中要求判断右子树时,若该右子树不空,则把该右子树作为新的当前结点,进入新一层的递归函数,然后输出其值。用栈来实现就是利用tempNode = tempNode.rightChild将右子树变成新的当前结点(变成新的当前结点也就相当于得到了此时的当前结点),然后立马输出其值。

(5)中要求必须等左子树全部判断完之后再判断对应的右子树,这其实也是前序遍历的特性所致。为了满足(3)中的要求,我们之前说将每一个当前结点依次入栈,后面判断右子树时再根据需要出栈,其实这个过程在栈“先进后出”特性的影响下,已经可以满足(5)中的要求了。因为上层结点一定比下层结点先入栈,这就使得上层结点比下层结点后出栈,而要想判断右子树必须先将其根结点出栈,然后通过tempNode.rightChild得到右子树,继而进行右子树判断,所以下层结点先出栈就可以满足下层结点先进行右子树判断,即先完成“根 左 右”;上层结点后出栈就可以满足上层结点后进行右子树判断,即后完成“根 左 右”。

我们将上述栈实现的过程进行一个总结:

  • 第一步,得到当前结点,不空则立马输出
  • 第二步,将该当前结点入栈
  • 第三步,如果该当前结点的左子树不空,则通过tempNode = tempNode.leftChild得到新的当前结点,然后返回第一步
  • 第四步,如果该当前结点的左子树为空,则下一步立马判断该当前结点的右子树,具体来说就是将此时的栈顶元素出栈(因为如果该当前结点的左子树为空时,是直接从第二步跳到第四步,所以此时的栈顶元素就是即将判断的这个右子树的根结点),再通过tempNode = tempNode.rightChild将出栈元素的右子树作为新的当前结点,然后返回第一步

用文字描述果然还是有点复杂来着,下面我们就用代码呈现这个过程,如下:

    /**
	 *********************
	 * Pre-order visit with stack.
	 *********************
	 */
	public void preOrderVisitWithStack() {
		ObjectStack tempStack = new ObjectStack();
		BinaryCharTree tempNode = this;
		while(!tempStack.isEmpty() || tempNode != null) {
			if(tempNode != null) {
				System.out.print("" + tempNode.value + " ");
				tempStack.push(tempNode);
				tempNode = tempNode.leftChild;
			} else {
				tempNode = (BinaryCharTree)tempStack.pop();
				tempNode = tempNode.rightChild;
			} // Of if
		} // Of while
	} // Of preOrderVisitWithStack

可以发现,栈迭代实现前序遍历与中序遍历的区别其实仅在于输出语句的位置不同。

二、栈实现后序遍历

讲栈实现后序遍历之前,我们先来看看前序遍历与后序遍历的互换:

在日撸Java三百行(day21:二叉树的深度遍历的递归实现)中我们说过由于二叉树的结构特性,其遍历顺序其实就可以看作是根结点、左子树、右子树这三者的一个先后访问顺序,根据数学中的排列组合知识,我们可以知道一共应该有6种顺序,

具体包括(1)根 左 右(2)左 根 右(3)左 右 根(4)根 右 左(5)右 根 左(6)右 左 根,不难发现前三种就是我们最常用的前中后序遍历,因为人类总是习惯于“先左后右”,而后三种其实就是将前三种进行了“左右交换”。

在这6种顺序中,如果将前序遍历“根 左 右”的左右子树交换,就可以得到(4)根 右 左,再逆序即可得到“左 右 根”,也就是后序遍历。至此,我们也就完成了从前序遍历到后序遍历的转换。

下面,我们就来用栈实现后序遍历:

  • 第一步,完全拷贝前序遍历的代码,只需要将左右子树交换即可,也就是将前序遍历中所有的tempNode.leftChild改成tempNode.rightChild,所有的tempNode.rightChild改成tempNode.leftChild
  • 第二步,逆序输出。要完成逆序输出,需要我们再创建一个“输出栈”,将原来前序遍历中的输出语句全部改成当前结点入栈“输出栈”(该过程可以使得原来在前序遍历中最先输出的元素,会最先进入输出栈,也就位于输出栈的栈底,后续出栈时就会最后才输出),然后再将该“输出栈”中的元素依次输出即可完成逆序输出,也就完成了后序遍历

具体的代码如下:

    /**
	 *********************
	 * Post-order visit with stack.
	 *********************
	 */
	public void postOrderVisitWithStack() {
		ObjectStack tempStack = new ObjectStack();
		BinaryCharTree tempNode = this;
		ObjectStack tempOutputStack = new ObjectStack();
		
		while (!tempStack.isEmpty() || tempNode != null) {
			if (tempNode != null) {
				//Store for output.
				tempOutputStack.push(new Character(tempNode.value));
				tempStack.push(tempNode);
				tempNode = tempNode.rightChild;
			} else {
				tempNode = (BinaryCharTree) tempStack.pop();
				tempNode = tempNode.leftChild;
			} // Of if
		} // Of while
		
		//Now reverse output.
		while (!tempOutputStack.isEmpty()) {
			System.out.print("" + tempOutputStack.pop() + " ");
		}//Of while
	}// Of postOrderVisitWithStack

三、完整的程序代码

完整的程序代码:

package datastructure.tree;

import datastructure.*;
import java.util.Arrays;
/**
 * Binary tree with char type elements.
 *
 *@auther Xin Lin 3101540094@qq.com.
 */

public class BinaryCharTree {

	/**
	 * The value
	 */
	char value;
	
	/**
	 * The left child
	 */
	BinaryCharTree leftChild;
	
	/**
	 * The right child
	 */
	BinaryCharTree rightChild;
	
	/**
	 *********************
	 * The first constructor.
	 * 
	 * @param paraName The value.
	 *********************
	 */
	public BinaryCharTree(char paraName) {
		value = paraName;
		leftChild = null;
		rightChild = null;
	} // Of constructor
	
	/**
	 *********************
	 * Manually construct a tree. Only for testing.
	 *********************
	 */
	public static BinaryCharTree manualConstructTree() {
		// Step 1. Construct a tree with only one node.
		BinaryCharTree resultTree = new BinaryCharTree('a');
		
		// Step 2. Construct all Nodes. The first node is the root.
		// BinaryCharTree tempTreeA = resultTree.root;
		BinaryCharTree tempTreeB = new BinaryCharTree('b');
		BinaryCharTree tempTreeC = new BinaryCharTree('c');
		BinaryCharTree tempTreeD = new BinaryCharTree('d');
		BinaryCharTree tempTreeE = new BinaryCharTree('e');
		BinaryCharTree tempTreeF = new BinaryCharTree('f');
		BinaryCharTree tempTreeG = new BinaryCharTree('g');
		
		// Step 3. Link all Nodes.
		resultTree.leftChild = tempTreeB;
		resultTree.rightChild = tempTreeC;
		tempTreeB.rightChild = tempTreeD;
		tempTreeC.leftChild = tempTreeE;
		tempTreeD.leftChild = tempTreeF;
		tempTreeD.rightChild = tempTreeG;
		
		return resultTree;
	} // Of manualConstructTree
	
	/**
	 *********************
	 * Pre-order visit.
	 *********************
	 */
	public void preOrderVisit() {
		System.out.print("" + value + " ");
		
		if(leftChild != null) {
			leftChild.preOrderVisit();
		} // Of if
		
		if(rightChild != null) {
			rightChild.preOrderVisit();
		} // Of if
	} // Of preOrderVisit
	
	/**
	 *********************
	 * In-order visit.
	 *********************
	 */
	public void inOrderVisit() {
		if(leftChild != null) {
			leftChild.inOrderVisit();
		} // Of if
		
		System.out.print("" + value + " ");
		
		if(rightChild != null) {
			rightChild.inOrderVisit();
		} // Of if
	} // Of inOrderVisit
	
	/**
	 *********************
	 * Post-order visit.
	 *********************
	 */
	public void postOrderVisit() {
		if(leftChild != null) {
			leftChild.postOrderVisit();
		} // Of if
		
		if(rightChild != null) {
			rightChild.postOrderVisit();
		} // Of if
		
		System.out.print("" + value + " ");
	} // Of postOrderVisit
	
	/**
	 *********************
	 * Get the depth of the binary char tree.
	 * 
	 * @return The depth.
	 *********************
	 */
	public int getDepth() {
		if((leftChild == null) && (rightChild == null)) {
			return 1;
		} // Of if
		
		// The depth of the left child.
		int tempLeftDepth = 0;
		if(leftChild != null) {
			tempLeftDepth = leftChild.getDepth();
		} // Of if
		
		// The depth of the right child.
		int tempRightDepth = 0;
		if(rightChild != null) {
			tempRightDepth = rightChild.getDepth();
		} // Of if
		
		if(tempLeftDepth >= tempRightDepth) {
			return tempLeftDepth + 1;
		} else {
			return tempRightDepth + 1;
		} // Of if
	} // Of getDepth
	
	/**
	 *********************
	 * Get the number of nodes of the binary char tree.
	 * 
	 * @return The number of nodes.
	 *********************
	 */
	public int getNumNodes() {
		if((leftChild == null) && (rightChild == null)) {
			return 1;
		} // Of if
		
		// The number of nodes of the left child.
		int tempLeftNodes = 0;
		if(leftChild != null) {
			tempLeftNodes = leftChild.getNumNodes();
		} // Of if
		
		// The number of nodes of the right child.
		int tempRightNodes = 0;
		if(rightChild != null) {
			tempRightNodes = rightChild.getNumNodes();
		} // Of if
		
		// The total number of nodes.
		return tempLeftNodes + tempRightNodes + 1;
	} // Of getNumNodes
	
	/**
	 * The values of nodes according to breadth first traversal.
	 */
	char[] valuesArray;

	/**
	 * The indices in the complete binary tree.
	 */
	int[] indicesArray;

	/**
	 ********************
	 * Convert the tree to data arrays, including a char array and an int array.
	 * The results are stored in two member variables.
	 * 
	 * @see #valuesArray
	 * @see #indicesArray
	 *********************
	 */
	public void toDataArrays() {
		//Initialize arrays.
		int tempLength = getNumNodes();

		valuesArray = new char[tempLength];
		indicesArray = new int[tempLength];
		int i = 0;

		//Traverse and convert at the same time.
		CircleObjectQueue tempQueue = new CircleObjectQueue();
		tempQueue.enqueue(this);
		CircleIntQueue tempIntQueue = new CircleIntQueue();
		tempIntQueue.enqueue(0);

		BinaryCharTree tempTree = (BinaryCharTree) tempQueue.dequeue();
		int tempIndex = tempIntQueue.dequeue();
		while (tempTree != null) {
			valuesArray[i] = tempTree.value;
			indicesArray[i] = tempIndex;
			i++;

			if (tempTree.leftChild != null) {
				tempQueue.enqueue(tempTree.leftChild);
				tempIntQueue.enqueue(tempIndex * 2 + 1);
			} // Of if

			if (tempTree.rightChild != null) {
				tempQueue.enqueue(tempTree.rightChild);
				tempIntQueue.enqueue(tempIndex * 2 + 2);
			} // Of i
			tempTree = (BinaryCharTree) tempQueue.dequeue();
			tempIndex = tempIntQueue.dequeue();
		} // Of while
	} // Of toDataArrays
	
	/**
	 ********************
	 * Convert the tree to data arrays, including a char array and an int array.
	 * The results are stored in two member variables.
	 * 
	 * @see #valuesArray
	 * @see #indicesArray
	 *********************
	 */
	public void toDataArraysObjectQueue() {
		//Initialize arrays.
		int tempLength = getNumNodes();

		valuesArray = new char[tempLength];
		indicesArray = new int[tempLength];
		int i = 0;

		//Traverse and convert at the same time.
		CircleObjectQueue tempQueue = new CircleObjectQueue();
		tempQueue.enqueue(this);
		CircleObjectQueue tempIntQueue = new CircleObjectQueue();
		Integer tempIndexInteger = Integer.valueOf(0);
		tempIntQueue.enqueue(tempIndexInteger);
		
		BinaryCharTree tempTree = (BinaryCharTree) tempQueue.dequeue();
		int tempIndex = ((Integer)tempIntQueue.dequeue()).intValue();
		System.out.println("tempIndex = " + tempIndex);
		while (tempTree != null) {
			valuesArray[i] = tempTree.value;
			indicesArray[i] = tempIndex;
			i++;
			
			if (tempTree.leftChild != null) {
				tempQueue.enqueue(tempTree.leftChild);
				tempIntQueue.enqueue(Integer.valueOf(tempIndex * 2 + 1));
			} // Of if
			if (tempTree.leftChild != null) {
				tempQueue.enqueue(tempTree.leftChild);
				tempIntQueue.enqueue(Integer.valueOf(tempIndex * 2 + 2));
			} // Of if
			
			tempTree = (BinaryCharTree) tempQueue.dequeue();
			if (tempTree == null) {
			     break;
			} // Of if
			
			tempIndex = ((Integer)tempIntQueue.dequeue()).intValue();
		} // Of while
	} // Of toDataArraysObjectQueue

	/**
	 *********************
	 * The second constructor. The parameters must be correct since no validity
	 * check is undertaken.
	 * 
	 * @param paraDataArray    The array for data.
	 * @param paraIndicesArray The array for indices.
	 *********************
	 */
	public BinaryCharTree(char[] paraDataArray, int[] paraIndicesArray) {
		// Step 1. Use a sequential list to store all nodes.
		int tempNumNodes = paraDataArray.length;
		BinaryCharTree[] tempAllNodes = new BinaryCharTree[tempNumNodes];
		for(int i = 0; i < tempNumNodes; i++) {
			tempAllNodes[i] = new BinaryCharTree(paraDataArray[i]);
		} // Of for i
		
		// Step 2. Link all nodes.
		for(int i = 1; i < tempNumNodes; i++) {
			for(int j = 0; j < i; j++) {
				System.out.println("Indices " + paraIndicesArray[j] + " vs. " + paraIndicesArray[i]);
				if(paraIndicesArray[i] == paraIndicesArray[j] * 2 + 1) {
					tempAllNodes[j].leftChild = tempAllNodes[i];
					System.out.println("Linking " + j + " with " + i);
					break;
				} // Of if
				if(paraIndicesArray[i] == paraIndicesArray[j] * 2 + 2) {
					tempAllNodes[j].rightChild = tempAllNodes[i];
					System.out.println("Linking " + j + " with " + i);
					break;
				} // Of if
			} // Of for j
		} // Of for i
		
		// Step 3. The root is the first node.
		value = tempAllNodes[0].value;
		leftChild = tempAllNodes[0].leftChild;
		rightChild = tempAllNodes[0].rightChild;
	} // Of the the second constructor
	
	/**
	 *********************
	 * In-order visit with stack.
	 *********************
	 */
	public void inOrderVisitWithStack() {
		ObjectStack tempStack = new ObjectStack();
		BinaryCharTree tempNode = this;
		while(!tempStack.isEmpty() || tempNode != null) {
			if(tempNode != null) {
				tempStack.push(tempNode);
				tempNode = tempNode.leftChild;
			} else {
				tempNode = (BinaryCharTree)tempStack.pop();
				System.out.print("" + tempNode.value + " ");
				tempNode = tempNode.rightChild;
			} // Of if
		} // Of while
	} // Of inOrderVisitWithStack
	
	/**
	 *********************
	 * Pre-order visit with stack.
	 *********************
	 */
	public void preOrderVisitWithStack() {
		ObjectStack tempStack = new ObjectStack();
		BinaryCharTree tempNode = this;
		while(!tempStack.isEmpty() || tempNode != null) {
			if(tempNode != null) {
				System.out.print("" + tempNode.value + " ");
				tempStack.push(tempNode);
				tempNode = tempNode.leftChild;
			} else {
				tempNode = (BinaryCharTree)tempStack.pop();
				tempNode = tempNode.rightChild;
			} // Of if
		} // Of while
	} // Of preOrderVisitWithStack
	
	/**
	 *********************
	 * Post-order visit with stack.
	 *********************
	 */
	public void postOrderVisitWithStack() {
		ObjectStack tempStack = new ObjectStack();
		BinaryCharTree tempNode = this;
		ObjectStack tempOutputStack = new ObjectStack();
		
		while (!tempStack.isEmpty() || tempNode != null) {
			if (tempNode != null) {
				//Store for output.
				tempOutputStack.push(new Character(tempNode.value));
				tempStack.push(tempNode);
				tempNode = tempNode.rightChild;
			} else {
				tempNode = (BinaryCharTree) tempStack.pop();
				tempNode = tempNode.leftChild;
			} // Of if
		} // Of while
		
		//Now reverse output.
		while (!tempOutputStack.isEmpty()) {
			System.out.print("" + tempOutputStack.pop() + " ");
		}//Of while
	}// Of postOrderVisitWithStack

	/**
	 *********************
	 * The entrance of the program.
	 * 
	 * @param args Not used now.
	 *********************
	 */
	public static void main(String args[]) {
		BinaryCharTree tempTree = manualConstructTree();
		System.out.println("\r\nPreorder visit:");
		tempTree.preOrderVisit();
		System.out.println("\r\nIn-order visit:");
		tempTree.inOrderVisit();
		System.out.println("\r\nPost-order visit:");
		tempTree.postOrderVisit();

		System.out.println("\r\n\r\nThe depth is: " + tempTree.getDepth());
		System.out.println("The number of nodes is: " + tempTree.getNumNodes());

		tempTree.toDataArrays();
		System.out.println("The values are: " + Arrays.toString(tempTree.valuesArray));
		System.out.println("The indices are: " + Arrays.toString(tempTree.indicesArray));
		
		tempTree.toDataArraysObjectQueue();
		System.out.println("Only object queue.");
		System.out.println("The values are: " + Arrays.toString(tempTree.valuesArray));
		System.out.println("The indices are: " + Arrays.toString(tempTree.indicesArray));
		
		char[] tempCharArray = {'A', 'B', 'C', 'D', 'E', 'F'};
		int[] tempIndices = {0, 1, 2, 4, 5, 12};
		BinaryCharTree tempTree2 = new BinaryCharTree(tempCharArray, tempIndices);
		
		System.out.println("\r\nPreorder visit:");
		tempTree2.preOrderVisit();
		System.out.println("\r\nIn-order visit:");
		tempTree2.inOrderVisit();
		System.out.println("\r\nPost-order visit:");
		tempTree2.postOrderVisit();
		
		System.out.println("\r\nIn-order visit with stack:");
		tempTree2.inOrderVisitWithStack();
		System.out.println("\r\nPre-order visit with stack:");
		tempTree2.preOrderVisitWithStack();
		System.out.println("\r\nPost-order visit with stack:");
		tempTree2.postOrderVisitWithStack();

	}// Of main	
} // Of class BinaryCharTree

运行结果:

显然,我们今天用栈迭代实现的前序遍历、后序遍历,与之前使用递归实现的前序遍历、后序遍历,其结果是一样的。

总结

今天的主要内容就是利用栈迭代实现二叉树的前序遍历和后序遍历,其实就是昨日内容的一个延续。由于有了昨天分析准备和相关代码的基础,今天进行起来就没有那么困难了,夸张一点说,经过这两天栈实现二叉树遍历的运用,我感觉我的迭代思维得到了升华…

除了递归与迭代的转换,今天我们还介绍了一种非常重要也非常好用的思想——等价替换,即将一个复杂又难以解决的问题,替换为一个等价且比较容易解决的问题。在高中阶段学习数学时,我的数学老师就特别喜欢用等价替换,每次都能把一个巨难的数学题转换成一个简单的基础题;而今天,面对栈实现后序遍历的问题,也是通过等价替换,将复杂的操作转化成了比较简单的过程,对此,我只想说,等价替换真的重要又好用,不过等价替换难就难在如何才能灵活的实现这种等价。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2050567.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Simple RPC - 06 从零开始设计一个服务端(上)_注册中心的实现

文章目录 Pre核心内容服务端结构概述注册中心的实现1. 注册中心的架构2. 面向接口编程的设计3. 注册中心的接口设计4. SPI机制的应用 5. 小结 Pre Simple RPC - 01 框架原理及总体架构初探 Simple RPC - 02 通用高性能序列化和反序列化设计与实现 Simple RPC - 03 借助Netty…

【与C++的邂逅】--- 类和对象(上)

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; 与C的邂逅 本篇博客将讲解C中的类和对象&#xff0c;C是面向对象的语言&#xff0c;面向对象三大特性是封装,继承,多态。学习类和对象&#xff0c;我们可…

Adobe Dimension DN v4.0.2 解锁版下载和安装教程 (专业的三维3D建模工具)

前言 Adobe Dimension&#xff08;简称DN&#xff09;是一款3D设计软件&#xff0c;三维合成和渲染工具&#xff0c;2D平面的二维转为3D立体的三维合成工具&#xff0c;用于3Dmax\C4D\MAYA等三维软件生成的效果图&#xff0c;在3D场景中排列对象、图形和光照。3D应用程序使用的…

Nginx实验

编译安装 Nginx 准备rhel9环境 下载安装包nginx-1.24.0&#xff08;xftp&#xff09;/复制下载链接 &#xff08;nginx.org——>download&#xff09; 解压 [rootnginx nginx-1.24.0]# tar zxf nginx-1.24.0.tar.gz [rootnginx nginx-1.24.0]#tar zxf nginx-1.24.0.tar.…

yolov8安装教程

一、资源下载 1.下载YOLOv8代码 github:YOLOv8-github gitee:YOLOv8-gitee&#xff08;推荐使用国内的gitee&#xff09; 2.conda、cuda 如果没有安装conda&#xff0c;按照流程安装好conda&#xff0c;还要下载好符合自己电脑版本的CUDA 后续会用。 二、创建conda虚拟环…

C语言典型例题43

《C程序设计教程&#xff08;第四版&#xff09;——谭浩强》 习题3.3 有一个函数&#xff1a;y{x,x<1;2x-1,1≤x≤10;3x-11,x≥10。写程序&#xff0c;输入x&#xff0c;输出y。 代码&#xff1a; //《C程序设计教程&#xff08;第四版&#xff09;——谭浩强》 //习题3.3…

OD C卷 - 传递悄悄话

传递悄悄话 &#xff08;100&#xff09; 给定一个二叉树&#xff0c;节点采用顺序存储&#xff0c;如 i0 表示根节点&#xff0c;2i 1 表示左子树根&#xff0c;2i 2 表示右子树根;每个节点站一个人&#xff0c;节点数值表示由父节点到该节点传递消息需要的时间&#xff1b…

周末休整

我写的东西&#xff0c;不爱看的人可以不看&#xff0c;我是给喜欢我的人写的&#xff0c;不喜欢我的人&#xff0c;我也讨厌她。 今天故意写点教人学坏的东西&#xff0c;因为以前写了很多正能量的东西&#xff0c;虽然阅读量还可以&#xff0c;但当见面聊天之后&#xff0c;…

【CSS】CSS新单位vmin和vmax

通过vmin单位可以自动取视口宽度和高度中较小的那个值&#xff0c;vmax同理。 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1…

百度智能云通用文字识别(标准版)- java.lang.NoSuchFieldError: Companion

需求环境 ORC识别图片信息 参考百度示例 百度智能云API文档通用文字识别 官方示例 package baidu.com;import okhttp3.*; import org.json.JSONObject;import java.io.*;/*** 需要添加依赖* <!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->…

8.16-ansible的应用

ansible ansible是基于模块工作的&#xff0c;本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块&#xff0c;ansible只是提供一种框架。 格式 ansible 主机ip|域名|组名|别名 -m ping|copy|... 参数 1.ping模块 m0 # 查看有没有安装epel ​ [rootm0 ~]#…

在vue3中配置scss

要在 Vue 3 中使用 SCSS&#xff08;Sass 的一个子集&#xff09;&#xff0c;你需要安装相应的依赖&#xff0c;并对项目进行一些配置。下面是详细的步骤&#xff1a; 步骤 1: 安装依赖 首先&#xff0c;你需要安装 sass 和 vue-loader&#xff08;如果你使用的是 Vue CLI&a…

vue 2.x + @vue/cli 4.x开发阶段使用Vite

项目用的是vue 2.x vue/cli 4.x(webpack 4.x)。冷启动项目时耗时较长&#xff0c;达到了2分钟以上。热更新时间也达到了10s以上。严重影响了开发体验和效率。 解决问题的过程中遵循2个原则&#xff1a; 不对会影响原构建流程的代码进行改动&#xff0c;向原Webpack构建兼容。…

加密创投周期进化论:未来或黯淡,但流动性是那道光

加密创投领域的风起云涌&#xff0c;而在2022年后&#xff0c;加密市场逐渐进入“行业阵痛期”&#xff0c;面对熊市的寒冬&#xff0c;整个行业的流动性急剧减少&#xff0c;市场的发展被迫寄希望于“板块轮动”的交替炒作。尽管如此&#xff0c;比特币生态和L2生态的兴起&…

树莓派开发笔记03-树莓派的GPIO口输入检测

github主页&#xff1a;https://github.com/snqx-lqh gitee主页&#xff1a;https://gitee.com/snqx-lqh 本项目github地址&#xff1a;https://github.com/snqx-lqh/RaspberryPiLearningNotes 本项目gitee地址&#xff1a;https://gitee.com/snqx-lqh/RaspberryPiLearningNote…

LLAMA 3.1 论文的见解

这有什么大不了的&#xff1f; LLAMA 3.1 的发布标志着 AI 开发的一个重要里程碑。开源模型首次接近领先的闭源模型的性能水平。这一转变预示着未来开源模型同样有效&#xff0c;任何人都可以灵活地修改和调整它们。马克扎克伯格将此与 Linux 的开源性质进行了比较&#xff0c;…

Mysql原理与调优-如何进行sql优化

1.绪论 本文主要讲解我们如何优化一个sql。优化的过程主要分为3个步骤&#xff0c;找到哪些sql需要被优化&#xff0c;这就需要用到慢sql日志。然后发现慢SQL为什么慢&#xff0c;即当前sql是如何执行的&#xff0c;这就需要用到执行计划。最后才是对sql进行优化&#xff0c;对…

作业帮 TiDB 7.5.x 使用经验

作者&#xff1a; 是我的海 原文来源&#xff1a; https://tidb.net/blog/5f9784d3 近期在使用 TiDB 时遇到的一些小问题的梳理总结&#xff0c;大部分版本都在6.5.6和7.5.2 1、limit 导致的扫描量过大的优化 研发定时任务每天需要扫描大量数据&#xff0c;到时机器网卡被…

26.10 Django Ajax异步提交

1. 表单提交 1.1 表单的作用 表单是Web开发中常见的数据收集方式, 它允许用户通过表单输入数据, 并通过提交操作将这些数据发送到服务器进行处理.表单提交方式主要分为两大类: 传统的同步提交(也称为标准提交)和异步提交(主要通过Ajax实现). 它们在工作方式, 用户体验和数据传…

语音助手Verbi:科技创新的未来

今天&#xff0c;我要向大家介绍一个名为Verbi的语音助手项目。这是一个结合了多种先进技术的模块化语音助手应用程序&#xff0c;能够实现语音到文本、文本生成和文本到语音的全流程处理。通过这个项目&#xff0c;我们可以体验到尖端科技如何改变我们的日常生活。 Verbi的诞…