数据结构篇4—递归实现二叉树基础结构

news2024/9/24 5:32:36

在这里插入图片描述

文章目录

  • 前言🚩
    • 1、树?
    • 2、树的相关概念
    • 3、树的结构表示
    • 4、二叉树
      • 🚀、概念和结构
      • 🎁、特殊二叉树
    • 5、二叉树常用性质
    • 6、二叉树的存储结构
      • 🧩、顺序存储结构
      • 🎨、链式存储结构
    • 7、二叉树顺序结构的实现----堆
    • 8、二叉树链式存储实现
    • 9、部分代码递归解析
    • 10、二叉树四种遍历

前言🚩

此次来了解的是不同于顺序表和链表的结构,顺序表和链表都是线性结构,而此次二叉树则是非线性结构的,从结构上来看相较于之前的要为复杂一些,接下来会讲到什么是二叉树?二叉树的相关性质和相关概念?代码结构实现?……

1、树?

树:一种非线性结构,由n个有限节点组成的具有一定层次关系的集合。从逻辑图上看类似一个倒过来的树。
这是网上一搜就可以看到的标准二叉树的结构。和下面逻辑结构相比较类似。
在这里插入图片描述
在这里插入图片描述
树的结构特点:
①在树形结构中,任何子树之间是不想交的;
②每颗子树的根节点只有一个前驱,可以有0个或者多个后继节点。
③一颗N个节点的树,有N-1条边。

2、树的相关概念

概念名称具体含义
节点的度就是一个节点所含子树的个数
叶子节点/终端节点度为0的节点(无后继的节点)
双亲节点若一个节点含有子节点,那么该节点就是父节点
孩子节点/子节点一个节点含有的子树的根节点(父节点下面的节点)
兄弟节点具有相同父节点的节点
树的度一棵树中,有最大的节点的度称为树的度、
树的深度/高度就是该树有多少层
节点的祖先从根节点到所经过分支上的所有节点
子孙以某节点为根的子树中的任意节点,若是根节点,那么根节点之下的都是子孙
森林有n(n>1)棵互不相交的树的集合(多颗不相交的树)

3、树的结构表示

表示方法:孩子兄弟表示法
结构如图:

在这里插入图片描述

代码结构:

typedef int DataType;
struct Node
{
 struct Node* _firstChild1; // 第一个孩子结点
 struct Node* _pNextBrother; // 指向其下一个兄弟结点
 DataType _data; // 结点中的数据域
};

4、二叉树

上面讲解的是树的结构,作为一种存储结构,在数据结构中的通常是写的是二叉树。

🚀、概念和结构

概念:是一棵拥有有限节点的集合;
结构特点:
①可以为空的树。
②具有一个根节点加上左子树和右子树两棵树组成;
③二叉树不存在度大于2的节点
④二叉树有左右两个孩子节点,具有一定顺序,次序不能颠倒,因此是有序树
在这里插入图片描述
以下都可以叫二叉树:
在这里插入图片描述

🎁、特殊二叉树

  1. 满二叉树

概念:在一棵二叉树中,只要该二叉树每一层的节点数量都达到最大值,则就是满二叉树。
结构图如下:
在这里插入图片描述

  1. 完全二叉树

概念:在一棵二叉树中,其最后一层的节点是从左到右是连续存在的,并且最后一层以上的都是最大节点数量,那么该树就是完全二叉树。

满二叉树是特殊的完全二叉树
在这里插入图片描述
满二叉树一定是完全二叉树,但完全二叉树不一定是满二叉树;

5、二叉树常用性质

  1. 在一棵二叉树中,以根节点为第一层为基准,则一棵非空二叉树的第i层上最大节点数为2(i-1)个节点。
  2. 在一棵二叉树中,若规定根节点的层数为第一层,则深度为h的二叉树的最大节点数为2h-1个节点。(总结点数)
  3. 对任何一颗二叉树,若度为0(为叶子节点的)个数为N0,度为2的节点数量为N2,则.有N0=N2+1公式成立。
  4. 若规定根节点的层数为1,具有n个结点的满二叉树的深度为h=Log2 (n+1);(以2为底的,对数为(n+1))
  1. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的结点有:

