数据结构与算法---树

这几个算法可视化网站,太牛了! 很多初学者在学习数据结构与算法的时候,都会觉得很难,很大一部分是因为数据结构与算法本身比较抽象,不好理解。对于这一点,可以通过一些可视化动画来帮助理解。 阅读详情

数据结构可视化网址

构建二叉树

在这里插入图片描述

// C

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

typedef char T;


typedef struct TreeNode {
	T data;
	struct TreeNode* left;
	struct TreeNode* right;
}Node;


int main()
{
	int spaceSize = sizeof(Node);

	Node* a = (Node*)malloc(spaceSize);
	Node* b = (Node*)malloc(spaceSize);
	Node* c = (Node*)malloc(spaceSize);
	Node* d = (Node*)malloc(spaceSize);
	Node* e = (Node*)malloc(spaceSize);

	a->data = 'A';
	b->data = 'B';
	c->data = 'C';
	d->data = 'D';
	e->data = 'E';

	a->left = b;
	a->right = c;
	b->left = d;
	b->right = e;
	c->left = c->right = NULL;
	d->left = d->right = NULL;
	e->left = e->right = NULL;
	
	free(a);
	free(b);
	free(c);
	free(d);
	free(e);

	getchar();
	return 0;
}

遍历二叉树

0.基本概念

二叉树是一种特殊的树形数据结构,其中每个节点最多有两个子节点,通常称为左子节点和右子节点。

当我们遍历二叉树时,可以根据访问节点的顺序得到不同的遍历结果。

有以下四种遍历方式:

  1. 前序遍历
    • 访问根节点
    • 前序遍历左子树
    • 前序遍历右子树
    • 对于给定的二叉树,前序遍历的结果是一个节点序列,这个序列首先列出根节点,然后递归地列出左子树的所有节点,最后递归地列出右子树的所有节点
  2. 中序遍历
    • 中序遍历左子树
    • 访问根节点
    • 中序遍历右子树
    • 在二叉搜索树(BST)中,中序遍历的结果是一个有序的节点序列,因为它首先遍历最小的节点(在BST的左下方),然后遍历根节点,最后遍历最大的节点(在BST的右上方)
  3. 后序遍历
    • 后序遍历左子树
    • 后序遍历右子树
    • 访问根节点
    • 后序遍历的结果是一个节点序列,这个序列首先列出左子树的所有节点,然后列出右子树的所有节点,最后列出根节点
  4. 层序遍历
    • 从根节点开始
    • 访问当前层的所有节点
    • 对下一层的每个节点进行同样的操作
    • 层序遍历通常使用队列来实现,首先将根节点入,然后在循环中,出队一个节点并访问它,然后将它的子节点(如果存在)入队。这个过程一直持续到队列为空

1.前序遍历

在这里插入图片描述

  • 通过递归的方式实现
// C

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

typedef char T;


typedef struct TreeNode {
	T data;
	struct TreeNode* left;
	struct TreeNode* right;
}Node;


// 先序遍历
void preorder(Node* root)	// 参数:二叉树的根节点
{
	if (root == NULL)	return;
	printf("%c", root->data);
	preorder(root->left);
	preorder(root->right);
}


int main()
{
	int spaceSize = sizeof(Node);

	Node* a = (Node*)malloc(spaceSize);
	Node* b = (Node*)malloc(spaceSize);
	Node* c = (Node*)malloc(spaceSize);
	Node* d = (Node*)malloc(spaceSize);
	Node* e = (Node*)malloc(spaceSize);
	Node* f = (Node*)malloc(spaceSize);

	a->data = 'A';
	b->data = 'B';
	c->data = 'C';
	d->data = 'D';
	e->data = 'E';
	f->data = 'F';

	a->left = b;
	a->right = c;
	b->left = d;
	b->right = e;
	c->right = f;
	c->left = d->left = d->right = e->left = e->right = f->left = f->right = NULL;

	preorder(a);

	free(a);
	free(b);
	free(c);
	free(d);
	free(e);


	getchar();
	return 0;
}
  • 通过"循环+栈"的方式实现
// C

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

// 二叉树的节点
typedef char T;
typedef struct TreeNode {
	T data;
	struct TreeNode* left;
	struct TreeNode* right;
}TreeNode;


// 栈的节点
typedef struct StackNode {
	TreeNode* node;
	StackNode* next;
}StackNode;


// 栈的初始化
void initStack(StackNode* head)
{
	head->next = NULL;
}


// 入栈
bool pushStack(StackNode* head, TreeNode* node)
{
	StackNode* p = (StackNode*)malloc(sizeof(StackNode));
	if (p == NULL)	return false;

	p->node = node;
	p->next = head->next;
	head->next = p;

	return true;
}


// 出栈
TreeNode* popStack(StackNode* head)
{
	StackNode* temp = head->next;
	TreeNode* node = head->next->node;

	head->next = head->next->next;
	free(temp);

	return node;
}


// 栈是否为空
bool isEmpty(StackNode* head)
{
	return head->next == NULL;
}


// 先序遍历
void preorder(TreeNode* root)
{
	StackNode stack;		// 创建一个栈
	initStack(&stack);		// 初始化这个栈

	while (root || !isEmpty(&stack))		// 如果栈不为空,也会继续循环下去
	{
		// 先不断遍历左子树,直到没有为止
		while (root)
		{
			printf("%c", root->data);
			pushStack(&stack, root);		// 途中每经过一个节点,就将节点丢进栈中
			root = root->left;
		}

		// 处理右子树
		root = popStack(&stack);
		root = root->right;
	}
}

int main()
{
	int spaceSize = sizeof(TreeNode);

	TreeNode* a = (TreeNode*)malloc(spaceSize);
	TreeNode* b = (TreeNode*)malloc(spaceSize);
	TreeNode* c = (TreeNode*)malloc(spaceSize);
	TreeNode* d = (TreeNode*)malloc(spaceSize);
	TreeNode* e = (TreeNode*)malloc(spaceSize);
	TreeNode* f = (TreeNode*)malloc(spaceSize);

	a->data = 'A';
	b->data = 'B';
	c->data = 'C';
	d->data = 'D';
	e->data = 'E';
	f->data = 'F';

	a->left = b;
	a->right = c;
	b->left = d;
	b->right = e;
	c->right = f;
	c->left = d->left = d->right = e->left = e->right = f->left = f->right = NULL;

	preorder(a);	// 先序遍历

	free(a);
	free(b);
	free(c);
	free(d);
	free(e);


	getchar();
	return 0;
}

2.中序遍历

在这里插入图片描述

  • 通过递归的方式实现
// C

// 中序遍历
void inOrder(TreeNode* root)
{
	if (root == NULL) return;
	inOrder(root->left);		// 先完成全部左子树的遍历
	printf("%c", root->data);   // 等待左子树遍历完成之后再打印
	inOrder(root->right);		// 然后就是对右子树进行遍历
}
  • 通过"循环+栈"的方式实现
