学习笔记—数据结构—二叉树(链式)

news2025/4/25 22:46:24

目录

二叉树(链式)

概念

结构

初始化

遍历

前序遍历

中序遍历

后序遍历

层序遍历

结点个数

叶子结点个数

第k层结点个数

深度/高度

查找值为x的结点

销毁

判断是否为完整二叉树

总结

头文件Tree.h

Tree.c

测试文件test.c

补充文件Queue.h

补充文件Queue.c


二叉树(链式)

概念

用链表来表示⼀棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址

结构

//二叉树结点的结构
typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;               //值域
	struct BinaryTreeNode* left;   //左孩子
	struct BinaryTreeNode* right;  //右孩子
}BTNode;

初始化

//初始化
BTNode* buyNode(BTDataType x)
{
	BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
	if (newnode == NULL)
	{
		perror("mallor fail!");
		exit(1);
	}
	newnode->data = x;
	newnode->left = newnode->right = NULL;

	return newnode;
}

遍历

前序遍历

前序遍历(Preorder Traversal 亦称先序遍历):访问根结点的操作发生在遍历其左右⼦树之前

访问顺序为:根结点、左子树、右子树

//前序遍历--根左右
void PreOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	printf("%d ", root->data);
	PreOrder(root->left);
	PreOrder(root->right);
}

中序遍历

中序遍历(Inorder Traversal):访问根结点的操作发生在遍历其左右子树之中(间)

访问顺序为:左子树、根结点、右子树

//中序遍历--左根右
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}

后序遍历

后序遍历(Postorder Traversal):访问根结点的操作发生在遍历其左右子树之后

访问顺序为:左子树、右子树、根结点

//后续遍历--左右根
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->data);
	
}

层序遍历

在二叉树的层序遍历是指按照树的层次顺序,从上到下、从左到右逐层访问二叉树的节点。这种遍历方式可以帮助我们了解二叉树的结构布局,特别是在处理树状数据结构时非常有用。

对于这么一个二叉树来说,我们通过层序遍历最后得到的是1 2 3 4 5 6

这里我们是不能通过递归来实现的

但是我们可以借助队列来实现这么一个结构

队列的结构是先进先出

恰好我们队列的底层结构就是链表来实现的,和这里的链式二叉树一样的

我们将之前写的Queue.c文件和Queue.h文件复制到我们链式二叉树的文件夹里面

typedef struct BinaryTreeNode* QDataType;

struct BinaryTreeNode*这个就是我们要保存在队列中的数据类型

之前的在队列中保存的数据类型是int类型

队列中存储的是堆节点的地址

那么存储的就是节点的指针,那么我们将这个类型重新定义

//层序遍历
void Levelorder(BTNode* root)
{
	//创建一个队列结构
	Queue q;
	QueueInit(&q);//进行初始化
	//第一步:让根节点直接入队列
	QueuePush(&q, root);//往队列中push根节点
	while (!Queuempty(&q))//只要队列不为空,我们就一直取队头数据
	{
		//取队头数据
		BTNode* front = QueueFront(&q);//将队头取出,返回值是节点的地址
		//打印对头
		printf("%d ", front->data);
		//让队头出队列
		QueuePop(&q);//那么此时的队列是空的

		//将队头节点的左右孩子入队列
		if (front->left)//如果这个节点的左孩子不是空的,那么我们将这个节点往队列中入
		{
			QueuePush(&q, front->left);
		}
		if (front->right)//如果这个节点的右孩子不是空的,那么我们将这个节点往队列中入
		{
			QueuePush(&q, front->right);
		}


	}

	QueueDestroy(&q);//销毁
}

结点个数

利用递归的方法,左右子树调用,如果该节点为NULL 便会返回0,否则返回1。

// 二叉树结点个数
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	//递归
	return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}

叶子结点个数

// 二叉树叶子结点个数
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);
}

第k层结点个数

假设查找第三层,K为3 ,每次递归K–,知道K== 1 的时候 返回1

// 二叉树第k层结点个数
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));
}

深度/高度

利用 left和right记录左右子树的个数,然后比较 选择较大的一个。

// 二叉树的深度/高度
int BinaryTreeDepth(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	int leftDep = BinaryTreeDepth(root->left);
	int rightDep = BinaryTreeDepth(root->right);

	return leftDep > rightDep ? leftDep + 1 : rightDep + 1;
}

查找值为x的结点