1. 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
2. 若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子
3. 若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子
该性质可用于堆结构中的建堆时,向上调整算法和向下调整算法;

相关例子:
这里是引用
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6、二叉树的存储结构

二叉树一般可以使用两种结构存储,一种顺序结构,一种链式结构

🧩、顺序存储结构

顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。而现实中使用中只有堆才会使用数组来存储。

在这里插入图片描述

🎨、链式存储结构

1、二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。
2、在链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。
3、结构如下:

在这里插入图片描述

7、二叉树顺序结构的实现----堆

  1. 利用堆(一种二叉树)实现。普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。
  2. 说到堆,就得说一下概念:如果有一个关键码的集合K = { , , ,…, },把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足: <= 且 <= ( >= 且 >= ) i = 0,1,2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。简单说就是任意一个父节点都大于子节点的是大堆,反之为小堆,但是左右子节点无大小关系的

在这里插入图片描述
在这里插入图片描述

此处就整体实现(大/小)堆的创建,代码如下:
1、Heap_Structure.h文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

//堆结构体
typedef int HPDataType;
typedef struct  Heap
{
	HPDataType* _a;
	int _size;
	int _capacity;
}Heap;

// 堆的构建
void HeapCreate(Heap* hp);
// 堆的销毁
void HeapDestory(Heap* hp);
// 堆的插入
void HeapPush(Heap* hp, HPDataType x);
void HeapPrint(Heap hp);
// 堆的删除
void HeapPop(Heap* hp);
// 取堆顶的数据
HPDataType HeapTop(Heap* hp);
// 堆的数据个数
int HeapSize(Heap* hp);
// 堆的判空
int HeapEmpty(Heap* hp);

2、Heap_Structure.c文件

#define _CRT_SECURE_NO_WARNINGS 1
#include "Heap_Structure.h"



void HeapCreate(Heap* hp)
{
	assert(hp);
	hp->_a = NULL;
	hp->_capacity = 0;
	hp->_size = 0;
}

void HeapPrint(Heap hp)
{
	for (int i = 0; i < hp._size; i++)
	{
		printf("%d ",hp._a[i]);
	}
	printf("\n");
}


void Swap(HPDataType* x, HPDataType* y)
{
	HPDataType tmp = *x;
	*x = *y;
	*y = tmp;
}


void HeapDestory(Heap* hp)
{
	assert(hp);
	free(hp->_a);
	hp->_a = NULL;
	hp->_capacity = 0;
	hp->_size = 0;
}