// C

// 中序遍历
void inOrder(TreeNode* root)
{
	StackNode stack;		// 创建一个栈
	initStack(&stack);		// 初始化这个栈

	while (root || !isEmpty(&stack))		// 如果栈不为空,也会继续循环下去
	{
		while (root)
		{
			pushStack(&stack, root);
			root = root->left;
		}
		root = popStack(&stack);
		printf("%c", root->data);   // 只需要将打印时机延后到左子树遍历完成
		root = root->right;
	}
}

3.后序遍历

// C

// 后序遍历
void postOrder(Node root){
    if(root == NULL) return;
    postOrder(root->left);
    postOrder(root->right);
    printf("%c", root->data);   // 时机延迟到最后
}

4.层序遍历

// C

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

typedef char E;


// 树的节点
struct TreeNode {
	E element;
	struct TreeNode* left;
	struct TreeNode* right;
	int flag;
};
typedef struct TreeNode* Node;


// 队列的节点
struct QueueNode {
	Node element;
	struct QueueNode* next;
};
typedef struct QueueNode* QNode;


// 队列
struct Queue {
	QNode front, rear;
};


// 初始化
bool initQueue(Queue* queue) {
	QNode node = (QNode)malloc(sizeof(struct QueueNode));
	if (node == NULL)   return false;

	queue->front = queue->rear = node;

	return true;
}


// 入队
bool offerQueue(Queue* queue, Node element) {
	QNode node = (QNode)malloc(sizeof(struct QueueNode));
	if (node == NULL) return false;

	node->element = element;
	queue->rear->next = node;
	queue->rear = node;

	return true;
}


// 出队
Node pollQueue(Queue* queue) {
	Node e = queue->front->next->element;
	QNode node = queue->front->next;

	queue->front->next = queue->front->next->next;
	if (queue->rear == node) queue->rear = queue->front;
	free(node);

	return e;
}


// 判断是否为空
bool isEmpty(Queue* queue) {
	return queue->front == queue->rear;
}


// 层序遍历
void levelOrder(Node root) {
	struct Queue queue;		// 创建一个队列
	initQueue(&queue);		// 初始化这个队列

	offerQueue(&queue, root);		// 先把根节点入队
	while (!isEmpty(&queue))		// 不断重复,直到队列空为止
	{
		Node node = pollQueue(&queue);		// 出队一个元素,打印值
		printf("%c", node->element);
		if (node->left)		// 如果存在左右孩子的话
			offerQueue(&queue, node->left);		// 记得将左右孩子入队,注意顺序,先左后右
		if (node->right)
			offerQueue(&queue, node->right);
	}
}


int main()
{
	int spaceSize = sizeof(TreeNode);

	TreeNode* a = (TreeNode*)malloc(spaceSize);
	TreeNode* b = (TreeNode*)malloc(spaceSize);
	TreeNode* c = (TreeNode*)malloc(spaceSize);
	TreeNode* d = (TreeNode*)malloc(spaceSize);
	TreeNode* e = (TreeNode*)malloc(spaceSize);
	TreeNode* f = (TreeNode*)malloc(spaceSize);

	a->element = 'A';
	b->element = 'B';
	c->element = 'C';
	d->element = 'D';
	e->element = 'E';
	f->element = 'F';

	a->left = b;
	a->right = c;
	b->left = d;
	b->right = e;
	c->right = f;
	c->left = d->left = d->right = e->left = e->right = f->left = f->right = NULL;

	levelOrder(a);	// 层序遍历

	free(a);
	free(b);
	free(c);
	free(d);
	free(e);


	getchar();
	return 0;
}

线索化二叉树

线索化概念

一棵二叉树的某些结点会存在NULL的情况,我们可以利用这些为NULL的指针,将其线索化为某一种顺序遍历的指向下一个按顺序的结点的指针,经过第一次遍历完成了线索化,以后我们再进行遍历的时候,就可以利用线索实现快速遍历。

  • 一棵经过线索化以后的二叉树的前序遍历顺序如下:

在这里插入图片描述

  • 一棵经过线索化以后的二叉树的中序遍历顺序如下:

在这里插入图片描述

  • 一棵经过线索化以后的二叉树的后序遍历顺序如下:

在这里插入图片描述

线索化规则

线索化的规则为:

  • 结点的左指针,指向其当前遍历顺序的前驱结点。
  • 结点的右指针,指向其当前遍历顺序的后继结点。

代码实现

// C

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

typedef char E;

// 树节点
typedef struct TreeNode {
	E element;
	struct TreeNode* left;
	struct TreeNode* right;
	struct TreeNode* parent;	// 指向双亲(父)结点 ------ 只是"后序遍历"需要用这个属性
	int leftTag, rightTag;		// 标志位,如果为1表示这一边指针指向的是线索,不为1就是正常的孩子结点
} *Node;


// 创建结点
Node createNode(E element) {
	Node node = (Node)malloc(sizeof(struct TreeNode));
	node->left = node->right = NULL;
	node->rightTag = node->leftTag = 0;
	node->element = element;
	return node;
}


// "前序遍历"线索化函数
Node pre1 = NULL;  // 这里我们需要一个pre1来保存后续结点的指向
void preOrderThreaded(Node root) {
	if (root == NULL) return;

	if (root->left == NULL) {   // 首先判断当前结点左边是否为NULL,如果是,那么指向上一个结点
		root->left = pre1;
		root->leftTag = 1;  // 记得修改标记
	}
	if (pre1 && pre1->right == NULL) {  // 然后是判断上一个结点的右边是否为NULL,如果是那么进行线索化,指向当前结点
		pre1->right = root;
		pre1->rightTag = 1;  // 记得修改标记
	}

	pre1 = root;   // 每遍历完一个,需要更新一下pre1,表示上一个遍历的结点

	if (root->leftTag == 0)   // 注意只有标志位是0才可以继续向下,否则就是线索了
		preOrderThreaded(root->left);
	if (root->rightTag == 0)
		preOrderThreaded(root->right);
}


// "前序遍历"一棵经过线索化的二叉树
void preOrder(Node root) {
	while (root) {
		printf("%c", root->element);   // 因为是前序遍历,所以直接按顺序打印就行了
		if (root->leftTag == 0)
			root = root->left;   // 如果是左孩子,那么就走左边
		else
			root = root->right;   // 如果左边指向的不是孩子,而是线索,那么就直接走右边,因为右边无论是线索还是孩子,都要往这边走了
	}
}


// "中序遍历"线索化函数
Node pre2 = NULL;  // 这里我们需要一个pre2来保存后续结点的指向
void inOrderThreaded(Node root) {
	if (root == NULL) return;
	if (root->leftTag == 0)
		inOrderThreaded(root->left);

	// ----------线索化 ---------
	if (root->left == NULL) {
		root->left = pre2;
		root->leftTag = 1;
	}
	if (pre2 && pre2->right == NULL) {
		pre2->right = root;
		pre2->rightTag = 1;
	}
	pre2 = root;
	// ----------线索化 ---------

	if (root->rightTag == 0)
		inOrderThreaded(root->right);
}


