C語言數(shù)據(jù)結(jié)構(gòu)之二叉樹詳解
1. 樹概念及結(jié)構(gòu)
1.1樹概念
樹是一種非線性的數(shù)據(jù)結(jié)構(gòu),它是由n(n>=0)個有限結(jié)點(diǎn)組成一個具有層次關(guān)系的集合。把它叫做樹是因?yàn)樗雌饋硐褚豢玫箳斓臉?,也就是說它是根朝上,而葉朝下的。
- 根結(jié)點(diǎn):根節(jié)點(diǎn)沒有前驅(qū)結(jié)點(diǎn)。
- 除根節(jié)點(diǎn)外,其余結(jié)點(diǎn)被分成是一棵結(jié)構(gòu)與樹類似的子樹。每棵子樹的根結(jié)點(diǎn)有且只有一個前驅(qū),可以有0個或多個后繼。
- 因此,樹是遞歸定義的。
- 節(jié)點(diǎn)的度:一個節(jié)點(diǎn)含有的子樹的個數(shù)稱為該節(jié)點(diǎn)的度; 如上圖:A的為2
- 葉節(jié)點(diǎn):度為0的節(jié)點(diǎn)稱為葉節(jié)點(diǎn); 如上圖:G、H、I節(jié)點(diǎn)為葉節(jié)點(diǎn)
- 非終端節(jié)點(diǎn)或分支節(jié)點(diǎn):度不為0的節(jié)點(diǎn); 如上圖:B、D、C、E、F節(jié)點(diǎn)為分支節(jié)點(diǎn)
- 雙親節(jié)點(diǎn)或父節(jié)點(diǎn):若一個節(jié)點(diǎn)含有子節(jié)點(diǎn),則這個節(jié)點(diǎn)稱為其子節(jié)點(diǎn)的父節(jié)點(diǎn); 如上圖:A是B的父節(jié)點(diǎn)
- 孩子節(jié)點(diǎn)或子節(jié)點(diǎn):一個節(jié)點(diǎn)含有的子樹的根節(jié)點(diǎn)稱為該節(jié)點(diǎn)的子節(jié)點(diǎn); 如上圖:B是A的孩子節(jié)點(diǎn)
- 兄弟節(jié)點(diǎn):具有相同父節(jié)點(diǎn)的節(jié)點(diǎn)互稱為兄弟節(jié)點(diǎn); 如上圖:B、C是兄弟節(jié)點(diǎn)
- 樹的度:一棵樹中,最大的節(jié)點(diǎn)的度稱為樹的度; 如上圖:樹的度為2
- 節(jié)點(diǎn)的層次:從根開始定義起,根為第1層,根的子節(jié)點(diǎn)為第2層,以此類推;
- 樹的高度或深度:樹中節(jié)點(diǎn)的最大層次; 如上圖:樹的高度為4
- 堂兄弟節(jié)點(diǎn):雙親在同一層的節(jié)點(diǎn)互為堂兄弟;如上圖:H、I互為兄弟節(jié)點(diǎn)
- 節(jié)點(diǎn)的祖先:從根到該節(jié)點(diǎn)所經(jīng)分支上的所有節(jié)點(diǎn);如上圖:A是所有節(jié)點(diǎn)的祖先
- 子孫:以某節(jié)點(diǎn)為根的子樹中任一節(jié)點(diǎn)都稱為該節(jié)點(diǎn)的子孫。如上圖:所有節(jié)點(diǎn)都是A的子孫
- 森林:由m棵互不相交的樹的集合稱為森林;
1.2樹的表示
樹結(jié)構(gòu)相對線性表就比較復(fù)雜了,要存儲表示起來就比較麻煩了,實(shí)際中樹有很多種表示方式,如:雙親表示法,孩子表示法、孩子兄弟表示法等等。我們這里就簡單的了解其中最常用的孩子兄弟表示法。
typedef int DataType; struct Node { struct Node* firstChild1; struct Node* pNextBrother; DataType data; };
2. 二叉樹概念及結(jié)構(gòu)
2.1概念
一棵二叉樹是結(jié)點(diǎn)的一個有限集合,該集合或者為空,或者是由一個根節(jié)點(diǎn)加上兩棵別稱為左子樹和右子樹的二叉樹組成。
二叉樹的特點(diǎn):
- 每個結(jié)點(diǎn)最多有兩棵子樹,即二叉樹不存在度大于2的結(jié)點(diǎn)。
- 二叉樹的子樹有左右之分,其子樹的次序不能顛倒。
2.2數(shù)據(jù)結(jié)構(gòu)中的二叉樹
2.3特殊的二叉樹
滿二叉樹:一個二叉樹,如果每一個層的結(jié)點(diǎn)數(shù)都達(dá)到最大值,則這個二叉樹就是滿二叉樹。也就是說,如果一個二叉樹的層數(shù)為K,且結(jié)點(diǎn)總數(shù)是(2^k) -1 ,則它就是滿二叉樹。
完全二叉樹:完全二叉樹是效率很高的數(shù)據(jù)結(jié)構(gòu),完全二叉樹是由滿二叉樹而引出來的。對于深度為K的,有n個結(jié)點(diǎn)的二叉樹,當(dāng)且僅當(dāng)其每一個結(jié)點(diǎn)都與深度為K的滿二叉樹中編號從1至n的結(jié)點(diǎn)一一對應(yīng)時稱之為完全二叉樹。 要注意的是滿二叉樹是一種特殊的完全二叉樹。
2.4二叉樹的存儲結(jié)構(gòu)
二叉樹一般可以使用兩種存儲結(jié)構(gòu),一種順序結(jié)構(gòu),一種鏈?zhǔn)浇Y(jié)構(gòu)。
2.4.1順序存儲
順序結(jié)構(gòu)存儲就是使用數(shù)組來存儲,一般使用數(shù)組只適合表示完全二叉樹,因?yàn)椴皇峭耆鏄鋾锌臻g的浪費(fèi)。而現(xiàn)實(shí)中使用中只有堆才會使用數(shù)組來存儲。二叉樹順序存儲在物理上是一個數(shù)組,在邏輯上是一顆二叉樹。
2.4.2鏈?zhǔn)酱鎯?/strong>
二叉樹的鏈?zhǔn)酱鎯Y(jié)構(gòu)是指,用鏈表來表示一棵二叉樹,即用鏈來指示元素的邏輯關(guān)系。 通常的方法是鏈表中每個結(jié)點(diǎn)由三個域組成,數(shù)據(jù)域和左右指針域,左右指針分別用來給出該結(jié)點(diǎn)左孩子和右孩子所在的鏈結(jié)點(diǎn)的存儲地址 。鏈?zhǔn)浇Y(jié)構(gòu)又分為二叉鏈和三叉鏈,當(dāng)前我們學(xué)習(xí)中一般都是二叉鏈,后面課程學(xué)到高階數(shù)據(jù)結(jié)構(gòu)如紅黑樹等會用到三叉鏈。
// 二叉鏈 struct BinaryTreeNode { struct BinTreeNode* _pLeft; // 指向當(dāng)前節(jié)點(diǎn)左孩子 struct BinTreeNode* _pRight; // 指向當(dāng)前節(jié)點(diǎn)右孩子 BTDataType _data; // 當(dāng)前節(jié)點(diǎn)值域 } // 三叉鏈 struct BinaryTreeNode { struct BinTreeNode* _pParent; // 指向當(dāng)前節(jié)點(diǎn)的雙親 struct BinTreeNode* _pLeft; // 指向當(dāng)前節(jié)點(diǎn)左孩子 struct BinTreeNode* _pRight; // 指向當(dāng)前節(jié)點(diǎn)右孩子 BTDataType _data; // 當(dāng)前節(jié)點(diǎn)值域 };
2.5二叉樹的性質(zhì)
- 若規(guī)定根節(jié)點(diǎn)的層數(shù)為1,則一棵非空二叉樹的第i層上最多有2^(i-1) 個結(jié)點(diǎn).
- 若規(guī)定根節(jié)點(diǎn)的層數(shù)為1,則深度為h的二叉樹的最大結(jié)點(diǎn)數(shù)是2^h- 1.
- 對任何一棵二叉樹, 如果度為0其葉結(jié)點(diǎn)個數(shù)為 n0, 度為2的分支結(jié)點(diǎn)個數(shù)為 n2,則有n0=n2+1
- 若規(guī)定根節(jié)點(diǎn)的層數(shù)為1,具有n個結(jié)點(diǎn)的滿二叉樹的深度,h=Log2(n+1). (ps:Log2(n+1)是log以2為
- 底,n+1為對數(shù))
- 對于具有n個結(jié)點(diǎn)的完全二叉樹,如果按照從上至下從左至右的數(shù)組順序?qū)λ泄?jié)點(diǎn)從0開始編號,則對于序號為i的結(jié)點(diǎn)有:
1. 若i>0,i位置節(jié)點(diǎn)的雙親序號:(i-1)/2;i=0,i為根節(jié)點(diǎn)編號,無雙親節(jié)點(diǎn)
2. 若2i+1<n,左孩子序號:2i+1,2i+1>=n否則無左孩子
3. 若2i+2<n,右孩子序號:2i+2,2i+2>=n否則無右孩子
3. 二叉樹順序結(jié)構(gòu)及概念
3.1二叉樹的順序結(jié)構(gòu)
普通的二叉樹是不適合用數(shù)組來存儲的,因?yàn)榭赡軙嬖诖罅康目臻g浪費(fèi)。而完全二叉樹更適合使用順序結(jié)構(gòu)存儲?,F(xiàn)實(shí)中我們通常把堆(一種二叉樹)使用順序結(jié)構(gòu)的數(shù)組來存儲,需要注意的是這里的堆和操作系統(tǒng)虛擬進(jìn)程地址空間中的堆是兩回事,一個是數(shù)據(jù)結(jié)構(gòu),一個是操作系統(tǒng)中管理內(nèi)存的一塊區(qū)域分段。
3.2堆的概念及結(jié)構(gòu)
如果有一個關(guān)鍵碼的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉樹的順序存儲方式存儲在一個一維數(shù)組中,并滿足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,則稱為小堆(或大堆)。將根節(jié)點(diǎn)最大的堆叫做最大堆或大根堆,根節(jié)點(diǎn)最小的堆叫做最小堆或小根堆。
堆的性質(zhì):
- 堆中某個節(jié)點(diǎn)的值總是不大于或不小于其父節(jié)點(diǎn)的值;
- 堆總是一棵完全二叉樹。
3.3堆的實(shí)現(xiàn)
typedef int HPDataType; typedef struct Heap { HPDataType* _a; int _size; int _capacity; }Heap; void swap(int *a, int *b); void AdjustDown(int *a, int parent, int n); void AdjustUp(int *a, int child, int n); // 堆的構(gòu)建 void HeapCreate(Heap* hp, HPDataType* a, int n); // 堆的銷毀 void HeapDestory(Heap* hp); // 堆的插入 void HeapPush(Heap* hp, HPDataType x); // 堆的刪除 void HeapPop(Heap* hp); // 取堆頂?shù)臄?shù)據(jù) HPDataType HeapTop(Heap* hp); // 堆的數(shù)據(jù)個數(shù) int HeapSize(Heap* hp); // 堆的判空 int HeapEmpty(Heap* hp); // 對數(shù)組進(jìn)行堆排序 void HeapSort(int* a, int n);
void swap(int *a, int *b) { int tmp = *a; *a = *b; *b = tmp; } void AdjustUp(int *a, int child, int n) { int parent = (child - 1) / 2; while (child > 0) { if (a[child] > a[parent]) { swap(&a[child], &a[parent]); child = parent; parent = (child - 1) / 2; } else { break; } } } void AdjustDown(int *a, int parent,int n) { int child = parent * 2 + 1; while ( child < n) { if (child + 1 < n && a[child]<a[child + 1]) { ++child; } if(a[child]>a[parent]) { swap(&a[child], &a[parent]); parent = child; child = (parent * 2) + 1; } else { break; } } } void HeapCreate(Heap* hp, HPDataType* a, int n) { assert(hp); hp->_a = (HPDataType*)malloc(sizeof(HPDataType)*n); if (hp->_a == NULL) { printf("malloc fail"); exit(-1); } for (int i = 0; i < n; ++i) { hp->_a[i] = a[i]; } hp->_size = hp->_capacity = n; for (int i = (n - 2) / 2; i >= 0; --i) { AdjustDown(hp->_a,i, hp->_size); } } // 堆的銷毀 void HeapDestory(Heap* hp) { assert(hp); hp->_size = hp->_capacity = 0; free(hp); } // 堆的插入 void HeapPush(Heap* hp, HPDataType x) { assert(hp); if (hp->_size == hp->_capacity) { HPDataType* tmp = (HPDataType*)realloc(hp->_a, sizeof(HPDataType)* 2 * hp->_capacity); if (tmp == NULL) { printf("realloc fail"); exit(-1); } hp->_a = tmp; hp->_a[hp->_size] = x; ++hp->_size; hp->_capacity *= 2; } else { hp->_a[hp->_size] = x; ++hp->_size; } AdjustUp(hp->_a, hp->_size-1, hp->_size); } // 堆的刪除 void HeapPop(Heap* hp) { assert(hp); assert(hp->_size>0); swap(&hp->_a[hp->_size-1], &hp->_a[0]); --hp->_size; AdjustDown(hp->_a, 0, hp->_size); } // 取堆頂?shù)臄?shù)據(jù) HPDataType HeapTop(Heap* hp) { assert(hp); assert(hp->_size>0); return hp->_a[0]; } // 堆的數(shù)據(jù)個數(shù) int HeapSize(Heap* hp) { assert(hp); return hp->_size; } // 堆的判空 int HeapEmpty(Heap* hp) { assert(hp); return hp->_size == 0 ? 1 : 0; for (int i = 0; i < 3; ++i)} // 對數(shù)組進(jìn)行堆排序 void HeapSort(int* a, int n) { assert(a); for (int i = (n - 2) / 2; i >= 0; --i) { AdjustDown(a, i, n); } int end = n - 1; while (end > 0) { swap(&a[0], &a[end]); AdjustDown(a, 0, end); --end; } }
4. 二叉樹鏈?zhǔn)浇Y(jié)構(gòu)及實(shí)現(xiàn)
4.1二叉樹鏈?zhǔn)浇Y(jié)構(gòu)的遍歷
所謂遍歷(Traversal)是指沿著某條搜索路線,依次對樹中每個結(jié)點(diǎn)均做一次且僅做一次訪問。訪問結(jié)點(diǎn)所做的操作依賴于具體的應(yīng)用問 題。 遍歷是二叉樹上最重要的運(yùn)算之一,是二叉樹上進(jìn)行其它運(yùn)算之基礎(chǔ)。
前序/中序/后序的遞歸結(jié)構(gòu)遍歷:是根據(jù)訪問結(jié)點(diǎn)操作發(fā)生位置命名
NLR:前序遍歷(Preorder Traversal 亦稱先序遍歷)——訪問根結(jié)點(diǎn)的操作發(fā)生在遍歷其左右子樹之前。
LNR:中序遍歷(Inorder Traversal)——訪問根結(jié)點(diǎn)的操作發(fā)生在遍歷其左右子樹之中(間)。
LRN:后序遍歷(Postorder Traversal)——訪問根結(jié)點(diǎn)的操作發(fā)生在遍歷其左右子樹之后。
由于被訪問的結(jié)點(diǎn)必是某子樹的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解釋為根、根的左子樹和根的右子樹。NLR、LNR和LRN分別又稱為先根遍歷、中根遍歷和后根遍歷。
層序遍歷:除了先序遍歷、中序遍歷、后序遍歷外,還可以對二叉樹進(jìn)行層序遍歷。設(shè)二叉樹的根節(jié)點(diǎn)所在層數(shù)為1,層序遍歷就是從所在二叉樹的根節(jié)點(diǎn)出發(fā),首先訪問第一層的樹根節(jié)點(diǎn),然后從左到右訪問第2層上的節(jié)點(diǎn),接著是第三層的節(jié)點(diǎn),以此類推,自上而下,自左至右逐層訪問樹的結(jié)點(diǎn)的過程就是層序遍歷。
4.2二叉樹的鏈?zhǔn)綄?shí)現(xiàn)
typedef char BTDataType; typedef struct BinaryTreeNode { BTDataType _data; struct BinaryTreeNode* _left; struct BinaryTreeNode* _right; }BTNode; typedef BTNode* QDataType; // 鏈?zhǔn)浇Y(jié)構(gòu):表示隊列 typedef struct QListNode { struct QListNode* _next; QDataType _data; }QNode; // 隊列的結(jié)構(gòu) typedef struct Queue { QNode* _front; QNode* _rear; }Queue; BTNode* CreateBTNode(BTDataType x); // 通過前序遍歷的數(shù)組"ABD##E#H##CF##G##"構(gòu)建二叉樹 BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi); // 二叉樹銷毀 void BinaryTreeDestory(BTNode** root); // 二叉樹節(jié)點(diǎn)個數(shù) int BinaryTreeSize(BTNode* root); // 二叉樹葉子節(jié)點(diǎn)個數(shù) int BinaryTreeLeafSize(BTNode* root); // 二叉樹第k層節(jié)點(diǎn)個數(shù) int BinaryTreeLevelKSize(BTNode* root, int k); // 二叉樹查找值為x的節(jié)點(diǎn) BTNode* BinaryTreeFind(BTNode* root, BTDataType x); // 二叉樹前序遍歷 void BinaryTreePrevOrder(BTNode* root); // 二叉樹中序遍歷 void BinaryTreeInOrder(BTNode* root); // 二叉樹后序遍歷 void BinaryTreePostOrder(BTNode* root); // 初始化隊列 void QueueInit(Queue* q); // 隊尾入隊列 void QueuePush(Queue* q, QDataType data); // 隊頭出隊列 void QueuePop(Queue* q); // 獲取隊列頭部元素 QDataType QueueFront(Queue* q); // 獲取隊列隊尾元素 QDataType QueueBack(Queue* q); // 獲取隊列中有效元素個數(shù) int QueueSize(Queue* q); // 檢測隊列是否為空,如果為空返回非零結(jié)果,如果非空返回0 int QueueEmpty(Queue* q); // 銷毀隊列 void QueueDestroy(Queue* q); // 層序遍歷 void BinaryTreeLevelOrder(BTNode* root); // 判斷二叉樹是否是完全二叉樹 int BinaryTreeComplete(BTNode* root);
// 初始化隊列 void QueueInit(Queue* q) { assert(q); q->_front = q->_rear = NULL; } // 隊尾入隊列 void QueuePush(Queue* q, QDataType data) { assert(q); QNode *newnode = ((QNode*)malloc(sizeof(QNode))); newnode->_data = data; newnode->_next = NULL; if (q->_rear == NULL) { q->_front = q->_rear = newnode; } else { q->_rear->_next = newnode; //q->_rear = q->_rear->_next; q->_rear = newnode; } } // 隊頭出隊列 void QueuePop(Queue* q) { assert(q); assert(!QueueEmpty(q)); if (q->_front == q->_rear) { free(q->_front); //free(q->_rear); q->_front = q->_rear = NULL; } else { QNode *cur = q->_front->_next; free(q->_front); q->_front = cur; } } // 獲取隊列頭部元素 QDataType QueueFront(Queue* q) { assert(q); assert(!QueueEmpty(q)); return q->_front->_data; } // 獲取隊列隊尾元素 QDataType QueueBack(Queue* q) { assert(q); assert(!QueueEmpty(q)); return q->_rear->_data; } // 獲取隊列中有效元素個數(shù) int QueueSize(Queue* q) { assert(q); int size = 0; QNode* cur = q->_front; while (cur) { ++size; cur = cur->_next; } return size; } // 檢測隊列是否為空,如果為空返回非零結(jié)果,如果非空返回0 int QueueEmpty(Queue* q) { assert(q); return q->_front == NULL ? 1 : 0; } // 銷毀隊列 void QueueDestroy(Queue* q) { assert(q); QNode *cur = q->_front; while (cur) { QNode *next = cur->_next; free(cur); cur = next; } q->_front = q->_rear = NULL; } BTNode* CreateBTNode(BTDataType x) { BTNode *node = (BTNode*)malloc(sizeof(BTNode)); node->_data = x; node->_left = NULL; node->_right = NULL; return node; } // 通過前序遍歷的數(shù)組"ABD##E#H##CF##G##"構(gòu)建二叉樹 BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi) { if (a[*pi] == '#') { return NULL; } BTNode *node = (BTNode*)malloc(sizeof(BTNode)); node->_data = a[*pi]; ++*pi; node->_left = BinaryTreeCreate(a, n, pi); ++*pi; node->_right = BinaryTreeCreate(a, n, pi); return node; } // 二叉樹銷毀 void BinaryTreeDestory(BTNode** root) { if (*root != NULL) { if ((*root)->_left) // 有左孩子 BinaryTreeDestory(&(*root)->_left); // 銷毀左孩子子樹 if ((*root)->_right) // 有右孩子 BinaryTreeDestory(&(*root)->_right); // 銷毀右孩子子樹 free(*root); // 釋放根結(jié)點(diǎn) *root = NULL; // 空指針賦NULL } } // 二叉樹節(jié)點(diǎn)個數(shù) int BinaryTreeSize(BTNode* root) { if (root == NULL) { return 0; } return BinaryTreeSize(root->_left) + BinaryTreeSize(root->_right) + 1; } // 二叉樹葉子節(jié)點(diǎn)個數(shù) 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層節(jié)點(diǎn)個數(shù) 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的節(jié)點(diǎn) BTNode* BinaryTreeFind(BTNode* root, BTDataType x) { if (root == NULL) { return NULL; } if (root->_data == x) { return root; } BTNode* ret=BinaryTreeFind(root->_left,x); if (ret != NULL) { return ret; } ret = BinaryTreeFind(root->_right, x); if (ret != NULL) { return ret; } return NULL; } // 二叉樹前序遍歷 void BinaryTreePrevOrder(BTNode* root) { if (root == NULL) { //printf("NULL "); return; } printf("%c ", root->_data); BinaryTreePrevOrder(root->_left); BinaryTreePrevOrder(root->_right); } // 二叉樹中序遍歷 void BinaryTreeInOrder(BTNode* root) { if (root == NULL) { //printf("NULL "); return; } BinaryTreeInOrder(root->_left); printf("%c ", root->_data); BinaryTreeInOrder(root->_right); } // 二叉樹后序遍歷 void BinaryTreePostOrder(BTNode* root) { if (root == NULL) { //printf("NULL "); return; } BinaryTreePostOrder(root->_left); BinaryTreePostOrder(root->_right); printf("%c ", root->_data); } // 層序遍歷 void BinaryTreeLevelOrder(BTNode* root) { Queue q; QueueInit(&q); if (root) { QueuePush(&q, root); } while (!QueueEmpty(&q)) { BTNode *front = QueueFront(&q); QueuePop(&q); printf("%c ", front->_data); if (front->_left) { QueuePush(&q, front->_left); } if (front->_right) { QueuePush(&q, front->_right); } } } // 判斷二叉樹是否是完全二叉樹 int BinaryTreeComplete(BTNode* root) { Queue q; QueueInit(&q); if (root) { QueuePush(&q, root); } while (!QueueEmpty(&q)) { BTNode *front = QueueFront(&q); QueuePop(&q); if (front == NULL) { break; } printf("%s ", front->_data); if (front->_left) { QueuePush(&q, front->_left); } if (front->_right) { QueuePush(&q, front->_right); } } while (!QueueEmpty(&q)) { BTNode *front = QueueFront(&q); QueuePop(&q); if (front != NULL) { return 0; } } return 1; }
到此這篇關(guān)于C語言數(shù)據(jù)結(jié)構(gòu)之二叉樹詳解的文章就介紹到這了,更多相關(guān)C語言二叉樹內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++學(xué)習(xí)之虛函數(shù)表與多態(tài)詳解
這篇文章主要為大家詳細(xì)介紹了C++中虛函數(shù)表與多態(tài)的相關(guān)知識,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)C++有一定的幫助,感興趣的小伙伴可以了解一下2023-03-03C++使用WideCharToMultiByte函數(shù)生成UTF-8編碼文件的方法
用來映射Unicode字符串的WideCharToMultiByte函數(shù)經(jīng)常被用來進(jìn)行UTF-8編碼的轉(zhuǎn)換,以下我們將看到C++使用WideCharToMultiByte函數(shù)生成UTF-8編碼文件的方法,首先先來對WideCharToMultiByte作一個詳細(xì)的了解:2016-06-06