节点的查找,如果节点为NULL饭后NULL,如果此节点的data等于x,返回节点的地址。

// 二叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return 0;
	}
	if (root->data == x)
	{
		return 1;
	}
	BTNode* leftFind = BinaryTreeFind(root->left,x);
	if (leftFind)
	{
		return leftFind;
	}
	BTNode* rightFind = BinaryTreeFind(root->right,x);
	if (leftFind)
	{
		return rightFind;
	}
	return NULL;
}

销毁

// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{
	if (*root == NULL)
	{
		return 0;
	}
	BinaryTreeDestory(&((*root)->left));
	BinaryTreeDestory(&((*root)->right));

	free(*root);
	*root = NULL;
}

判断是否为完整二叉树

除了最后一层,其它层的节点数达到最大,那么这个数就是完全二叉树

这里涉及到每层,那么这里还是要借助队列这么一个结构的

我们先取根节点放进队列,队列不为空,我们将队列中的节点取出来

然后将这个节点的左右孩子一起放进队列中去

我们再将队头取出,将队头的左右孩子放进去,如果孩子为空放个NULL进去

如果我们队列剩下的都是NULL的话,我们将队列中第一个NULL取出

那么我们取到的数据为空,取到为空的情况我们就跳出循环

//判断二叉树是否为完全二叉树
//借助队列
bool BinaryTreeComplete(BTNode* root)
{
    Queue q;
    QueueInit(&q);//进行初始化

    //将二叉树根节点入队列
    QueuePush(&q, root);//往队列中push根节点

    while (!Queuempty(&q))//队列不为空,我们就循环取队头
    {
        BTNode* front = QueueFront(&q);//将队头取出

        QueuePop(&q);//让队头出队,保证下次取到的是最新的队头数据


        //如果我们取到的front是空的话
        if (front == NULL)//如果此时的队头是空的,那么我们就取不到左右孩子
        {
            break;
        }

        //将队头的左右孩子取出放到队列中
        QueuePush(&q, front->left);
        QueuePush(&q, front->right);
    }

    //此时队列不一定为空
    while (!Queuempty(&q))//只要队列不为空
    {
        BTNode* front = QueueFront(&q);//取队头
        QueuePop(&q);//出队列
        //如果我们在队列中剩下的节点中遇到了节点的话,那么这个树就不是一个完全二叉树了
        if (front != NULL)
        {
            QueueDestroy(&q);//销毁
            return false;
        }
    }


    QueueDestroy(&q);//销毁

    //到这里就说明没有找到完全二叉树
    return true;
}

总结

头文件Tree.h

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

//定义二叉树链式结构
//二叉树结点的结构
typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;               //值域
	struct BinaryTreeNode* left;   //左孩子
	struct BinaryTreeNode* right;  //右孩子
}BTNode;



//前序遍历
void PreOrder(BTNode* root);
//中序遍历
void InOrder(BTNode* root);
//后续遍历
void PostOrder(BTNode* root);

// 二叉树结点个数
int BinaryTreeSize(BTNode* root);
// 二叉树叶子结点个数
int BinaryTreeLeafSize(BTNode* root);
// 二叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k);
// 二叉树的深度/高度
int BinaryTreeDepth(BTNode * root);
// 二叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
// 二叉树销毁
void BinaryTreeDestory(BTNode** root);

//层序遍历---借助数据结构(队列)
void Levelorder(BTNode* root);
//判断二叉树是否为完全二叉树
bool BinaryTreeComplete(BTNode* root);

Tree.c

#include"Tree.h"
#include"Queue.h"
//前序遍历--根左右
void PreOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	printf("%d ", root->data);
	PreOrder(root->left);
	PreOrder(root->right);
}

//中序遍历--左根右
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}
	


//后续遍历--左右根
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->data);
	
}

// 二叉树结点个数
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	//递归
	return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}

// 二叉树叶子结点个数
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);
}

// 二叉树第k层结点个数
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));
}

// 二叉树的深度/高度
int BinaryTreeDepth(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	int leftDep = BinaryTreeDepth(root->left);
	int rightDep = BinaryTreeDepth(root->right);

	return leftDep > rightDep ? leftDep + 1 : rightDep + 1;
}

// 二叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return 0;
	}
	if (root->data == x)
	{
		return 1;
	}
	BTNode* leftFind = BinaryTreeFind(root->left,x);
	if (leftFind)
	{
		return leftFind;
	}
	BTNode* rightFind = BinaryTreeFind(root->right,x);
	if (leftFind)
	{
		return rightFind;
	}
	return NULL;
}

// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{
	if (*root == NULL)
	{
		return 0;
	}
	BinaryTreeDestory(&((*root)->left));
	BinaryTreeDestory(&((*root)->right));

	free(*root);
	*root = NULL;
}

//层序遍历
void Levelorder(BTNode* root)
{
	//创建一个队列结构
	Queue q;
	QueueInit(&q);//进行初始化
	//第一步:让根节点直接入队列
	QueuePush(&q, root);//往队列中push根节点
	while (!Queuempty(&q))//只要队列不为空,我们就一直取队头数据
	{
		//取队头数据
		BTNode* front = QueueFront(&q);//将队头取出,返回值是节点的地址
		//打印对头
		printf("%d ", front->data);
		//让队头出队列
		QueuePop(&q);//那么此时的队列是空的

		//将队头节点的左右孩子入队列
		if (front->left)//如果这个节点的左孩子不是空的,那么我们将这个节点往队列中入
		{
			QueuePush(&q, front->left);
		}
		if (front->right)//如果这个节点的右孩子不是空的,那么我们将这个节点往队列中入
		{
			QueuePush(&q, front->right);
		}


	}

	QueueDestroy(&q);//销毁
}

//判断二叉树是否为完全二叉树
//借助队列
bool BinaryTreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);//进行初始化

	//将二叉树根节点入队列
	QueuePush(&q, root);//往队列中push根节点

	while (!Queuempty(&q))//队列不为空,我们就循环取队头
	{
		BTNode* front = QueueFront(&q);//将队头取出

		QueuePop(&q);//让队头出队,保证下次取到的是最新的队头数据


		//如果我们取到的front是空的话
		if (front == NULL)//如果此时的队头是空的,那么我们就取不到左右孩子
		{
			break;
		}

		//将队头的左右孩子取出放到队列中
		QueuePush(&q, front->left);
		QueuePush(&q, front->right);
	}

	//此时队列不一定为空
	while (!Queuempty(&q))//只要队列不为空
	{
		BTNode* front = QueueFront(&q);//取队头
		QueuePop(&q);//出队列
		//如果我们在队列中剩下的节点中遇到了节点的话,那么这个树就不是一个完全二叉树了
		if (front != NULL)
		{
			QueueDestroy(&q);//销毁
			return false;
		}
	}


	QueueDestroy(&q);//销毁

	//到这里就说明没有找到完全二叉树
	return true;
}

测试文件test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"tree.h"

BTNode* buyNode(BTDataType x)//创建一个节点
{

    BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
    if (newnode == NULL)
    {
        perror("malloc fail!");
        exit(1);
    }
    newnode->data = x;
    newnode->left = newnode->right = NULL;
    return newnode;
}
void test01()
{
    BTNode* node1 = buyNode(1);
    BTNode* node2 = buyNode(2);
    BTNode* node3 = buyNode(3);
    BTNode* node4 = buyNode(4);
    /*BTNode* node5 = buyNode(5);
    BTNode* node6 = buyNode(6);*/

    node1->left = node2;
    node1->right = node3;
    node2->left = node4;
    /*node2->right = node5;
    node3->left = node6;*/
    //前序遍历
     PreOrder(node1);// 1 2 4 3

     printf("\n");
     //中序遍历
     InOrder(node1);// 4 2 1 3

     //二叉树节点的个数
     printf("size:%d\n", BinaryTreeSize(node1));//4
     printf("size:%d\n", BinaryTreeSize(node2));//2

     // 二叉树叶子结点的个数
     printf("leaf size:%d\n", BinaryTreeLeafSize(node1));

     //第k层节点的个数
     printf("k size:%d\n", BinaryTreeLevelKSize(node1, 3));

     //二叉树的高度
     printf("depth/height :%d\n", BinaryTreeDepth(node1));

     //查找值为x的节点
     BTNode*find=BinaryTreeFind(node1, 5);
     printf("%s\n", find == NULL ? "没找到":"找到了");

     //层序遍历
     Levelorder(node1);

    //判断是否为完全二叉树
    bool ret = BinaryTreeComplete(node1);
    printf("%s\n", ret == false ? "不是完全二叉树" : "是完全二叉树");

    //二叉树的销毁
    BinaryTreeDestory(&node1);

}
int main()
{
    test01();
    return 0;
}

补充文件Queue.h

#pragma once

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



//定义队列结构
//typedef int QDataType;

