【數據結構】二叉樹接口實現指南:遞歸方法的高效運用 (附經典算法OJ)

文章目錄

1、前置說明

1、定義二叉樹結點結構

2、創建新節點

3、手動創建二叉樹

2、二叉樹的遍歷

1、前序,中序和后序遍歷

1.1、二叉樹前序遍歷

1.2、二叉樹中序遍歷

1.3、二叉樹后序遍歷

2、二叉樹層序遍歷

?3、二叉樹的基礎操作

1、二叉樹節點總數

2、葉子節點個數

3、二叉樹高度

4、二叉樹第k層節點數

5、查找目標節點

6、通過前序遍歷的數組"ABD##E#H##CF##G##"構建二叉樹

7、銷毀

4、經典算法OJ

1、單值二叉樹

2、檢查兩顆樹是否相同

3、另一棵樹的子樹


1、前置說明

前面的文章我們根據完全二叉樹的結構特點,用順序存儲的方式實現了堆相關的接口以及堆排序。下面我們用鏈式結構來實現普通二叉樹的基本操作,但在實現之前,我們需要先創建一棵二叉樹,然后才能學習相關的操作,由于我們對二叉樹的結構掌握還不夠深入,我們就先手動地創建一棵二叉樹,等我們對二叉樹的結構有了進一步的理解,再反過來實現二叉樹真正的創建。

二叉樹是: 1、空樹

2、非空:根結點,根結點的左子樹、根結點的右子樹組成的。

從概念中可以看出,二叉樹定義是遞歸式的,因此后序基本操作中基本都是按照該概念實現的。?

1、定義二叉樹結點結構

用鏈式結構實現二叉樹,節點結構就類似于鏈表的節點。同時,我們還需要兩個結構體類型的指針來連接孩子節點。

//定義二叉樹存儲的數據類型
typedef int BTDateType;
//定義節點結構
typedef struct BinaryTree
{BTDateType val;struct BinaryTree* left;struct BinaryTree* right;
}BTNode;

2、創建新節點

BTNode* BuyBTNode(BTDateType x)
{BTNode* pst = (BTNode*)malloc(sizeof(BTNode));if (pst == NULL){perror("malloc");exit(1);}pst->val = x;pst->left = NULL;pst->right = NULL;
}

3、手動創建二叉樹

BTNode* BinaryTreeCreat()
{//創建二叉樹的節點BTNode* s1 = BuyBTNode(1);BTNode* s2 = BuyBTNode(2);BTNode* s3 = BuyBTNode(3);BTNode* s4 = BuyBTNode(4);BTNode* s5 = BuyBTNode(5);BTNode* s6 = BuyBTNode(6);//連接節點成為二叉樹s1->left = s2;s2->left = s3;s2->right = s7;s1->right = s4;s4->left = s5;s4->right = s6;return s1;
}

2、二叉樹的遍歷

1、前序,中序和后序遍歷

所謂二叉樹遍歷(Traversal)是按照某種特定的規則,依次對二叉樹中的結點進行相應的操作,并且每個結點只操作一次。訪問結點所做的操作依賴于具體的應用問題。 遍歷 是二叉樹上最重要的運算之一,也是二叉樹上進行其它運算的基礎。

按照規則,二叉樹的遍歷有:前序/中序/后序的遞歸結構遍歷:

1. 前序遍歷(先序遍歷)——訪問根結點的操作發生在遍歷其左右子樹之前,根->左子樹->右子樹。

2. 中序遍歷——訪問根結點的操作發生在遍歷其左右子樹之中(間),左子樹->根->右子樹。

3. 后序遍歷——訪問根結點的操作發生在遍歷其左右子樹之后,左子樹->右子樹->根。

由于被訪問的結點必是某子樹的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解釋為 根、根的左子樹和根的右子樹。NLR、LNR和LRN分別又稱為先根遍歷、中根遍歷和后根遍歷。?