void AdjustUp(HPDataType* a, int child)
{
	//向上调整是从最后个叶子结点开始调整,和父节点比较,谁小谁当爹
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		//if (a[child] < a[parent])//小堆
		if (a[child] > a[parent])//大堆
		{
			//交换
			Swap(&a[child],&a[parent]);
			//更新孩子和父节点
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}


void HeapPush(Heap* hp, HPDataType x)
{
	assert(hp);
	//检测空间
	if (hp->_capacity == hp->_size)
	{
		int new_cpacity = hp->_capacity == 0 ? 4 : 2 * hp->_capacity;
		HPDataType* tmp = (HPDataType*)realloc(hp->_a,sizeof(HPDataType)*new_cpacity);
		if (tmp == NULL)
		{
			perror("malloc fail!");
			return;
		}
		hp->_a = tmp;
		hp->_capacity = new_cpacity;
	}
	hp->_a[hp->_size++] = x;

	AdjustUp(hp->_a,hp->_size-1);
}


void AdjustDown(HPDataType* a, int size, int parent)
{
	//比较和孩子的大小,谁小谁当爹,但是不知道哪个孩子小些,用假设法
	//假设左孩子小
	int child = 2 * parent + 1;
	while (child < size)
	{
		//if (child+1<size&&a[child] >a[child + 1])//小堆
		if (child + 1 < size && a[child] < a[child + 1])//大堆

		{
			++child;
		}
		//判断
		//if (a[child] < a[parent])//小堆
		if(a[child]>a[parent])
		{
			Swap(&a[child], &a[parent]);
			//更新
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}
	}
}


void HeapPop(Heap* hp)
{
	//保证堆里有数据
	assert(hp&&hp->_size>0);
	//交换数据
	Swap(&hp->_a[0],&hp->_a[hp->_size-1]);
	//直接大小减去1
	hp->_size--;
	//向下调整
	AdjustDown(hp->_a,hp->_size,0);
}

HPDataType HeapTop(Heap* hp)
{
	assert(hp&&hp->_size>0);
	return hp->_a[0];
}

int HeapSize(Heap* hp)
{
	assert(hp);
	return hp->_size;
}

int HeapEmpty(Heap* hp)
{
	assert(hp);
	return hp->_size==0;
}

3、Test.c测试文件

#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap_Structure.h"

int main()
{
	int a[] = { 4,2,8,1,5,6,9,7 };
	Heap hp;
	HeapCreate(&hp);
	for (size_t i = 0; i < sizeof(a) / sizeof(int); i++)
	{
		HeapPush(&hp, a[i]);
	}
	HeapPrint(hp);
	printf("堆顶数据:%d\n",HeapTop(&hp));
	//HeapPop(&hp);
	HeapPrint(hp);
	printf("堆顶数据:%d\n", HeapTop(&hp));
	printf("堆中数据量:%d\n",HeapSize(&hp));
	HeapDestory(&hp);
		
	return 0;
}

在这里插入图片描述
画出图如下:
在这里插入图片描述

8、二叉树链式存储实现

  1. 此棵树手动连接而成:
    在这里插入图片描述
  2. 代码实现如下:
#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<stdlib.h>

typedef int  BTData;
typedef struct BinaryTreeNode
{
	BTData _data;
	struct BinarayTreeNode* _left;
	struct BinarayTreeNode* _right;
}BTNode;

BTNode* BuyBTNode(BTData x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	node->_data = x;
	node->_left = NULL;
	node->_right = NULL;

	return node;
}

BTNode* test_create_binary_tree()
{
	BTNode* node1 = BuyBTNode(1);
	BTNode* node2 = BuyBTNode(2);
	BTNode* node3 = BuyBTNode(3);
	BTNode* node4 = BuyBTNode(4);
	BTNode* node5 = BuyBTNode(5);
	BTNode* node6 = BuyBTNode(6);
	BTNode* node7 = BuyBTNode(7);


	(BTNode*)node1->_left = node2;
	(BTNode*)node1->_right = node4;
	(BTNode*)node2->_left = node3;
	(BTNode*)node4->_left = node5;
	(BTNode*)node4->_right = node6;
	(BTNode*)node3->_left = node7;
	
	//返回二叉树顶端数据节点
	return node1;
}

//前序遍历二叉树
void PrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("%s ", "NULL");
		return;
	}
	printf("%d ",root->_data);
	PrevOrder((BTNode*)root->_left);
	PrevOrder((BTNode*)root->_right);
}

//中序遍历
void InOder(BTNode* root)
{
	if (root == NULL)
	{
		printf("%s ", "NULL");
		return;
	}
	
	InOder((BTNode*)root->_left);
	printf("%d ", root->_data);
	InOder((BTNode*)root->_right);
}

//后序遍历
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("%s ","NULL");
		return;
	}

	PostOrder((BTNode*)root->_left);
	PostOrder((BTNode*)root->_right);
	printf("%d ",root->_data);
}


int BTSize(BTNode* root)
{
	/*if (root == NULL)
	{
		return 0;
	}
	else
	{
		return BTSize((BTNode*)root->_left) + BTSize((BTNode*)root->_right) + 1;
	}*/

	return root==NULL?0:BTSize((BTNode*)root->_left) + BTSize((BTNode*)root->_right) + 1;
}

int BTLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	if ((BTNode*)root->_left == NULL && (BTNode*)root->_right == NULL)
	{
		return 1;
	}
	return BTLeafSize((BTNode*)root->_left) + BTLeafSize((BTNode*)root->_right);
}


int BTHeight(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}

	return  BTHeight((BTNode*)root->_left) > BTHeight((BTNode*)root->_right) ?
		BTHeight((BTNode*)root->_left) + 1 : BTHeight((BTNode*)root->_right) + 1;
}