typedef struct BinaryTreeNode* QDataType;
//struct BinaryTreeNode*这个就是我们要保存在队列中的数据类型
//struct BinaryTreeNode*这个是个数据类型,和之前的
//之前的在队列中保存的数据类型是int类型
//因为我们在tree.h中将结构体类型重命名了
//那么我们可以这么写
//typedef struct BTNode* QDataType;

typedef struct QueueNode
{
    QDataType data;
    struct QueueNode* next;

}QueueNode;

typedef struct Queue
{
    QueueNode* phead;//指向头节点的指针---队头--删除数据
    QueueNode* ptail;//指向尾节点的指针---队尾--插入数据
    int size;//保存队列有效个数
}Queue;


//初始化
void QueueInit(Queue* pq);

//入队列,队尾   插入数据
void QueuePush(Queue* pq, QDataType x);

//出队列,队头    删除数据
void QueuePop(Queue* pq);

//判断队列是否为空
bool Queuempty(Queue* pq);

//取队头数据
QDataType QueueFront(Queue* pq);

//取队尾数据
QDataType QueueBack(Queue* pq);

//队列有效元素个数
int QueueSize(Queue* pq);

//队列的销毁
void QueueDestroy(Queue* pq);

补充文件Queue.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"

//初始化
void QueueInit(Queue* pq)
{
    assert(pq);//传过来的不能是空指针 

    pq->phead = pq->ptail = NULL;//空的队列
    pq->size = 0;
}

//判断队列是否为空
bool Queuempty(Queue* pq)
{
    assert(pq);

    return pq->phead == NULL && pq->ptail == NULL;
    //如果后面的表达式成立,那么就是真,返回的是true

    //就是说如果这里的是空队列的话,那么就返回的是true
}

//入队列,队尾   插入数据
void QueuePush(Queue* pq, QDataType x)
{
    assert(pq);

    //申请新节点
    QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));//申请一个节点大小的空间
    if (newnode == NULL)
    {
        perror("malloc dail!");
        exit(1);
    }
    //对newnode进行初始化操作
    newnode->data = x;
    newnode->next = NULL;
    if (pq->phead == NULL)//说明队列为空
    {
        pq->phead = pq->ptail = newnode;//那么此时的newnode不仅是头结点也是尾节点
    }
    else//队列不为空
    {
        pq->ptail->next = newnode;
        //那么此时的newnode 就是新的ptail
        pq->ptail = newnode;
    }
    pq->size++;
}

//出队列,队头    删除数据    从头结点开始删除数据
void QueuePop(Queue* pq)
{
    assert(pq);
    //队列为空(不可删除数据,因为没有数据)
    //队列不为空(可删除数据)

    assert(!Queuempty(pq));//队列为空白的话就报错

    //处理只有一个节点的情况,避免ptail变成野指针
    //判断只有一个节点的情况
    if (pq->ptail == pq->phead)//头尾指针相同,说明只有一个节点
    {
        free(pq->phead);//随便释放
        pq->phead = pq->ptail = NULL;
    }
    else//处理多个节点的情况
    {
        //删除队头元素
    //那么我们现将下个节点的位置进行保存
        QueueNode* next = pq->phead->next;
        //存储好之后我们直接将头结点进行释放
        free(pq->phead);
        pq->phead = next;//那么之前存的next就是新的头结点了
    }
    pq->size--;
}

//取队头数据
QDataType QueueFront(Queue* pq)//返回队头数据
{
    assert(pq);
    assert(!Queuempty(pq));//队列不为空

    return pq->phead->data;//将队头里面的数据直接返回就行了
}

//取队尾数据
QDataType QueueBack(Queue* pq)
{
    assert(pq);
    assert(!Queuempty(pq));//队列不为空

    return pq->ptail->data;
}

//队列有效元素个数
int QueueSize(Queue* pq)
{
    assert(pq);
    //下面这种遍历的话效率太低了
    //int size = 0;
    //定义一个指针进行遍历
        //QueueNode* pcur = pq->phead;//指向队列的头结点
        //while (pcur)//pcur不为空就往后走
        //{
        //  size++;
        //  pcur = pcur->next;
        //}
        //return size;
        return pq->size;
}