// 二叉樹前序遍歷 
void prevOrder(BTNode* root);
// 二叉樹中序遍歷
void midOrder(BTNode* root);
// 二叉樹后序遍歷
void afterOrder(BTNode* root);

1.1、二叉樹前序遍歷

前序遍歷遞歸圖解:

//前序遍歷:根  左子樹  右子樹
void prevOrder(BTNode* root)
{//打印空節點if (root == NULL){printf("N ");return;}//打印根節點的值printf("%d ", root->val);//遞歸遍歷左子樹prevOrder(root->left);//遞歸遍歷右子樹prevOrder(root->right);
}

輸出結果:

1 2 3 N N N 4 5 N N 6 N N

為了能夠更加直觀的理解遞歸調用的過程,我們畫圖來感受一下,后面用遞歸實現接口的過程中,我們也可以用類似的方法來畫圖,幫助我們理解!!!

1.2、二叉樹中序遍歷

//中序遍歷:左子樹  根  右子樹
void midOreder(BTNode* root)
{   //打印空節點if (root == NULL){printf("N ");return;}//遞歸遍歷左子樹midOreder(root->left);//打印根節點的值printf("%d ", root->val);//遞歸遍歷右子樹midOreder(root->right);
}

輸出結果

N 3 N 2 N 1 N 5 N 4 N 6 N

1.3、二叉樹后序遍歷

//后序遍歷:左子樹  右子樹  根
void afterOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}//遞歸遍歷左子樹afterOrder(root->left);//遞歸遍歷右子樹afterOrder(root->right);//打印根節點的值printf("%d ", root->val);
}

輸出結果

N N 3 N 2 N N 5 N N 6 4 1

2、二叉樹層序遍歷

層序遍歷:除了先序遍歷、中序遍歷、后序遍歷外,還可以對二叉樹進行層序遍歷。設二叉樹的根結點所在 層數為1,層序遍歷就是從所在二叉樹的根結點出發,首先訪問第一層的樹根結點,然后從左到右訪問第2層 上的結點,接著是第三層的結點,以此類推,自上而下,自左至右逐層訪問樹的結點的過程就是層序遍歷。

?3、二叉樹的基礎操作

1、二叉樹節點總數

思路1:遍歷二叉樹,創建一個變量來記錄節點個數,但是,每次函數調用都是在棧區開辟空間,數據在函數調用結束后就會銷毀,所以要創建全局變量,或者用static修飾的全局變量(但是在調用之前需要初始化為0)。當遇到某個節點的左孩子或者右孩子為空時,遞歸結束,開始返回。

int size = 0;//全局變量
//static int size = 0;int TreeSize(BTNode* root)
{//遞歸結束,遇到空樹,返回if (root == NULL)return 0;else++size;//遍歷二叉樹TreeSize(root->left);TreeSize(root->right);return size;
}

還有一種簡單的寫法,用三目操作符來判斷,但是不容易理解

int TreeSize(BTNode* root)
{return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}

遞歸調用圖解:?

?思路2:將size作為實參,但是為了讓形參改變的同時改變實參的值,我們需要傳實參的地址。

//將size作為參數
void TreeSize(BTNode* root, int* psize)
{if (root == NULL)return 0;else++(*psize);TreeSize(root->left, psize);TreeSize(root->right, psize);
}

2、葉子節點個數

思路:遍歷二叉樹,將二叉樹不斷分為左子樹與右子樹,找左孩子與右孩子都不存在的節點,即葉子節點,然后將所有左子樹與右子樹的葉子節點加起來。

//計算葉子節點個數
int TreeLeafCount(BTNode* root)
{//遇到空節點,遞歸結束條件if (root == NULL){return 0;}//當左子樹與右子樹同時為空時為葉子節點if ((root->left == NULL) && (root->right == NULL)){return 1;}//葉子節點數等于左子樹+右子樹return TreeLeafCount(root->left) + TreeLeafCount(root->right);
}

3、二叉樹高度