int main()
{
	BTNode* root=test_create_binary_tree();

	printf("前序遍历:");
	PrevOrder(root);
	printf("\n");
	printf("\n");

	printf("中序遍历:");
	InOder(root);
	printf("\n");
	printf("\n");

	printf("后序遍历:");
	PostOrder(root);
	printf("\n");
	printf("\n");

	printf("二叉树大小:%d\n", BTSize(root));
	printf("叶子节点个数:%d\n", BTLeafSize(root));
	printf("二叉树高度:%d\n", BTHeight(root));
	return 0;
}


在这里插入图片描述

下面通过前序遍历创建二叉树,并实现简单的函数:先看代码

1、Binary_Tree_code.c文件

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include"Queue.h"

typedef char BTDataType;

typedef struct BinaryTreeNode
{
	BTDataType _data;
	struct BinaryTreeNode* _left;
	struct BinaryTreeNode* _right;
}BTNode;

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int* pi);
// 二叉树销毁
void BinaryTreeDestory(BTNode* root);

// 二叉树节点个数
int BinaryTreeSize(BTNode* root);

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);

// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root);

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root);

// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root);

// 层序遍历
void BinaryTreeLevelOrder(BTNode* root);

// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root);


int main()
{
	// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
	char array[] = {'A','B','D','#','#','E','#','H','#','#','C','F','#','#','G','#','#','\0'};
	//scanf("%s", array);
	int index = 0;
	//int lenght = sizeof(array) / sizeof(array[0]);
	BTNode* root=BinaryTreeCreate(array, &index);
	printf("前序遍历创建二叉树:");
	BinaryTreePrevOrder(root);
	printf("\n中序遍历二叉树打印:");
	BinaryTreeInOrder(root);
	printf("\n后序遍历二叉树打印:");
	BinaryTreePostOrder(root);
	printf("\n二叉树节点个数:%d\n",BinaryTreeSize(root));
	printf("二叉树的叶子节点个数:%d\n", BinaryTreeLeafSize(root));
	int k = 0;
	printf("请输入要查看的层数:");
	scanf("%d", &k);
	printf("二叉树第%d层的节点数为%d\n",k, BinaryTreeLevelKSize(root, k));
	printf("查找字符为E的节点:%p\n", BinaryTreeFind(root, 'E'));
	printf("二叉树层序遍历打印:");
	BinaryTreeLevelOrder(root);
	printf("是否为完全二叉树:%d\n", BinaryTreeComplete(root));
	BinaryTreeDestory(root);
	return 0;
}

BTNode* BinaryTreeCreate(BTDataType* a, int* pi)
{
		//创建空间
		BTNode* root = (BTNode*)malloc(sizeof(BTNode));
		if (root == NULL)
		{
			perror("malloc fail");
			return NULL;
		}
		if (a[*pi] == '#')
		{
			(*pi)++;
			return NULL;
		}
		root->_data = a[*pi];
		(*pi)++;
		root->_left=BinaryTreeCreate(a, pi);
		root->_right=BinaryTreeCreate(a, pi);

		return root;
}

void BinaryTreeDestory(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	BinaryTreeDestory(root->_left);
	BinaryTreeDestory(root->_right);
	free(root);
}

int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	return BinaryTreeSize(root->_left) + BinaryTreeSize(root->_right)+1;
}

int BinaryTreeLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	if (root->_left == NULL && root->_right == NULL)
	{
		return 1;
	}
	return BinaryTreeLeafSize(root->_left) + BinaryTreeLeafSize(root->_right);
}

int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	return BinaryTreeLevelKSize(root->_left,k-1)+BinaryTreeLevelKSize(root->_right, k - 1);
}


// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->_data == x)
	{
		return root;
	}
	BTNode* ret1 = BinaryTreeFind(root->_left, x);
	if (ret1)
		return ret1;

	BTNode* ret2 = BinaryTreeFind(root->_right, x);
	if (ret2)
		return ret2;

	return NULL;
}

void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("%c ", '#');
		return;
	}
	printf("%c ", root->_data);
	BinaryTreePrevOrder(root->_left);
	BinaryTreePrevOrder(root->_right);
}

void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("%c ",'#');
		return;
	}
	BinaryTreeInOrder(root->_left);
	printf("%c ",root->_data);
	BinaryTreeInOrder(root->_right);
}