// "中序遍历"一棵经过线索化的二叉树
void inOrder(Node root) {

	while (root) {   // 因为中序遍历需要先完成左边,所以说要先走到最左边才行

		while (root && root->leftTag == 0)    // 如果左边一直都不是线索,那么就一直往左找,直到找到一个左边是线索的为止,表示到头了
			root = root->left;

		printf("%c", root->element);   // 到最左边了再打印,中序开始

		while (root && root->rightTag == 1) {   // 打印完就该右边了,右边如果是线索化之后的结果,表示是下一个结点,那么就一路向前,直到不是为止
			root = root->right;
			printf("%c", root->element);   // 注意按着线索往下就是中序的结果,所以说沿途需要打印
		}
		root = root->right;  // 最后继续从右结点开始,重复上述操作

	}
}


// "后序遍历"线索化函数
Node pre3 = NULL;  // 这里我们需要一个pre3来保存后续结点的指向
void postOrderThreaded(Node root) {

	if (root == NULL) return;
	if (root->leftTag == 0) {
		postOrderThreaded(root->left);
		if (root->left) root->left->parent = root;  // 左边完事之后,如果不为空,那么就设定父子关系
	}
	if (root->rightTag == 0) {
		postOrderThreaded(root->right);
		if (root->right) root->right->parent = root;   // 右边完事之后,如果不为空,那么就设定父子关系
	}

	// ------ 线索化 -------
	if (root->left == NULL) {
		root->left = pre3;
		root->leftTag = 1;
	}
	if (pre3 && pre3->right == NULL) {
		pre3->right = root;
		pre3->rightTag = 1;
	}
	pre3 = root;
	// ------ 线索化 -------
}


// "后序遍历"一棵经过线索化的二叉树
void postOrder(Node root) {

	Node last = NULL, node = root;  // 这里需要两个暂存指针,一个记录上一次遍历的结点,还有一个从root开始
	while (node) {
		while (node->left != last && node->leftTag == 0)    // 依然是从整棵树最左边结点开始,和前面一样,只不过这里加入了防无限循环机制,看到下面就知道了
			node = node->left;
		while (node && node->rightTag == 1) {   // 左边完了还有右边,如果右边是线索,那么直接一路向前,也是跟前面一样的
			printf("%c", node->element);   // 沿途打印
			last = node;
			node = node->right;
		}
		if (node == root && node->right == last) {
			// 上面的操作完成之后,那么当前结点左右就结束了,此时就要去寻找其兄弟结点了,我们可以
			// 直接通过parent拿到兄弟结点,但是如果当前结点是根结点,需要特殊处理,因为根结点没有父结点了
			printf("%c", node->element);
			return;   // 根节点一定是最后一个,所以说直接返回就完事
		}
		while (node && node->right == last) {    // 如果当前结点的右孩子就是上一个遍历的结点,那么一直向前就行
			printf("%c", node->element);   // 直接打印当前结点
			last = node;
			node = node->parent;
		}
		// 到这里只有一种情况了,是从左子树上来的,那么当前结点的右边要么是线索要么是右子树,所以直接向右就完事
		if (node && node->rightTag == 0) {  // 如果不是线索,那就先走右边,如果是,等到下一轮再说
			node = node->right;
		}
	}
}





int main() {
	// 一颗二叉树的所有节点
	Node a = createNode('A');
	Node b = createNode('B');
	Node c = createNode('C');
	Node d = createNode('D');
	Node e = createNode('E');

	// 节点相连,形成二叉树
	a->left = b;
	b->left = d;
	a->right = c;
	b->right = e;

	// 前序遍历
	preOrderThreaded(a);	// 线索化
	preOrder(a);			// 遍历

	// 中序遍历
	inOrderThreaded(a);		// 线索化
	inOrder(a);				// 遍历

	// 后序遍历
	postOrderThreaded(a);	// 线索化
	postOrder(a);			// 遍历

	// 释放内存空间
	free(a);
	free(b);
	free(c);
	free(d);
	free(e);

	// 程序暂停
	getchar();

	// 结束主函数
	return 0;
}

二叉查找树

二叉查找树也叫二叉搜索树或是二叉排序树,它具有一定的规则:

  • 左子树中所有结点的值,均小于其根结点的值
  • 右子树中所有结点的值,均大于其根结点的值
  • 二叉搜索树的子树也是二叉搜索树

在这里插入图片描述

平衡二叉树

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

typedef int E;

typedef struct TreeNode {
    E element;
    struct TreeNode * left;
    struct TreeNode * right;
    int height;   // 每个结点需要记录当前子树的高度,便于计算平衡因子
} * Node;


Node createNode(E element){
    Node node = malloc(sizeof(struct TreeNode));
    node->left = node->right = NULL;
    node->element = element;
    node->height = 1;   // 初始化时,高度写为1就可以了
    return node;
}


int max(int a, int b){
    return a > b ? a : b;
}


int getHeight(Node root){
    if(root == NULL) return 0;
    return root->height;
}


Node leftRotation(Node root){  		// 左旋操作,实际上就是把左边结点拿上来
    Node newRoot = root->right;   	// 先得到左边结点
    root->right = newRoot->left;   	// 将左边结点的左子树丢到原本根结点的右边去
    newRoot->left = root;			// 现在新的根结点左边就是原本的跟结点了

    root->height = max(getHeight(root->right), getHeight(root->left)) + 1;
    newRoot->height = max(getHeight(newRoot->right), getHeight(newRoot->left)) + 1;
    return newRoot;
}


Node rightRotation(Node root){
    Node newRoot = root->left;
    root->left = newRoot->right;
    newRoot->right = root;

    root->height = max(getHeight(root->right), getHeight(root->left)) + 1;
    newRoot->height = max(getHeight(newRoot->right), getHeight(newRoot->left)) + 1;
    return newRoot;
}


Node leftRightRotation(Node root){
    root->left = leftRotation(root->left);
    return rightRotation(root);
}


Node rightLeftRightRotation(Node root){
    root->right = rightRotation(root->right);
    return leftRotation(root);
}


Node insert(Node root, E element){
    if(root == NULL) {    					// 如果结点为NULL,说明找到了插入位置,直接创建新的就完事
        root = createNode(element);
    }else if(root->element > element) {   // 和二叉搜索树一样,判断大小,该走哪边走哪边,直到找到对应插入位置
        root->left = insert(root->left, element);
        if(getHeight(root->left) - getHeight(root->right) > 1) {   	// 插入完成之后,需要计算平衡因子,看看是否失衡
            if(root->left->element > element) 			// 接着需要判断一下是插入了左子树的左边还是右边,如果是左边那边说明是LL,如果是右边那说明是LR
                root = rightRotation(root);   // LL型得到左旋之后的结果,得到新的根结点
            else
                root = leftRightRotation(root);    // LR型得到先左旋再右旋之后的结果,得到新的根结点
        }
    }else if(root->element < element){
        root->right = insert(root->right, element);
        if(getHeight(root->left) - getHeight(root->right) < -1){
            if(root->right->element < element)
                root = leftRotation(root);
            else
                root = rightLeftRightRotation(root);
        }
    }
    // 前面的操作完成之后记得更新一下树高度
    root->height = max(getHeight(root->left), getHeight(root->right)) + 1;
    return root;  	// 最后返回root到上一级
}