思路:遞歸遍歷二叉樹的左子樹與右子樹的同時,記下左子樹與右子樹的高度,然后比較左子樹與右子樹,二叉樹的高度就是較高的一個加上根節點的高度。

//計算二叉樹高度
int TreeHeight(BTNode* root)
{//遞歸結束條件if (root == NULL){return 0;}//記下返回值,防止造成時間效率低下//左子樹高度int leftheight = TreeHeight(root->left);//右子樹高度int rightheight = TreeHeight(root->right);//高度為較大的高度+根節點的高度if (leftheight > rightheight)return leftheight + 1;elsereturn rightheight + 1;//三目操作符//return leftheight > rightheight ? leftheight + 1 : rightheight + 1;
}

4、二叉樹第k層節點數

思路:計算二叉樹第k層節點數,遞歸遍歷二叉樹的左子樹與右子樹,計算第k-1層的節點的不為空的左孩子和右孩子的個數,返回左子樹與右子樹k-1層的節點的不為空的左孩子和右孩子的個數的和。

//計算第k層有多少個節點
int TreeNodecount_k(BTNode* root, int k)
{//遞歸結束條件if (root == NULL)return 0;//處理特殊情況if (k == 1)return 1;//注意不能使用k--或者--k,這樣遞歸一次,后一次調用相當于k-1-1return TreeNodecount_k(root->left, k - 1) + TreeNodecount_k(root->right, k - 1);
}

5、查找目標節點

遞歸遍歷左子樹與右子樹

//查找目標節點
BTNode* TreeFind(BTNode* root, BTDateType x)
{if (root == NULL)return NULL;if (root->val == x){return root;}//記下返回值BTNode* ret1 = TreeFind(root->left, x);//找到了,就返回if (ret1)return ret1;BTNode* ret2 = TreeFind(root->right, x);if (ret2)return ret2;return NULL;
}

6、通過前序遍歷的數組"ABD##E#H##CF##G##"構建二叉樹

//定義二叉樹存儲的數據類型
typedef char BTDateType;

?ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空樹。

//創建一顆二叉樹
BTNode* CreatTree(char* a, int* pi)
{//遞歸結束條件,同時處理空樹if (a[*pi] == '#'){(*pi)++;return NULL;}//不是'#'就為節點開辟空間BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));newnode->val = a[(*pi)++];//遞歸遍歷數組newnode->left = CreatTree(a, pi);newnode->right = CreatTree(a, pi);return newnode;
}int main()
{char arr[] = { "ABD##E#H##CF##G##" };int i = 0;BTNode* root = CreatTree(arr, &i);return 0;
}

7、銷毀

思路:遞歸遍歷二叉樹,用后序遍歷,防止將根釋放而找不到左子樹與右子樹。

//銷毀二叉樹
//后序遍歷:左子樹->右子樹->根,防止將根釋放而找不到左子樹與右子樹
void TreeDestry(BTNode* root)
{if (root == NULL){return;}//遞歸遍歷左子樹TreeDestry(root->left);//遞歸遍歷右子樹TreeDestry(root->right);free(root);
}