void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("%c ",'#');
		return;
	}
	BinaryTreePostOrder(root->_left);
	BinaryTreePostOrder(root->_right);
	printf("%c ",root->_data);

}

void BinaryTreeLevelOrder(BTNode* root)
{
	Queue queue;
	QueueInit(&queue);
	if (root!= NULL)
	{
		QueuePush(&queue,root);
	}
	while (!QueueEmpty(&queue))
	{
		BTNode* pcur = QueueFront(&queue);
		QueuePop(&queue);
		/*if (pcur == NULL)
		{
			printf("%c",'#');
			return;
		}*/
		printf("%c ", pcur->_data);

		if (pcur->_left != NULL)
		{
			QueuePush(&queue,pcur->_left);
		}

		if (pcur->_right != NULL)
		{
			QueuePush(&queue, pcur->_right);
		}
	}
	QueueDestroy(&queue);
}

int BinaryTreeComplete(BTNode* root)
{
	Queue queue;
	QueueInit(&queue);
	if (root != NULL)
	{
		QueuePush(&queue, root);
	}
	while (!QueueEmpty(&queue))
	{
		BTNode* pcur = QueueFront(&queue);
		QueuePop(&queue);
		if (pcur == NULL)
		{
			break;
		}
		QueuePush(&queue, pcur->_left);
		QueuePush(&queue, pcur->_right);
	}
	while (!QueueEmpty(&queue))
	{
		BTNode* pcur = QueueFront(&queue);
		QueuePop(&queue);
		if (pcur)
		{
			QueueDestroy(&queue);
			return false;
		}
	}
	QueueDestroy(&queue);
	return true;
}



2、由于层序遍历需要用到队列,下面是队列实现:

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef struct BinaryTreeNode* QDataType;
typedef struct QueueNode
{
	QDataType val;
	struct QueueNode* next;
}QNode;

typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;

void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);

// 队尾插入
void QueuePush(Queue* pq, QDataType x);
// 队头删除
void QueuePop(Queue* pq);

// 取队头和队尾的数据
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
//
int QueueSize(Queue* pq);
bool QueueEmpty(Queue* pq);
#include "Queue.h"

#define _CRT_SECURE_NO_WARNINGS 1

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

void QueueDestroy(Queue* pq)
{
	assert(pq);
	QNode* pcur = pq->phead;
	while (pcur != NULL)
	{
		QNode* Next = pcur->next;
		free(pcur);
		pcur = Next;
	}
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

void QueuePush(Queue* pq, QDataType x)
{
	QNode* node = (QNode*)malloc(sizeof(QNode));
	if (node == NULL)
	{
		perror("malloc fail");
		return;
	}
	node->next = NULL;
	node->val = x;

	//判断尾指针是否为空
	if (pq->ptail == NULL)
	{
		pq->phead = pq->ptail = node;
	}
	else
	{
		pq->ptail->next = node;
		pq->ptail = node;
	}
	pq->size++;
}

void QueuePop(Queue* pq)
{
	assert(pq);
	if (pq->size == 0)
	{
		printf("队列数据为空,无法删除");
		return;
	}
	队头删除数据
	//QNode* Next = pq->phead->next;
	//free(pq->phead);
	//pq->phead = Next;
	//pq->size--;

	//但是得分情况①只有一个节点的时候
	if (pq->phead->next == NULL)
	{
		free(pq->phead);
		pq->phead = NULL;
		pq->ptail = NULL;
	}
	else
	{
		QNode* Next = pq->phead->next;
		free(pq->phead);
		pq->phead = Next;
	}
	pq->size--;
}

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	if (pq->size == 0)
	{
		printf("数据为空!");
	}
	return pq->phead->val;
}

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->ptail);
	return pq->ptail->val;
}

int QueueSize(Queue* pq)
{
	assert(pq);
	assert(pq->size);
	return pq->size;
}

bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->size==0;
}

结果如下:
在这里插入图片描述

9、部分代码递归解析

在这里插入图片描述

10、二叉树四种遍历

1、前序遍历:根–左–右
2、中序遍历:左–根–右
3、后序遍历:左–右–根
4、层序遍历:从第一层,一层一层遍历