红黑树

B树

基本认识

B树 ( Balance Tree ),它是专门为磁盘数据读取设计的一种度为 m 的查找树(多用于数据库)

下面是一棵度为4的B树:

在这里插入图片描述

详细规则

  • 树中每个结点最多含有m个孩子(m >= 2)比如上面就是m为4的4阶B树,最多有4个孩子
  • 除根结点和叶子结点外,其它每个结点至少有⌈m/2⌉个孩子,同理键值数量至少有⌈m/2⌉-1个
  • 若根结点不是叶子结点,则至少有2个孩子
  • 所有叶子结点都出现在同一层
  • 一个结点的包含多种信息(P0,K1,P1,K2,…,Kn,Pn),其中P为指向子树的指针,K为键值(关键字)
  • Ki (i=1…n)为键值,也就是每个结点保存的值,且键值按顺序升序排序K(i-1)< Ki
  • Pi为指向子树的指针,且指针Pi指向的子树中所有结点的键值均小于Ki,但都大于K(i-1)
  • 键值的个数n必须满足: ⌈m/2⌉-1 <= n <= m-1

动画演示

https://www.cs.usfca.edu/~galles/visualization/BTree.html

B+树

基本认识

  • B+树是B树的一种变体,有着比B树更高的查询性能
  • B+树上的叶子结点存储关键字以及相应记录的地址,叶子结点以上各层作为索引使用

B+树的应用

在这里插入图片描述

动画演示

https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html

代码演示

https://www.cnblogs.com/yangj-Blog/p/12992124.html

哈夫曼树

基本认识

  • 哈夫曼树(Huffman Tree)又称最优二叉树,是n个带权叶子结点构成的二叉树中,带权路径长度(WPL)最小的二叉树。
  • 哈夫曼编码是一种压缩编码的编码算法,是基于哈夫曼树的一种编码方式。
  • 在计算机数据处理中,哈夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现机率的方法得到的,出现机率高的字母使用较短的编码,反之出现机率低的则使用较长的编码,这便使编码之后的字符串的平均长度、期望值降低,从而实现无损压缩数据。

详细内容

https://zhuanlan.zhihu.com/p/415467000

堆

基本认识

  • 堆 (heap) 是计算机科学中一类特殊的数据结构的统称。
  • 堆通常是一个可以被看做一棵树的数组对象
  • 堆总是满足下列性质:
    • 堆中某个节点的值总是不大于或不小于其父节点的值
    • 堆总是一棵完全二叉树

详细内容

https://blog.youkuaiyun.com/xiaomucgwlmx/article/details/103522410

数据结构学不会?数据结构可视化网站来了 想要触及光芒,却发现影子越来越长学习之路本身就充满了各种苦难,当你想要追求一门技术的时候,会发现似乎困难越来越多,越来越力不从心,但不要放弃,在追逐光芒的过程中影子会越来越长,但不断努力就能触及到你想要的光芒加油各位程序员! 阅读详情

相关推荐

数据结构之树--二叉树/B树/B+树/红黑树及相关算法

树 定义:由一个根结点和m个非根结点组成(m &amp;amp;amp;gt;= 0),其中每个结点下连接n个子结点(n &amp;amp;amp;gt;= 0),非根结点且无子结点的称为叶子结点 树与图的区别在于树中没有一个闭环 二叉树 定义:即每个结点都最多只有两个子结点的树 完全二叉树:高度为k的二叉树,其1~h-1层为满结点,且其h层(叶子结点层)的节点从左至右依次排列(最多2^h-1个,最少0个) 满二叉树:除最后一层外...

目标架构师,进击! 1万+

计算机基础数据结构和算法动态可视化展示网站收录

交互式动画一步步展示整个过程可以帮助我们快速准确地理解这些算法。我们整理了12个可动态交互和展示常见数据结构和排序、图算法等网站

风起于青萍之末,折秀于林 2037

数据结构与算法(十)哈夫曼树

什么叫做哈夫曼树呢?通过一个栗子来看。 我们通常需要按照考试成绩的百分制转换为一个五级分制的成绩,于是得到下面的代码。 if (score < 60) achievement = "不及格"; else if (score < 70) achievement = "及格"; else if (score < 80) achievement = "中等...

SunSatan的博客 1013

(收藏)强烈推荐几个学习数据结构和算法的网站和可视化工具

一、学算法必去的一个网站 首先有一个网站那是每一个学习数据结构与算法都必须去的网站,说出来你就知道了,那就是大名鼎鼎的LeetCode。 链接直达:https://leetcode.com/ 中文版长这个样子的:点开探索给你看看 强烈推荐人手一个啊!不骗你! 二、数据结构可视化网站 接下来就是在你学习数据结构与算法的道路上不得不知的几个可视化网站,啥意思嘞,我们在学习数据结构与算法的时候,之所以会觉得比较难,很大一部分是因为数据结构与算法比较抽象,我们理解起来比较困难,所以啊,理解数据结构与算法的一个最

weixin_42208959的博客 6万+

数据结构与算法——树和二叉树

1、二叉树:是n个结点的有限集,它或者是空集(n=0),或者由一个根结点及两棵互不相交的分别称作这个根左子树和右子树的二叉树组成。2、特点:(1)每个结点最多有两个孩子(2)子树有左右之分,其次序不能颠倒(3)二叉树可以是空集合,根可以有空的左子树或空的右子树3、二叉树的性质(1)性质1:在二叉树的第i层上至多有个结点(i>=1)(2)性质2:深度为k的二叉树至多有个结点(k>=1)(3)性质3:对任何一棵二叉树T,如果其叶子数为n0,度为2的结点数为n2,则n0=n2+1。

m0_57086839的博客 1204

数据结构形象动态演示的网站

最近,很多同学问黄老师,数据结构很难理解,怎么办?可以查看各种算法的时间复杂度。

h a 6 6 6 c k 为 你解决复杂难题! 4290

算法及数据结构系列 - 树

树结构的应用

gdr12的专栏 1441

C++实现B+树数据结构与算法

数据结构是组织和存储数据的方式,它决定着数据如何被使用和操作。良好的数据结构能够提高算法的执行效率,降低系统开销。常见的数据结构有线性结构、树形结构、图结构等。

weixin_42591413的博客 800

数据结构与算法-树、二叉树与BST