4、完整源碼?

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<math.h>
#include"Queue.h"//定義二叉樹的節點
typedef int BTDateType;
typedef struct BinaryTree
{BTDateType val;struct BinaryTree* left;struct BinaryTree* right;
}BTNode;BTNode* BuyBTNode(BTDateType x)
{BTNode* pst = (BTNode*)malloc(sizeof(BTNode));if (pst == NULL){perror("malloc");exit(1);}pst->val = x;pst->left = NULL;pst->right = NULL;
}
BTNode* BinaryTreeCreat()
{//創建一棵樹BTNode* s1 = BuyBTNode(1);BTNode* s2 = BuyBTNode(2);BTNode* s3 = BuyBTNode(3);BTNode* s4 = BuyBTNode(4);BTNode* s5 = BuyBTNode(5);BTNode* s6 = BuyBTNode(6);BTNode* s7 = BuyBTNode(7);s1->left = s2;s2->left = s3;s2->right = s7;s1->right = s4;s4->left = s5;s4->right = s6;//s5->right = s7;return s1;
}
//前序遍歷:根  左子樹  右子樹
void prevOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}printf("%d ", root->val);prevOrder(root->left);prevOrder(root->right);
}//中序遍歷:左子樹  根  右子樹
void midOreder(BTNode* root)
{if (root == NULL){printf("N ");return;}midOreder(root->left);printf("%d ", root->val);midOreder(root->right);
}
//后序遍歷:左子樹  右子樹  根
void afterOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}afterOrder(root->left);afterOrder(root->right);printf("%d ", root->val);
}//計算節點總數
//每次函數調用都是在棧區開辟空間,數據在函數調用結束后就會銷毀,所以要創建全局變量,或者用static修飾的全局變量(但是在調用之前需要初始化為0)//錯誤示范:static修飾的變量在函數作用域內,又static修飾的變量不會銷毀,所以在main函數中反復調用會導致結果不斷增加
//int TreeNodeCount(BTNode* root)
//{
//	static int size = 0;
//	if (root == NULL)
//	{
//		return 0;
//	}
//	size++;
//	TreeNodeCount(root->left);
//	TreeNodeCount(root->right);
//	return size;
//}int size = 0;//全局變量
//static int size = 0;int TreeSize(BTNode* root)
{if (root == NULL)return 0;else++size;TreeSize(root->left);TreeSize(root->right);return size;
}////將size作為參數
//void TreeSize(BTNode* root, int* psize)
//{
//	if (root == NULL)
//		return 0;
//	else
//		++(*psize);
//
//	TreeSize(root->left, psize);
//	TreeSize(root->right, psize);
//}//int TreeSize(BTNode* root)
//{
//	return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
//}//計算葉子節點個數
int TreeLeafCount(BTNode* root)
{if (root == NULL){return 0;}if ((root->left == NULL) && (root->right == NULL)){return 1;}return TreeLeafCount(root->left) + TreeLeafCount(root->right);
}//計算二叉樹高度
int TreeHeight(BTNode* root)
{if (root == NULL){return 0;}//記下返回值,防止造成時間效率低下int leftheight = TreeHeight(root->left);int rightheight = TreeHeight(root->right);//高度為較大的高度+根節點的高度if (leftheight > rightheight)return leftheight + 1;elsereturn rightheight + 1;//三目操作符//return leftheight > rightheight ? leftheight + 1 : rightheight + 1;
}////使用fmax()函數求較大的值
//int TreeHeight(BTNode* root)
//{
//	if (root == NULL)
//		return 0;
//
//	return fmax(TreeHeight(root->left), TreeHeight(root->right)) + 1;
//}//計算第k層有多少個節點
int TreeNodecount_k(BTNode* root, int k)
{if (root == NULL)return 0;if (k == 1)return 1;//注意不能使用k--或者--k,這樣遞歸一次,后一次調用相當于k-1-1return TreeNodecount_k(root->left, k - 1) + TreeNodecount_k(root->right, k - 1);
}//查找目標節點
BTNode* TreeFind(BTNode* root, BTDateType x)
{if (root == NULL)return NULL;if (root->val == x){return root;}//記下返回值BTNode* ret1 = TreeFind(root->left, x);//找到了,就返回if (ret1)return ret1;BTNode* ret2 = TreeFind(root->right, x);if (ret2)return ret2;return NULL;
}//銷毀二叉樹
//后序遍歷:左子樹->右子樹->根,防止將根釋放而找不到左子樹與右子樹
void TreeDestry(BTNode* root)
{if (root == NULL){return;}TreeDestry(root->left);TreeDestry(root->right);free(root);
}//測試
int main()
{BTNode* root = BinaryTreeCreat();//前序遍歷prevOrder(root);printf("\n");//中序遍歷midOreder(root);printf("\n");//后序遍歷afterOrder(root);printf("\n");//計算二叉樹節點總個數//size = 0;//printf("TreeSize:%d\n", TreeSize(root));//size = 0;//printf("TreeSize:%d\n", TreeSize(root));//size = 0;//printf("TreeSize:%d\n", TreeSize(root));//int size = 0;//TreeSize(root, &size);//printf("TreeSize:%d\n", size);//size = 0;//TreeSize(root, &size);//printf("TreeSize:%d\n", size);//printf("%d ", TreeSize(root));//printf("%d ", TreeSize(root));//求葉子節點的個數//printf("%d\n", TreeLeafCount(root));////求二叉樹的高度//printf("%d\n", TreeHeight(root));////求二叉樹第k層有多少個節點//printf("%d\n",TreeNodecount_k(root, 3));////查找目標節點//BTNode* ret = TreeFind(root, 5);//printf("%d\n", ret->val);return 0;
}