在这里插入图片描述
在这里插入图片描述

遍历的一些例子:
在这里插入图片描述

在这里插入图片描述

递归实现的二叉树到此为止了,非递归于后再描述,谢谢!🚗🚗✔

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

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

相关文章

前端开发知识(三)-javascript(对象)

一、JS对象 包括JS已经定义的对象&#xff0c;如&#xff0c;Array,Sting &#xff0c;DOM&#xff0c;BOM等&#xff0c;其中&#xff0c;JSON是用户自定义对象&#xff08;除对象外&#xff0c;还有文本&#xff09;&#xff0c;其他是JS定义 1.Array&#xff1a;数组 数…

React最新版本 18

截至当前时间&#xff08;2024年07月24日&#xff09;&#xff0c;React 的最新版本是 18.2.0。这个版本在 2022 年 3 月 29 日由 React 团队正式发布&#xff0c;主要着眼于解决 React 应用在性能、稳定性、开发体验等方面的问题。 React 18 是 React 的一个重要版本&#xf…

算法导论 总结索引 | 第五部分 第二十章:van Emde Boas树

1、一些支持优先队列操作的 数据结构,如第6章的二叉堆、第13章的红黑树 和 第19章的斐波那契堆。在这几种数据结构中, 不论是最好情况 还是 摊还情况, 至少有一项重要操作 只需要 O(n lgn) 时间 由于这些数据结构 都是基于关键字比较 决定的&#xff0c;因此, 8.1节中的下界 Ω…

【网络流】——初识(最大流)

网络流-最大流 基础信息引入一些概念基本性质 最大流定义 Ford–Fulkerson 增广Edmons−Karp算法Dinic 算法参考文献 基础信息 引入 假定现在有一个无限放水的自来水厂和一个无限收水的小区&#xff0c;他们之间有多条水管和一些节点构成。 每一条水管有三个属性&#xff1a…

sql_exporter通过sql收集业务数据并通过prometheus+grafana展示

下载并解压安装sql_exporter wget https://github.com/free/sql_exporter/releases/download/0.5/sql_exporter-0.5.linux-amd64.tar.gz #解压 tar xvf sql_exporter-0.5.linux-amd64.tar.gz -C /usr/local/修改主配置文件 cd /usr/local/ mv sql_exporter-0.5.linux-amd64 s…

海山数据库(He3DB)技术解析:海山Redis定时任务与持久化管控设计

文章目录 引言一、背景介绍二、具体实现1、多副本容灾功能2、主备切换后任务断点续做功能3、持久化管控编排功能 三、总结作者 引言 云Redis数据库服务是目前广泛应用的模式&#xff0c;其数据持久化方案是现在研究的热点内容&#xff0c;数据持久化操作主要由参数设置自动触发…

AI学习记录 - 激活函数的作用

试验&#xff0c;通过在线性公式加入激活函数&#xff0c;可以拟合复杂的情况&#xff08;使用js实现&#xff09; 结论:1、线性函数的叠加&#xff0c;无论叠加多少次&#xff0c;都是线性的 如下图 示例代码 线性代码&#xff0c;使用ykxb的方式&#xff0c;叠加10个函数…

AnimationCurve动画曲线 简单使用

资料 AnimationCurve AnimationCurve 表示一条曲线。可在曲线上添加关键帧&#xff0c;编辑曲线。 水平轴表示时间&#xff0c;竖直轴表示曲线的高度 获取曲线高度方法&#xff0c;AnimationCurve.Evaluate 示例 循环移动Cube,Cube沿着曲线移动 using UnityEngine; publ…

正则表达式与文本处理

目录 一、正则表达式 1、正则表达式定义 1.1正则表达式的概念及作用 1.2、正则表达式的工具 1.3、正则表达式的组成 2、基础正则表达式 3、扩展正则表达式 4、元字符操作 4.1、查找特定字符 4.2、利用中括号“[]”来查找集合字符 4.3、查找行首“^”与行尾字符“$”…

火山引擎边缘智能平台,让AI走进企业现场

如何让大模型更好地与生产进行融合&#xff0c;让AI生产力为企业降本增效&#xff0c;是每个企业都在关注的问题。但设备异构、隐私安全、传输延迟等困难&#xff0c;让大模型走进企业现场变得步履维艰。这种情况&#xff0c;就需要借助边缘智能来应对这些挑战。 什么是边缘智能…