对于BST而言,插入一个节点主要是要保持其“小-中-大”的逻辑不变,因此插入的节点的逻辑可以从根节点开始,一步步寻找新节点的“最终归宿”,比如在如下BST中,要插入新节点16,最终应该插入到节点17的左孩子处。由于在顺序存储,数据元素之间的逻辑关系是用物理位置来表达的,而二叉树中每一个节点都有一个对应的标号,因此可以使用标号来作为数组的下标,但除非是完美或者完全二叉树,否则会浪费存储空间,如下图所所示。其中8是根节点,14是10的右孩子(因为二叉树是有序树,因此严格区分左右),而13则是14的左孩子。

m0_74147998的博客 962

数据结构演示软件

数据结构算法演示(Windows版) 使 用 手 册 一、 功能简介 本课件是一个动态演示数据结构算法执行过程的辅助教学软件, 它可适应读者对算法的输入数据和过程执行的控制方式的不同需求, 在计算机的屏幕上显示算法执行过程中数据的逻辑结构或存储结构的变化状况或递归算法执行过程中栈的变化状况。整个系统使用菜单驱动方式, 每个菜单包括若干菜单项。每个菜单项对应一个动作或一个子菜单。系统一直处于选择菜单项或执行动作状态, 直到选择了退出动作为止。 二、 系统内容 本系统内含84个算法,分属13部分内容,由主菜单显示,与《数据结构》教科书中自第2章至第11章中相对应。各部分演示算法如下: 1. 顺序表 (1)在顺序表中插入一个数据元素(ins_sqlist) (2)删除顺序表中一个数据元素(del_sqlist) (3)合并两个有序顺序表(merge_sqlist) 2. 链表 (1)创建一个单链表(Crt_LinkList) (2)在单链表中插入一个结点(Ins_LinkList) (3)删除单链表中的一个结点(Del_LinkList) (4)两个有序链表求并(Union) (5)归并两个有序链表(MergeList_L) (6)两个有序链表求交(ListIntersection_L) (7)两个有序链表求差(SubList_L) 3. 栈和队列 (1)计算阿克曼函数(AckMan) (2)栈的输出序列(Gen、Perform) (3)递归算法的演示  汉诺塔的算法(Hanoi)  解皇后问题的算法(Queen)  解迷宫的算法(Maze)  解背包问题的算法(Knap) (4)模拟银行(BankSimulation) (5)表达式求值(Exp_reduced) 4. 串的模式匹配 (1)古典算法(Index_BF) (2)求Next 函数值(Get_next)和按Next 函数值进行匹配 (Index_KMP(next)) (3)求 Next 修正值(Get_nextval)和按 Next 修正值进行匹配(Index_KMP(nextval)) 5. 稀疏矩阵 (1)矩阵转置 (Trans_Sparmat) (2)快速矩阵转置 (Fast_Transpos) (3)矩阵乘法 (Multiply_Sparmat) 6. 广义表 (1)求广义表的深度(Ls_Depth) (2)复制广义表(Ls_Copy) (3)创建广义表的存储结构(Crt_Lists) 7. 二叉树 (1)遍历二叉树  二叉树的线索化  先序遍历(Pre_order)  中序遍历(In_order)  后序遍历(Post_order) (2) 按先序建二叉树(CrtBT_PreOdr) (3) 线索二叉树  二叉树的线索化  生成先序线索(前驱或后继) (Pre_thre)  中序线索(前驱或后继) (In_thre)  后序线索(前驱或后继) (Post_thre)  遍历中序线索二叉树(Inorder_thlinked)  中序线索树的插入(ins_lchild_inthr)和删除(del_lchild_inthr)结点 (4)建赫夫曼树和求赫夫曼编码(HuffmanCoding) (5)森林转化成二叉树(Forest2BT) (6)二叉树转化成森林(BT2Forest) (7)按表达式建树(ExpTree)并求值(CalExpTreeByPostOrderTrav) 8. 图 (1)图的遍历  深度优先搜索(Travel_DFS)  广度优先搜索(Travel_BFS) (2)求有向图的强连通分量(Strong_comp) (3)有向无环图的两个算法  拓扑排序(Toposort)  关键路径(Critical_path) (4)求最小生成树  普里姆算法(Prim)  克鲁斯卡尔算法(Kruscal) (5)求关节点和重连通分量(Get_artical) (6)求最短路径  弗洛伊德算法(shortpath_Floyd)  迪杰斯特拉算法(shortpath_DIJ) 9. 存储管理 (1)边界标识法 (Boundary_tag_method) (2)伙伴系统 (Buddy_system) (3)紧缩无用单元 (Storage_compaction) 10. 静态查找 (1)顺序查找(Search_Seq) (2)折半查找 (Serch_Bin) (3)插值查找 (Search_Ins) (4)斐波那契查找 (Search_Fib) (5)次优查找树(BiTree_SOSTree) 11. 动态查找 (1)在二叉排序树上进行查找(bstsrch)、插入结点(ins_bstree)和删除结点(del_bstree) (2)在二叉平衡树上插入结点(ins_AVLtree) 和删除结点(del_AVLtree) (3)在 B-树上插入结点(Ins_BTree) 和 删除结点(Del_BTree) (4)在 B+树上插入结点(Ins_PBTree) 和 删除结点(Del_PBTree) 12. 内部排序 (1)简单排序法  直接插入排序(Insert_sort)  表插入排序(内含插入(Ins_Tsort) 重排(Arrange)两个算法)  起泡排序(BubbleSort)  简单选择排序(SelectSort) (2)复杂排序法  堆排序(HeapSort)  快速排序(QuickSort)  锦标赛排序(Tournament) (3)其他  快速地址排序(QkAddrst)  基数排序(RadixSort) 13. 外部排序 (1)多路平衡归并排序(K-Merge) (2)置换-选择排序(Repl_Selection) 三、 运行环境 1. 硬件:Pentium100以上PC机。 2. 软件:Windows95及以上版本的操作系统。 四、 运行 本系统的执行文件为DSDEMOW.EXE。 五、 如何使用本课件 读者可以利用鼠标移动光标选择“演示算法”或“菜单命令”来控制课件的运行过程。 1. 课件的演示算法菜单为页式菜单。第一级菜单中的各项与上述“系统内容”中各大项相对应,读者运行“算法演示课件”后, 即进入“算法选择一级菜单”画面,此时可移动光标进行选择,当光标所在菜单项改为红色时,单击鼠标即进入“算法选择二级菜单”,进行相同操作之后,或进入算法选择三级菜单(如图1所示),或进入算法演示的执行状态(如图2所示)。 图1 图2 在算法选择菜单画面中,形如 的图标意为尚有下级菜单,形如 的图标则表示将直接进入算法演示状态。此时也可直接单击一级菜单或二级菜单的标题直接返回之,注意:菜单右侧上方的“退出”按钮意为退出整个演示课件。 2. 算法演示执行状态下的屏幕分为三部分:第一行为“标题行”,第二行为“菜单命令”,以下为算法演示屏上各菜单的说明。 菜单命令中各项自左至右的功能分别为:  数据——设置算法演示的数据(数据结构)。  调用栈——察看当前函数(或过程)嵌套或递归的历程。  说明——察看算法说明。  暂停——中断演示过程。  执行——连续执行算法直至所设断点或至算法执行完毕。  单步——执行一行算法,遇到子程序调用时,连续执行完子程序。  跟踪——执行一行算法,遇到子程序调用时,进入子程序。  执行到——演示算法到当前所设最近的断点或算法窗口中的当前行。  恢复——重置屏幕为当前算法执行前的初始状态。  断点——在算法窗口的当前选择行设置断点或清除断点。  设置——设置连续演示时的速度或开/闭背景音乐(或动作音效)开关。  返回——返回算法选择菜单。 3. 断点的设置方法为:移动光标至“断点语句”所在行,点击鼠标后即出现绿色光条,之后单击“断点”菜单中的“设置断点”命令项即可,此时该断点语句所在行上将出现红色光条。 六、 算法演示屏的详细说明 本系统对屏幕设计的基本原则是集数据结构、算法和其他重要信息(如栈等)于同一屏幕。一般情况下演示屏由图示、算法和变量三个窗口组成,特殊情况下将根据演示内容适当增加。一般情况下, 左侧图示窗口显示演示数据的逻辑结构或存储结构,右侧上方窗口显示算法文本,右侧下方窗口显示当前算法中各变量的值或递归工作栈的状态。各窗口间的边界大小均可自由调节,且可按需扩大至全屏。 算法窗口显示当前演示的算法文本,并以深蓝色的光条覆盖将要执行的语句。若算法中含有函数或过程调用语句,则当光条覆盖到该过程调用语句时,随即自动隐去原算法文本而显示子过程的文本,而从此过程返回时再重新显示原算法文本。类似地,在演示递归算法执行过程时,每当执行递归调用本过程的语句时,随即隐去当前层次的算法文本而显示下一层的算法文本,并且以不同颜色的算法文本表示递归的不同层次。如第一层的算法文本为深绿色,第二层为紫色,第三层为深红色,第四层为深蓝色,第五层为浅蓝色,第六层为玫瑰红色等。 当演示递归算法执行过程中递归工作栈的变化状态时,递归工作栈显示在右侧下窗口,递归工作栈的状态和算法文本窗口中相应语句执行后的结果相对应,栈顶记录为当前递归层的参量值。每进入一层递归时,就产生一个新的工作记录(包括调用语句行号、变量参数或全程变量、数值参数和局部变量)压入栈顶;每退出一层递归时,先根据栈顶的调用语句行号返回至上层,然后在传递完变量参数的值后退栈。 各个算法演示屏的补充说明如下: 1. 顺序表和链表的插入、删除和链表的生成 算法演示屏由显示顺序表或链表的图示、算法文本及变量等三个窗口组成。在演示算法之前,需先在弹出的小窗口中输入线性表的数据元素及算法参数 i(插入或删除的位置)和 b(被插的数据元素)的值。顺序表的图示窗口在演示屏的上方,链表的图示窗口在左侧。 2. 有序表的操作 算法演示屏的状态和 1 中所述相同。 3. 汉诺塔问题 算法演示屏由4个窗口组成。右侧上方为算法文本,在算法中有4个形式参量,其中值参 n 为圆盘个数,x、y、和 z 分别表示3个塔座;右侧下方为递归工作栈,栈中每个记录包含调用语句行号 adr 及值参 n 和 x、y、z;左侧上方显示汉诺塔图形及移动操作结果;左侧下方显示移动操作的记录。 4. 迷宫问题 左侧窗口显示迷宫的逻辑结构,由 N×N 个方格组成,左上[1,1]为入口,右下[N,N]为出口,并且以红色钉子填充表示障碍,空白表示通路,红色交通灯表示已游历过的路,箭头表示继续游历的方向,演示结束时显示一条通路或迷宫不通的信息。右侧下窗口为递归工作栈,栈中每个记录含6个数据项,其中 adr 指示调用语句行号,k 指示步数,(x,y) 表示当前坐标,i 指示路径方向(起始方向为 1,顺时针方向旋转搜索)。 5. 皇后问题 左侧图示窗口包含棋盘和递归工作栈两部分,栈中记录含3个数据项,其中 adr 指示调用语句行号,k 指示列号,i 指示行号。此算法演示可求得所有可行结果,在求得每一种排布的结果之后,均会弹出一个窗口显示“找到第 j (j=1,2,…) 种排布”,单击“确定”按钮将继续进行,直至找到所有可能构成的排布。 6. 背包问题 右侧图示窗口的上方显示背包、物件及其体积。 若有解,则在求得每一组结果之后,均会弹出一个窗口提示求得一组解,单击提示窗口中的小人将继续进行。该窗口的下方为递归工作栈,栈中的记录含3个数据项,其中 adr 指示调用语句所在行号,n 指示物件个数,t 指示背包总体积。 7. 阿克曼函数 整个演示屏只有显示算法文本和显示算法执行过程中栈的状态两个窗口。在执行算法之前,首先应按照提示输入参数 m 和 n 的值。 8. 栈的输出序列 图示窗口的内容为:由算法 Gen 生成的栈的操作序列(列出在窗口的下方)、算法 Perform 执行时栈的操作过程(该窗口的上方)以及算法 Perform 执行的结果——栈的输出序列(列出在图示窗口的右侧)。 9. 表达式求值 图示窗口的内容主要为显示表达式求值过程中操作数栈和运算符栈的变化情况以及主要操作。上方的小窗口显示在算法演示之前设定的表达式。 10. 离散事件模拟 图示窗口分成3部分:中间部分或显示客户流动情况的动画,或显示程序执行过程中事件表和4个队列的数值,上方两个按钮用以切换动画或静态数据,下方则显示客户总人数、客户逗留的累计时间以及调节动画中小人移动速度的指针。 11. 串的模式匹配 上窗口显示算法文本,下窗口显示串的匹配过程或求 next 函数的过程。 12. 稀疏矩阵 图示窗口显示矩阵的状态或其三元组的表示。 13. 求广义表的深度 图示窗口显示广义表的存储结构,图中指针 ls 指向当前所求深度的广义表,值为空时不显示。演示结束时弹出窗口显示求得的深度。 14. 复制广义表 图示窗口的上方显示已知广义表的存储结构,图示窗口的下方显示复制求得的广义表的存储结构。递归工作栈中含调用语句行号 adr、变参 nls 和值参 ls。 15. 创建广义表的存储结构 图示窗口显示广义表存储结构的建立过程和算法执行过程中参数Sub的当前值。 16. 遍历二叉树 图示窗口显示二叉树的逻辑结构和遍历结果输出的结点序列,图中指针 bt 指向当前遍历的二叉树的根结点。 17. 线索二叉树 图示窗口显示二叉树的存储结构,但结点中只含标志域,而以结点间的黑色连线表示指针,红色连线表示前驱线索,蓝色连线表示后继线索。在二叉树线索化的过程中,图中指针 p 指向当前层二叉树的根结点,指针 pre 指向当前被访问的结点的前驱。在演示线索树的插入和删除过程时,图示窗口的下方还包括“输入行”和“提示行”。 18. 按先序序列建二叉链表 图示窗口显示输入的先序序列和生成二叉链表的过程。 19. 森林和二叉树的相互转换 图示窗口在显示屏的上方,其左侧为森林,右侧为二叉树。 20. 赫夫曼树和赫夫曼编码 图示窗口显示生成的赫夫曼树的逻辑结构和每个叶子结点的编码。 21. 图的深度优先搜索 图示窗口的上半部分显示图的逻辑结构,初始状态用青色圆圈表示顶点,结点间的黑色连线表示边或弧(连线上画有箭头)。演示过程中用红色覆盖已访问的顶点和边(或弧)。窗口下方显示图的邻接表,演示过程中以红色框边表示已访问过的弧。图示窗口的下方显示遍历后输出的顶点序列。 22. 图的广度优先搜索 与深度优先不同的是,在窗口的下方增加一个队列,其左端为队头,右端为队尾。 23. 求有向图的强连通分量 图示窗口自上而下分别显示有向图的逻辑结构、存储结构和 Finished 数组在算法执行过程中的变化情况。所求得的各个强连通分量,将以不同颜色的顶点组表示。 24. 求关节点和重连通分量 图示窗口的上半部分显示无向图,下半部分自上而下分别显示 Vexnum、Vexdata、Visited、Low、Squlow(求得 low 值的顺序)和 artpoint(关节点)的信息。 25. 有向图的拓扑排序 图示窗口由5部分组成。其中左上显示有向图的邻接表;左下显示有向图,其中顶点和弧的初始状态分别为绿色和黑色,从栈中退出的顶点(i)用红色表示,分别以蓝色和红色指示当前访问的邻接点(k)和它们之间的弧(ik),灰白色表示已经输出的顶点;右下显示顶点的入度;右上显示入度为零的栈。当拓扑排序不成功时,在演示屏的中央将会弹出一个窗口,显示提示信息“网中存在自环!”,此时用户可在左下显示的有向图中由绿色顶点和黑色弧构成的子图中找到这个环。 26. 有向图的关键路径 图示窗口包含5部分信息。左上显示带入度域的邻接表;左下显示有向网的逻辑结构和顶点的入度及各顶点事件的最早发生时间和最迟发生时间;右下显示拓扑排序过程中入度为零的顶点的栈S,右上显示的栈 T 存放拓扑序列,其入栈顺序和栈 S 的出栈顺序相同,从栈顶到栈底的顶点顺序即为顶点的逆拓扑序列。算法执行结束后将弹出窗口列出全部结果,其中红色字体的弧表示关键活动。 27. 普里姆算法 图示窗口包含3部分内容。右上是邻接矩阵;左上是无向网的逻辑结构,图中顶点的初始状态为黄色,算法执行过程中,红色覆盖的顶点和边则表示已加入生成树的顶点和生成树上的边;窗口的下方则显示 closedge 数组中的值。 28. 克鲁斯卡尔算法 图示窗口的左侧为无向网,以红色标定已落在生成树上的边;右侧自上而下列出各条边的信息以及选择生成树的边的执行过程。 29. 边界标识法 图示窗口的初始状态为 64KB 的模拟存储器,演示过程中,以绿色覆盖占用块。各个存储块的头部左侧所示为该块的起始地址,头部结构或其他信息参见教科书。用户可根据弹出窗口的操作提示信息进行操作,输入请求分配的空间大小或释放块的首地址。 30. 伙伴系统 在图示窗口中,左侧为可利用空间链表的逻辑结构,右侧为存储结构,其中红色覆盖部分为占用块。弹出窗口为输入窗口,由用户输入请求分配的空间大小或释放块的首地址。 31. 紧缩无用单元 右侧显示存储空间,空白表示空闲块,其他颜色覆盖表示占用块,在存储空间不足分配时将进行空闲块压缩。左侧显示存储映像。弹出窗口为输入窗口,由用户输入请求分配的空间大小和分配或释放块的块名。 32. 静态查找 上窗口为图示窗口,演示查找过程;左下和右下分别为算法文本和变量窗口。 33. B-树和B+树 整个屏幕分为上、下两个窗口,上窗口演示插入或删除结点过程中B-树或B+ 树结构的变化状况;下窗口内显示如查找关键字、插入位置、结点分裂等操作信息。下窗口上面左侧的小窗口为编辑窗口,由用户输入待插或待删的关键字,输入之后其右侧的操作命令将由隐式状态改为显式状态。 34. 内部排序 图示窗口演示排序过程以及排序过程中关键字之间进行的比较次数和记录移动的次数。 七、 用户自行输入数据指南 算法操作的对象——数据结构,或由用户自行输入,或由系统随机产生,并在获得用户的确认之前,可反复随机产生,直至用户满意,用鼠标点击“OK”按钮确认为止。 多数情况下的输入界面上有足够的提示信息,以指示用户需要进行何种操作。补充说明如下: 1. 表的数据元素为任意的单个字符。 2. 迷宫的输入界面如图3所示。图中砖墙图案表示障碍,连续点击鼠标可将光标所在位置设置成通道或者障碍,建议用户先点击“随机生成”按钮随机生成一个迷宫,然后移动鼠标调整成所需。所设迷宫可以利用“保存数据”按钮生成dat类型文件,并在需要时可以利用“取出数据”按钮读入。 图3 3. 演示背包问题的算法之前,首先需要输入物品个数,之后将出现如图4所示的输入界面,可以利用“随机生成”的按钮或各个相应的小窗口输入物品体积 wi 和背包体积 T 。背包的总体积不得超过 30 ,单个物品的体积不得超过 10 。 图4 4. “表达式求值”和“建表达式树”时的输入界面如图5所示。用户可在窗口内自行输入,并以“Enter”键为结束符;也可以连续点击左侧蓝色的表达式由系统自动生成,直至用户点击右侧的计算器表示确认为止。“求值”可实现带括弧的四则运算和幂次运算,并支持sin、cos、tan、arcsin 和 arccos 等函数计算,其操作数为实数。“建树”的表达式仅限于带括弧的四则运算,其操作数为单个字母的字符。 图5 5. 稀疏矩阵的输入界面如图6所示。用户可随意进行矩阵中任意位置元素的输入,只要将光标移动至待输入的元素位置,单击鼠标后将弹出计算器,单击数字按钮,可进行随意输入,之后点击“OK”按钮表示确认。 图6 6. 广义表的数据输入方式为自左向右顺序输入广义表的字符串。输入过程中,图7所示输入界面中的“确定”为灰色字体,只有当用户正确输入完毕时,“确定”两字才改为黑色字体,此时用户可单击此按钮表示确认。 图7 7. 图的输入界面如图8所示。之前尚需确认是否为有向图和带权图。在用户自行输入图时,首先按下“创建节点”按钮,之后可移动光标至窗口的任意位置单击鼠标创建顶点;然后单击“创建弧”按钮,可在任意两个顶点之间构建弧或边。构建弧(或边)的操作为:先将光标移动至弧尾的顶点,单击一次鼠标,然后移动光标至弧头位置,再单击一次鼠标。对于带权的图,则在构建弧(或边)的同时,在当时弹出的窗口中输入权值,权值的默认值为 1。 图8 8. 内部排序的关键字均为单个字符。