5、經典算法OJ

1、單值二叉樹

965. 單值二叉樹 - 力扣(LeetCode)

題目描述:

示例:?

bool _isUnivalTree(struct TreeNode* root,int x) 
{  //處理空樹情況,同時為遞歸結束條件if(root==NULL){return true;}//排除空樹,且只要不等于根結點的值,就返回falseif(root->left&&root->left->val!=x){return false;}if(root->right&&root->right->val!=x){return false;}//遞歸遍歷左子樹與右子樹return _isUnivalTree(root->left, x)&&_isUnivalTree(root->right,x);
}bool isUnivalTree(struct TreeNode* root) 
{return _isUnivalTree(root,root->val);
}

2、檢查兩顆樹是否相同

100. 相同的樹 - 力扣(LeetCode)

題目描述:

示例:?

?首先判斷如果都是空樹時返回真;一個為空一個不為空時返回false;值不相等,返回false。然后遞歸遍歷左子樹和右子樹,左子樹與左子樹比較,右子樹與右子樹比較,當遞歸到都是空時返回true(與剛開始的判空對應),遞歸到一個為空一個不為空時返回false(與剛開始的判斷一個為空一個不為空對應),最后左子樹與左子樹相等且右子樹與右子樹相等則返回true;反之,返回false。

bool isSameTree(struct TreeNode* p, struct TreeNode* q) 
{//都是空樹或遞歸到都是空時返回真if(p==NULL&&q==NULL){return true;}//一個為空一個不為空或遞歸到一個為空一個不為空時返回falseif(p==NULL||q==NULL){return false;}//值不相等,返回falseif(p->val!=q->val){return false;}//遞歸遍歷左子樹和右子樹,左子樹與左子樹比較,右子樹與右子樹比較return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}

3、另一棵樹的子樹

572. 另一棵樹的子樹 - 力扣(LeetCode)

題目描述:

?不斷遞歸遍歷一棵樹的左子樹和右子樹,然后判斷這棵樹的左子樹與右子樹與另一棵樹是否相等。可以借助前面實現的判斷兩棵樹是否相等的函數。?

bool isSameTree(struct TreeNode*p,struct TreeNode*q)
{//都為空if(p==NULL&&q==NULL){return true;}//一個為空,一個不為空if(p==NULL||q==NULL){return false;}if(p->val!=q->val){return false;}return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot) 
{if(root==NULL){return false;}if((root->val==subRoot->val) && (isSameTree(root,subRoot))){ return true;}//將root拆分為左子樹和右子樹與subRoot比較return isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/91974.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/91974.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/91974.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

自動駕駛控制算法——LQR控制算法

自動駕駛控制算法——LQR控制算法 文章目錄自動駕駛控制算法——LQR控制算法**一、LQR 是什么&#xff1f;**二、LQR 原理2.1 線性狀態空間模型 (State–Space Model)2.2 二次型性能指標 JJJ2.3 代數黎卡提方程 (ARE)2.4 特點總結2.5 一句話總結 LQR 原理&#xff1a;2.5.1 場景…

Jotai:React輕量級原子化狀態管理,告別重渲染困擾

簡介 Jotai 是一個為 React 提供的原子化狀態管理庫&#xff0c;采用自下而上的方法來進行狀態管理。Jotai 受 Recoil 啟發&#xff0c;通過組合原子來構建狀態&#xff0c;并且渲染基于原子依賴性進行優化。這解決了 React 上下文的額外重新渲染問題&#xff0c;并消除了對 m…

C語言數據結構(7)貪吃蛇項目2.貪吃蛇項目實現

8. 核心邏輯實現分析 8.1 游戲主邏輯 程序開始就設置程序支持本地模式&#xff0c;然后進入程序的主邏輯。 主邏輯分為3個過程&#xff1a; ? 游戲開始&#xff08;GameStart&#xff09;完成游戲的初始化。 ? 游戲運行&#xff08;GameRun&#xff09;完成游戲運行邏輯的…

知識蒸餾 - 最小化KL散度與最小化交叉熵是完全等價的

知識蒸餾 - 最小化KL散度與最小化交叉熵是完全等價的 flyfish KL散度與交叉熵的數學關系 對于兩個概率分布 PPP&#xff08;真實分布&#xff09;和 QQQ&#xff08;模型預測分布&#xff09;&#xff0c;KL散度的定義是&#xff1a; DKL(P∥Q)∑xP(x)log?(P(x)Q(x)) D_{KL}(P…

設計心得——網絡包的處理

一、介紹 在程序的開發中&#xff0c;網絡開發是一個重要的應用場景。畢竟這些年IT行業之所以火&#xff0c;主要還是互聯網&#xff08;移動互聯網&#xff09;帶來的。網絡開發&#xff0c;有各種平臺、框架以及系統和庫提供的API&#xff0c;如果說網絡開發是一個特別復雜和…

sqli-labs通關筆記-第30關GET字符注入(WAF繞過 雙引號閉合 手工注入+腳本注入兩種方法)

目錄 一、源碼分析 1、index.php代碼審計 2、login.php代碼審計 3、java_implimentation函數 4、whitelist函數 5、SQL安全性分析 二、滲透實戰 1、進入靶場 2、WAF探測 &#xff08;1&#xff09;觸發WAF &#xff08;2&#xff09;繞過WAF 3、手工注入 &#xf…

【openlayers框架學習】九:openlayers中的交互類(select和draw)

文章目錄openlayers進階28 openlayers中的事件29 openlayers中select交互類的使用30 openlayers中select常見的配置選項31 openlayers中繪制交互類&#xff08;Draw&#xff09;openlayers進階 28 openlayers中的事件 常用進行事件交互的對象&#xff1a;map\view\source29 o…

Java企業級應用性能優化實戰

在企業級Java應用開發中,性能優化是確保系統穩定運行的關鍵因素。本文將從多個維度深入分析Java應用性能瓶頸,并提供實戰優化方案。 ?? 性能優化核心領域 1. 對象操作性能優化 在企業應用中,對象拷貝是一個高頻操作,特別是在分層架構中的DO、DTO、VO轉換。選擇合適的拷…

LLM Prompt與開源模型資源(3)如何寫一個好的 Prompt

學習材料&#xff1a;https://www.hiascend.com/developer/courses/detail/1935520434893606913 &#xff08;3.5&#xff09;學習時長&#xff1a; 預計 60 分鐘學習目的&#xff1a; 了解提示工程的定義與作用熟悉提示工程的關鍵技術相關概念掌握基于昇騰適配的大模型提示工程…

日志管理工具 ——ELK Stack

一、ELK Stack 概述1.1 核心組件ELK Stack&#xff08;現更名為 Elastic Stack&#xff09;是一套開源的日志收集、存儲、分析和可視化平臺&#xff0c;由三個核心組件構成&#xff1a;Elasticsearch&#xff1a;分布式搜索引擎&#xff0c;負責日志數據的存儲、索引和快速查詢…

SpringAI:AI工程應用框架新選擇

Spring AI 是一個用于 AI 工程的應用框架 Spring AI 是一個用于 AI 工程的應用框架。其目標是將可移植性和模塊化設計等 Spring 生態系統設計原則應用于 AI 領域,并推廣使用 POJO 作為應用程序的構建塊到 AI 領域。 Spring AI 的核心是解決 AI 集成的基本挑戰:將企業數據和…

Kettle 開源ETL數據遷移工具從入門到實戰

ETL&#xff08;Extract, Transform, Load&#xff09;工具是用于數據抽取、轉換和加載的軟件工具&#xff0c;用于支持數據倉庫和數據集成過程。Kettle作為傳統的ETL工具是純 java 開發的開源的 ETL工具&#xff0c;用于數據庫間的數據遷移 。可以在 Linux、windows、unix 中運…

Maven中的bom和父依賴

maven最全避坑指南寫完后&#xff0c;發現自己對于bom和父pom的理解還是不夠深入&#xff0c;特此轉載DeepSeek的回答&#xff0c;和大家一起學習了。 在 Maven 的依賴管理中&#xff0c;父 POM (Parent POM) 和 BOM (Bill of Materials) 都是用于實現集中化管理和控制的核心機…

Python 操作 Word 文檔:主流庫對比與選擇指南

在辦公自動化、報告生成、數據處理等領域&#xff0c;利用 Python 程序化地創建、讀取或修改 Microsoft Word 文檔 (.docx 格式) 是一項非常實用的技能。Python 生態中有多個優秀的庫可以完成這項任務&#xff0c;但它們各有側重和優缺點。選擇哪一個“最好用”&#xff0c;關鍵…

怎么修改論文格式呢?提供一份論文格式模板

注!!!本文內容是作者自己整理的一份模板,僅供參考,各位如何修改,還需要看學校的要求。 一、參考文獻 1、有一定數量的近幾年參考文獻、不宜過多中文文獻 英文期刊模板 [1] Taesoo K, Sooyoung K, Kyunghan L, et al. Special issue on 6G and satellite communication…

MVC 發布

MVC 發布 引言 MVC(Model-View-Controller)模式是一種廣泛應用于軟件開發的架構模式。它將應用程序分為三個主要部分:模型(Model)、視圖(View)和控制器(Controller)。這種模式不僅提高了代碼的可維護性和可擴展性,而且使得開發者可以更加專注于各個組件的開發。本文…

arkui 動畫曲線

參考文檔 https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-curve#curvesinterpolatingspring10 可視化工具網站 https://easingwizard.com/ https://www.desmos.com/calculator/k01p40v0ct?langzh-CN 基本介紹 import { curves } from kit.A…

大語言模型(LLM)技術架構與工程實踐:從原理到部署

在自然語言處理領域,大語言模型(LLM)已成為顛覆性技術。從 GPT 系列到 LLaMA、ChatGLM,這些參數規模動輒百億甚至萬億的模型,不僅實現了流暢的自然語言交互,更在代碼生成、邏輯推理等復雜任務中展現出驚人能力。本文將從技術底層拆解 LLM 的核心架構,分析訓練與推理的關…

python后端之DRF框架(上篇)

一、DRF框架介紹 1、web應用開發模式 1.1、前后端不分離1.2、前后端分離2、RESTful介紹 RESTful是目前最流行的API設計風格 &#xff0c; REST 指的是一組架構約束條件和原則。滿足這些約束條件和原則的應用程序或設計就是 RESTful。 1、每一個URI代表1種資源&#xff1b; 2、客…

信創數據庫-DM(達夢)數據庫安裝教程

官方安裝文檔在這&#xff1a;安裝前準備 | 達夢技術文檔 本文也是基于這個來寫的&#xff0c;微調了一下。 1&#xff0c;下載安裝包 體驗版直接到官方下載即可&#xff1a;產品下載 | 達夢在線服務平臺 如果是有需要商業版等&#xff0c;需要聯系客服申請。 安裝包要選擇CPU…