//队列的销毁
void QueueDestroy(Queue* pq)
{
    assert(pq);
    //assert(!Queuempty(pq));//队列不为空
    //遍历
    QueueNode* pcur = pq->phead;
    while (pcur)
    {
        //销毁之前先把下个节点进行保存
        QueueNode* next = pcur->next;
        free(pcur);
        //将Pcur销毁之后,那么之前保存的next就是新的头结点
        pcur = next;
    }
    pq->phead = pq->ptail = NULL;
    pq->size = 0;
}

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

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

相关文章

深入理解指针5

sizeof和strlen的对比 sizeof的功能 **sizeof是**** 操作符****&#xff0c;用来**** 计算****变量或类型或数组所占**** 内存空间大小****&#xff0c;**** 单位是字节&#xff0c;****他不管内存里是什么数据** int main() {printf("%zd\n", sizeof(char));p…

一文详解QT环境搭建:Windows使用CLion配置QT开发环境

在当今的软件开发领域&#xff0c;跨平台应用的需求日益增长&#xff0c;Qt作为一款流行的C图形用户界面库&#xff0c;因其强大的功能和易用性而备受开发者青睐。与此同时&#xff0c;CLion作为一款专为C/C打造的强大IDE&#xff0c;提供了丰富的特性和高效的编码体验。本文将…

NE 综合实验3:基于 IP 配置、链路聚合、VLAN 管理、路由协议及安全认证的企业网络互联与外网访问技术实现(H3C)

综合实验3 实验拓扑 设备名称接口IP地址R1Ser_1/0与Ser_2/0做捆绑MP202.100.1.1/24G0/0202.100.2.1/24R2Ser_1/0与Ser_2/0做捆绑MP202.100.1.2/24G0/0172.16.2.1/24G0/1172.16.1.1/24G0/2172.16.5.1/24R3G5/0202.100.2.2/24G0/0172.16.2.2/24G0/1172.16.3.1/24G0/2172.16.7.1/…

多段圆弧拟合离散点实现切线连续

使用多段圆弧来拟合一个由离散点组成的曲线,并且保证切线连续。也就是说&#xff0c;生成的每一段圆弧之间在连接点处必须有一阶导数连续&#xff0c;也就是切线方向相同。 点集分割 确保每个段的终点是下一段的起点&#xff0c;相邻段共享连接点&#xff0c;避免连接点位于数…

【蓝桥杯】第十四届C++B组省赛

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;蓝桥杯 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 试题A&#xff1a;日期统计试题B&#xff1a;01串的熵试题C&#xff1a;冶炼金属试题D&#xff1a;飞机降落试题E&#xff1a;接…

企业级海外网络专线行业应用案例及服务商推荐

在全球化业务快速发展的今天&#xff0c;传统网络技术已难以满足企业需求。越来越多企业开始选择新型海外专线解决方案&#xff0c;其中基于SD-WAN技术的企业级海外网络专线备受关注。这类服务不仅能保障跨国数据传输&#xff0c;还能根据业务需求灵活调整网络配置。接下来我们…

阿里云服务器安装docker以及mysql数据库

(1) 官方下载路径 官方下载地址: Index of linux/static/stable/x86_64/阿里云镜像地址: https://mirrors.aliyun.com/docker-ce/下载最新的 Docker 二进制文件&#xff1a;wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.23.tgz登录到阿里云服务…

深入解析:HarmonyOS Design设计语言的核心理念

深入解析&#xff1a;HarmonyOS Design设计语言的核心理念 在当今数字化迅速发展的时代&#xff0c;用户对操作系统的体验要求越来越高。华为的HarmonyOS&#xff08;鸿蒙操作系统&#xff09;应运而生&#xff0c;旨在为用户提供全场景、全设备的智慧体验。其背后的设计语言—…

dfs记忆化搜索刷题 + 总结

文章目录 记忆化搜索 vs 动态规划斐波那契数题解代码 不同路径题解代码 最长递增子序列题解代码 猜数字大小II题解代码 矩阵中的最长递增路径题解代码 总结 记忆化搜索 vs 动态规划 1. 记忆化搜索&#xff1a;有完全相同的问题/数据保存起来&#xff0c;带有备忘录的递归 2.记忆…

【Linux】进程的详讲(中上)

目录 &#x1f4d6;1.什么是进程? &#x1f4d6;2.自己写一个进程 &#x1f4d6;3.操作系统与内存的关系 &#x1f4d6;4.PCB(操作系统对进程的管理) &#x1f4d6;5.真正进程的组成 &#x1f4d6;6.形成进程的过程 &#x1f4d6;7、Linux环境下的进程知识 7.1 task_s…