Python量化交易实战:从零搭建你的第一个多因子选股模型(附完整代码)

本文是一份详细的Python量化交易入门实战指南,手把手教你从零搭建第一个多因子选股模型。内容涵盖环境配置、数据获取、因子挖掘与有效性检验、多因子合成以及完整的策略回测与绩效评估,并附有可直接运行的完整代码,帮助初学者快速掌握量化交易的基本概念与实践流程。

resnet7explorer的博客 933

算法基础—数据结构—树

我们就先从树的储存看起吧。 以字母为例,先建立一个根节点,然后向右创建子节点,并在最后的字符串的结尾处进行标记。 好了,上模板代码(取自AcWing) int son[N][26], cnt[N], idx; // 0号点既是根节点,又是空节点 // son[][]存储树中每个节点的子节点 // cnt[]存储以每个节点结尾的单词数量 // 插入一个字符串 void insert(c...

qq_43638329的博客 254

PCB布局布线要求及多层电路板叠加原则

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。提示:以下是本篇文章正文内容,下面案例可供参考本文主要针对PCB布局布线中的要点进行了总结,并对多层电路板的叠加原则进行了解释。

Ka_wyb的博客 2934

# 基本数据结构与算法(树)

基本数据结构与算法(树) 树的前中后序遍历 定义树的数据结构 class TreeNode { /** * 节点存放的值 */ int val; /** * 左节点 */ TreeNode left; /** * 右节点 */ TreeNode right; TreeNode(int val) { this.val = val; } TreeNod

不积跬步,无以至千里;不积小流,无以成江海 268

PCIe Gen4 Switch芯片PM40028调试踩坑实录:从boot引脚设置到串口无输出的诡异问题

本文记录了PCIe Gen4 Switch芯片PM40028的实战调试过程,重点剖析了从boot引脚配置错误导致串口无输出,到使用逻辑分析仪定位并解决启动问题的完整排障思路。文章深入探讨了芯片启动流程、硬件信号测量方法,并总结了高速硬件调试的核心经验与系统性排查清单,为工程师解决类似PCIe Gen4设备调试难题提供实用指南。

i8j9k0l1的博客 251

【100%通过率】华为od机试C卷【特殊的加密算法】Python 实现

有一种特殊的加密算法,明文为一段数字串,经过密码本查找转换,生成另一段密文数字串。规则如下1.明文为一段数字串由0-9组成2.密码本为数字0-9组成的二维数组3.需要按明文串的数字顺序在密码本里找到同样的数字串,密码本里的数字串是由相邻的单元格数字组成,上下和左右是相邻的,注意:对角线不相邻,同一个单元格的数字不能重复使用。

MISAYAONE的博客 5924

数据结构与算法——树与树算法

目录 第六章 树 树的概念 树的术语 树的种类 树的存储与表示 常见的一些树的应用场景 二叉树 二叉树的基本概念 二叉树的性质(特性) 二叉树的节点表示以及树的创建 二叉树的遍历 广度优先遍历(层次遍历) 深度优先遍历 第六章 树 树的概念 每个节点有零个或多个子节点; 没有父节点的节点称为根节点; 每一个非根节点有且只有一个父节点; 除了根节点外,每个子节点可以分为多个不相交的子树; 树的术语 节点的度:一个节点含有的子树的个数称为该节点的度; 树

weixin_46489969的博客 171

风电功率预测 | 基于RF随机森林的风电功率预测(附matlab完整源码)

风电功率预测 | 基于RF随机森林的风电功率预测(附matlab完整源码)

天天酷科研的博客 896

数据结构与算法---B+树

再了解B+树之前如果还有不清楚B-树的可以了解先去一下,方便后续理解。 B-Tree B+Tree 简介 B+树是一种树数据结构,通常用于数据库和操作系统的文件系统中。B+树的特点是能够保持数据稳定有序,其插入与修改拥有较稳定的对数时间复杂度。B+树元素自底向上插入,这与二叉树恰好相反。 定义 B+树是B树的一种变形形式,B+树上的叶子结点存储关键字以及相应记录的地址,叶子结点以上各层作为索引使用。一棵m阶的非空B+树满足如下条件: 每个结点至多有m个子女; 除根结点外,每个结点至少有m/2个子结点,.

it浅阳的博客 1180

Linux 下安装 openjdk 17【详细步骤】

JDK17,安装教程。

甘蓝的专栏 7503

【SigmaStudio】自定义算法组件之XML编写规范(一)

SigmaStudio生成自定义算法组件时,需要XML和DLB文件,本文主要记录XML文件的编码规范

liang_song的博客 1139

数据结构与算法总结——树

若将树中每个节点的各子树看成是从左到右有次序的(即不能互换),则称该树为有序树(Ordered Tree)

sinat_39377093的博客 2490

计算机毕设项目一:基于卷积神经网络、resnet、VGG化妆品分类识别 完整代码数据可直接运行

计算机毕设项目一:基于卷积神经网络、resnet、VGG化妆品分类识别 完整代码数据可直接运行

653

数据结构与算法——树与二叉树

树型结构是一类重要的非线性数据结构,其中以树和二叉树最为常用,直观来看,树是以分支关系定义的层次结构。树型结构在客观世界中广泛存在,比如人类社会中的祖辈关系,社会机构组织等等都可以用树来形象表示。树型结构在计算机领域中也得到了广泛应用。

小田是个程序员的博客欢迎你的到来呀~ 2319

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Python数据结构与算法之树与树算法

树的概念       树(tree)是一种抽象数据类型(ADT)或是实现这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合。它是由n(n>=1)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是跟朝上,而叶超下的。它具有以下有特点: 每个节点由零个或多个子节点 没有父节点的节...

weixin_44953902的博客 286

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

算法与数据结构:树

前缀树的增删改查,二叉树的递归套路,二叉树的遍历,序列化和反序列化,搜索二叉树,平衡二叉树,完全二叉树

2401_88007700的博客 770

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

上一篇: 数据结构与算法---线性表
下一篇: 查找算法与排序算法
code_stream
博客等级 码龄4年 1238粉丝 169原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值