二维数组前缀和

二维数组前缀和&#xff08;Leetcode304&#xff09; 想法(参考题解)&#xff1a; 如上图&#xff0c;在矩阵中根据给定的方框围成的范围&#xff0c;确定范围内元素之和。题目&#xff1a;二维区域和检索 - 矩阵不可变。思路就是使用前缀和&#xff0c;前缀和表示的是面积&am…

Linux 安装 GDB (无Root 权限)

引入 在Linux系统中&#xff0c;如果你需要在集群或者远程操作没有root权限的机子&#xff0c;安装GDB&#xff08;GNU调试器&#xff09;可能会有些限制&#xff0c;因为通常安装新软件或更新系统文件需要管理员权限。下面我们介绍可以在没有root权限的情况下安装GDB&#xf…

微信小程序获取蓝牙并实现内容打印

通过微信小程序如何实现获取蓝牙打印机并实现打印能力&#xff0c;之前做过一个测试Dome&#xff0c;能够获取附近的蓝牙打印机设备并实现打印,今天开放出来供大家参考。 wxml <!--右下角搜索--> <view class"ly-cass-box"><view class"ly-cas…

【Python第三方库】PyQt5安装与应用

文章目录 引言安装PYQT5基于Pyqt5的简单桌面应用常用的方法与属性QtDesigner工具使用与集成窗口类型QWidget和QMainWindow区别 UI文件加载方式直接加载UI文件的方式显示窗口转化py文件进行显示窗口 PyQt5中常用的操作信号与槽的设置绑定页面跳转 引言 PyQt5是一个流行的Python…

Java——多线程(2/9):线程创建方式三Callable,Thread的常用方法(如何创建、代码实例、API及优缺点)

目录 方式三&#xff1a;实现Callable接口 前言 如何创建 代码实例 API及优缺点 Thread的常用方法 代码演示 方式三&#xff1a;实现Callable接口 前言 前两种线程创建方式都存在的一个问题 假如线程执行完毕后有一些数据需要返回&#xff0c;他们重写的run方法均不能…

算法与算法分析

目录 一.前言 二.算法的特性和要求 三.分析算法--时间效率 四. 分析算法--空间效率 一.前言 算法就是对特定问题求解方法和步骤的一种描述&#xff0c;它是指令的有限序列。其中&#xff0c;每个指令表示一个或多个操作。总而言之&#xff0c;我们数据结构就是通过算法实现操…

如何根据员工的反馈来确定六西格玛培训需求?

在六西格玛的推广与实施过程中&#xff0c;最大的挑战往往不在于技术本身&#xff0c;而在于如何让每一位员工都能理解、接受并积极参与其中。员工是企业最直接的执行者&#xff0c;他们的声音直接反映了项目落地的难易程度及潜在障碍。因此&#xff0c;倾听并有效整合员工反馈…

Python Django功能强大的扩展库之channels使用详解

概要 随着实时 web 应用程序的兴起,传统的同步 web 框架已经无法满足高并发和实时通信的需求。Django Channels 是 Django 的一个扩展,旨在将 Django 从一个同步 HTTP 框架转变为一个支持 WebSockets、HTTP2 和其他协议的异步框架。它不仅能够处理传统的 HTTP 请求,还可以处…

STM32串口(串口基础)

串口整个东西可以说但凡你要碰单片机&#xff0c;想做点上点档次的东西的话那你就包用它的。32的串口配置并不难&#xff0c;哪怕是比起51其实也难不到哪去。 目录 一.通信基础 1.通信方式 2.通信速率 二.串口基础 1.串口的数据帧结构&#xff08;协议&#xff09; 2.ST…

【轨物方案】开关柜在线监测物联网解决方案

随着物联网技术的发展&#xff0c;电力设备状态监测技术也得到了迅速发展。传统的电力成套开关柜设备状态监测方法主要采用人工巡检和定期维护的方式&#xff0c;这种方法不仅效率低下&#xff0c;而且难以保证设备的实时性和安全性。因此&#xff0c;基于物联网技术的成套开关…