优选算法的巧思之径:模拟专题

专栏&#xff1a;算法的魔法世界 个人主页&#xff1a;手握风云 目录 一、模拟 二、例题讲解 2.1. 替换所有的问号 2.2. 提莫攻击 2.3. Z字形变换 2.4. 外观数列 2.5. 数青蛙 一、模拟 模拟算法说简单点就是照葫芦画瓢&#xff0c;现在草稿纸上模拟一遍算法过程&#xf…

【云服务器】在Linux CentOS 7上快速搭建我的世界 Minecraft 服务器搭建,并实现远程联机,详细教程

【云服务器】在Linux CentOS 7上快速搭建我的世界 Minecraft 服务器搭建&#xff0c;详细详细教程 一、 服务器介绍二、下载 Minecraft 服务端三、安装 JDK 21四、搭建服务器五、本地测试连接六、添加服务&#xff0c;并设置开机自启动 前言&#xff1a; 推荐使用云服务器部署&…

文本分析(非结构化数据挖掘)——特征词选择(基于TF-IDF权值)

TF-IDF是一种用于信息检索和文本挖掘的常用加权算法&#xff0c;用于评估一个词在文档或语料库中的重要程度。它结合了词频&#xff08;TF&#xff09;和逆文档频率&#xff08;IDF&#xff09;两个指标&#xff0c;能够有效过滤掉常见词&#xff08;如“的”、“是”等&#x…

【JavaSE】小练习 —— 图书管理系统

【JavaSE】JavaSE小练习 —— 图书管理系统 一、系统功能二、涉及的知识点三、业务逻辑四、代码实现4.1 book 包4.2 user 包4.3 Main 类4.4 完善管理员菜单和普通用户菜单4.5 接着4.4的管理员菜单和普通用户菜单&#xff0c;进行操作选择&#xff08;1查找图书、2借阅图书.....…

多线程(多线程案例)(续~)

目录 一、单例模式 1. 饿汉模式 2. 懒汉模式 二、阻塞队列 1. 阻塞队列是什么 2. 生产者消费者模型 3. 标准库中的阻塞队列 4. 自实现阻塞队列 三、定时器 1. 定时器是什么 2. 标准库中的定时器 欢迎观看我滴上一篇关于 多线程的博客呀&#xff0c;直达地址&#xf…

一个判断A股交易状态的python脚本

最近在做股票数据相关的项目&#xff0c;需要用到判断某一天某个时刻A股的状态&#xff0c;比如休市&#xff0c;收盘&#xff0c;交易中等&#xff0c;发动脑筋想了一下&#xff0c;这个其实还是比较简单的&#xff0c;这里我把实现方法分享给大家。 思路 当天是否休市 对于某…

闪记(FlashNote):让灵感快速成文的轻量级笔记工具

闪记&#xff08;FlashNote&#xff09;&#xff1a;让灵感快速成文的轻量级笔记工具 你是否经常遇到这样的情况&#xff1a;桌面上放了一大堆的新建123.txt&#xff0c;想记录一个想法&#xff0c;应该是一键开个一个快捷键然后瞬间记录就自动保存了&#xff0c;现在的很多笔记…

《大模型部署》——ollama下载及大模型本地部署(详细快速部署)

ollama Ollama 是一款开源跨平台的大语言模型&#xff08;LLM&#xff09;运行工具&#xff0c;旨在简化本地部署和管理 AI 模型的流程。 下载ollama 进入官网下载https://ollama.com/ 选择需要的系统下载 下载完成后直接进行安装 下载大模型 选择想要部署的模型&#…

Geotools结合SLD实现矢量中文标注下的乱码和可用字体解析

目录 前言 一、需求溯源 1、原始的SLD渲染 2、最初的效果 二、问题修复 1、还是字符编码 2、如何选择可用的字体 3、如何查看支持的字体库 三、总结 前言 随着地理信息系统&#xff08;GIS&#xff09;技术的不断发展&#xff0c;矢量数据的可视化和标注成为了地理信息展…

基于Python与CATIA V5的斐波那契螺旋线自动化建模技术解析

引言 斐波那契螺旋线&#xff08;Fibonacci Spiral&#xff09;作为自然界广泛存在的黄金比例曲线&#xff0c;在工业设计、产品造型、机械工程等领域具有重要应用价值。本文将以Python控制CATIA V5进行参数化建模为例&#xff0c;深入解析三维CAD环境中复杂数学曲线的自动化生…