国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

數(shù)據(jù)結(jié)構(gòu)(C語言實(shí)現(xiàn))——二叉樹的概念及二叉樹順序結(jié)構(gòu)和鏈?zhǔn)浇Y(jié)構(gòu)的實(shí)現(xiàn)(堆排序+TOP-K問題+鏈?zhǔn)蕉鏄湎嚓P(guān)操作)

這篇具有很好參考價(jià)值的文章主要介紹了數(shù)據(jù)結(jié)構(gòu)(C語言實(shí)現(xiàn))——二叉樹的概念及二叉樹順序結(jié)構(gòu)和鏈?zhǔn)浇Y(jié)構(gòu)的實(shí)現(xiàn)(堆排序+TOP-K問題+鏈?zhǔn)蕉鏄湎嚓P(guān)操作)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

1. 前言

前面學(xué)習(xí)了數(shù)據(jù)結(jié)構(gòu)中線性結(jié)構(gòu)的幾種結(jié)構(gòu),順序表,鏈表,棧和隊(duì)列等,今天我們來學(xué)習(xí)一種非線性的數(shù)據(jù)結(jié)構(gòu)——樹。由于二叉樹是數(shù)據(jù)結(jié)構(gòu)中的一個(gè)重點(diǎn)和難點(diǎn),所以本文著重介紹二叉樹的相關(guān)概念和性質(zhì),以及二叉樹的應(yīng)用。

2. 樹的概念及結(jié)構(gòu)

2.1 樹的概念

樹是一種非線性的數(shù)據(jù)結(jié)構(gòu),它是由n(n>=0)個(gè)有限結(jié)點(diǎn)組成一個(gè)具有層次關(guān)系的集合。把它叫做樹是因?yàn)樗雌饋硐褚豢玫箳斓臉?,也就是說它是根朝上,而葉朝下的。
注意事項(xiàng):
1.樹是遞歸定義的
2.樹形結(jié)構(gòu)中,子樹之間不能有交集,否則就不是樹形結(jié)構(gòu)

數(shù)據(jù)結(jié)構(gòu)(C語言實(shí)現(xiàn))——二叉樹的概念及二叉樹順序結(jié)構(gòu)和鏈?zhǔn)浇Y(jié)構(gòu)的實(shí)現(xiàn)(堆排序+TOP-K問題+鏈?zhǔn)蕉鏄湎嚓P(guān)操作)

2.2 樹的相關(guān)概念

如果有一棵樹如下圖所示:
數(shù)據(jù)結(jié)構(gòu)(C語言實(shí)現(xiàn))——二叉樹的概念及二叉樹順序結(jié)構(gòu)和鏈?zhǔn)浇Y(jié)構(gòu)的實(shí)現(xiàn)(堆排序+TOP-K問題+鏈?zhǔn)蕉鏄湎嚓P(guān)操作)
那么它有以下概念:

節(jié)點(diǎn)的度:一個(gè)節(jié)點(diǎn)含有的子樹的個(gè)數(shù)稱為該節(jié)點(diǎn)的度; 如上圖:A的為6
葉節(jié)點(diǎn)或終端節(jié)點(diǎn):度為0的節(jié)點(diǎn)稱為葉節(jié)點(diǎn); 如上圖:B、C、H、I…等節(jié)點(diǎn)為葉節(jié)點(diǎn)
非終端節(jié)點(diǎn)或分支節(jié)點(diǎn):度不為0的節(jié)點(diǎn); 如上圖:D、E、F、G…等節(jié)點(diǎn)為分支節(jié)點(diǎn)
雙親節(jié)點(diǎn)或父節(jié)點(diǎn):若一個(gè)節(jié)點(diǎn)含有子節(jié)點(diǎn),則這個(gè)節(jié)點(diǎn)稱為其子節(jié)點(diǎn)的父節(jié)點(diǎn); 如上圖:A是B的父節(jié)點(diǎn)
孩子節(jié)點(diǎn)或子節(jié)點(diǎn):一個(gè)節(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)的度稱為樹的度; 如上圖:樹的度為6
節(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(m>0)棵互不相交的樹的集合稱為森林;

2.3 樹的表示

樹在存儲(chǔ)時(shí),既要保存數(shù)據(jù),也要保存結(jié)點(diǎn)與結(jié)點(diǎn)之間的關(guān)系,而且實(shí)際中樹有許多種表示方法,如:雙親表示法,孩子表示法、孩子雙親表示法以及孩子兄弟表示法等。下面我們就介紹最常用的孩子兄弟表示法。

typedef int TreeDataType;
struct TreeNode
{
	TreeDataType data;//結(jié)點(diǎn)的數(shù)據(jù)域
	struct TreeNode* FirstChild;//指向其第一個(gè)孩子結(jié)點(diǎn)
	struct TreeNode* NextBrother;//指向其下一個(gè)兄弟結(jié)點(diǎn)
};

數(shù)據(jù)結(jié)構(gòu)(C語言實(shí)現(xiàn))——二叉樹的概念及二叉樹順序結(jié)構(gòu)和鏈?zhǔn)浇Y(jié)構(gòu)的實(shí)現(xiàn)(堆排序+TOP-K問題+鏈?zhǔn)蕉鏄湎嚓P(guān)操作)

3. 二叉樹的概念

一棵二叉樹是結(jié)點(diǎn)的一個(gè)有限集合,該集合:
1.或者為空
2.由一個(gè)根結(jié)點(diǎn)加上兩棵分別稱為左子樹和右子樹的二叉樹組成

如下圖所示就是一顆二叉樹:
數(shù)據(jù)結(jié)構(gòu)(C語言實(shí)現(xiàn))——二叉樹的概念及二叉樹順序結(jié)構(gòu)和鏈?zhǔn)浇Y(jié)構(gòu)的實(shí)現(xiàn)(堆排序+TOP-K問題+鏈?zhǔn)蕉鏄湎嚓P(guān)操作)
從上圖我們可以看出:

1.二叉樹不存在度大于2的結(jié)點(diǎn)
2.二叉樹的子樹有左右之分,次序不能顛倒,因此二叉樹是有序樹

3.1 特殊二叉樹

二叉樹中還有倆種特殊的二叉樹:

1.滿二叉樹:一個(gè)二叉樹,如果每一個(gè)層的結(jié)點(diǎn)數(shù)都達(dá)到最大值,則這個(gè)二叉樹就是滿二叉樹。也就是說,如果一個(gè)二叉樹的層數(shù)為K,且結(jié)點(diǎn)總數(shù)是2^k - 1,則它就是滿二叉樹。

數(shù)據(jù)結(jié)構(gòu)(C語言實(shí)現(xiàn))——二叉樹的概念及二叉樹順序結(jié)構(gòu)和鏈?zhǔn)浇Y(jié)構(gòu)的實(shí)現(xiàn)(堆排序+TOP-K問題+鏈?zhǔn)蕉鏄湎嚓P(guān)操作)

2.完全二叉樹:完全二叉樹是效率很高的數(shù)據(jù)結(jié)構(gòu),完全二叉樹是由滿二叉樹而引出來的。對(duì)于深度為K的,有n個(gè)結(jié)點(diǎn)的二叉樹,當(dāng)且僅當(dāng)其每一個(gè)結(jié)點(diǎn)都與深度為K的滿二叉樹中編號(hào)從1至n的結(jié)點(diǎn)一一對(duì)應(yīng)時(shí)稱之為完全二叉樹。要注意的是滿二叉樹是一種特殊的完全二叉樹。

數(shù)據(jù)結(jié)構(gòu)(C語言實(shí)現(xiàn))——二叉樹的概念及二叉樹順序結(jié)構(gòu)和鏈?zhǔn)浇Y(jié)構(gòu)的實(shí)現(xiàn)(堆排序+TOP-K問題+鏈?zhǔn)蕉鏄湎嚓P(guān)操作)

3.2 二叉樹的性質(zhì)

1.若規(guī)定根節(jié)點(diǎn)的層數(shù)為1,則一棵非空二叉樹的第i層上最多有2^(i-1)個(gè)結(jié)點(diǎn)
2.若規(guī)定根節(jié)點(diǎn)的層數(shù)為1,則深度為h的二叉樹的最大結(jié)點(diǎn)數(shù)是2^h-1
3.對(duì)任何一棵二叉樹, 如果度為0其葉結(jié)點(diǎn)個(gè)數(shù)為n0, 度為2的分支結(jié)點(diǎn)個(gè)數(shù)為n2,則有n0 = n2 + 1
4.若規(guī)定根節(jié)點(diǎn)的層數(shù)為1,具有n個(gè)結(jié)點(diǎn)的滿二叉樹的深度,h = log2(n+1)
5.對(duì)于具有n個(gè)結(jié)點(diǎn)的完全二叉樹,如果按照從上至下從左至右的數(shù)組順序?qū)λ泄?jié)點(diǎn)從0開始編號(hào),
則對(duì)于序號(hào)為i的結(jié)點(diǎn)有:
(1)若i > 0,i位置節(jié)點(diǎn)的雙親序號(hào):(i - 1) / 2;若i = 0,則i為根節(jié)點(diǎn)編號(hào),無雙親節(jié)點(diǎn)
(2)若2i + 1 < n,左孩子序號(hào):2i + 1,若2i + 1 >= n則無左孩子
(3)若2i + 2 < n,右孩子序號(hào):2i + 2,若2i + 2 >= n則無右孩子

4. 二叉樹的順序存儲(chǔ)

順序結(jié)構(gòu)存儲(chǔ)就是使用數(shù)組來存儲(chǔ),一般使用數(shù)組只適合表示完全二叉樹,因?yàn)椴皇峭耆鏄鋾?huì)有空間的浪費(fèi)。
二叉樹順序存儲(chǔ)在物理上是一個(gè)數(shù)組,在邏輯上是一顆二叉樹。
而現(xiàn)實(shí)中只有堆才會(huì)使用數(shù)組來存儲(chǔ)。

4.1 堆的概念

所有元素按完全二叉樹的順序存儲(chǔ)方式存儲(chǔ)在一個(gè)一維數(shù)組中,將根節(jié)點(diǎn)最大的堆叫做最大堆或大根堆,根節(jié)點(diǎn)最小的堆叫做最小堆或小根堆。
堆中某個(gè)節(jié)點(diǎn)的值總是不大于或不小于其父節(jié)點(diǎn)的值;
堆總是一棵完全二叉樹。

4.2 堆的實(shí)現(xiàn)

4.2.1 堆的結(jié)點(diǎn)定義

typedef int HPDataType;

typedef struct Heap
{
	HPDataType* a;
	int size;
	int capacity;
}HP;

4.2.2 堆的打印和銷毀

打?。?/p>

void HeapPrint(HP* php)
{
	assert(php);
	int i = 0;
	for (i = 0; i < php->size; i++)
	{
		printf("%d ", php->a[i]);
	}
	printf("\n");
}

銷毀:

void HeapDestroy(HP* php)
{
	assert(php);
	free(php->a);
	php->a = NULL;
	php->capacity = php->size = 0;
}

4.2.3 堆的插入

先插入一個(gè)數(shù)據(jù)到數(shù)組的尾上,再進(jìn)行向上調(diào)整算法,直到滿足大根堆或者小根堆。
向上調(diào)整算法:以小根堆來舉例,從該結(jié)點(diǎn)開始向上找父結(jié)點(diǎn),如果該結(jié)點(diǎn)小于父結(jié)點(diǎn),就把該結(jié)點(diǎn)和父結(jié)點(diǎn)交換,繼續(xù)向上調(diào)整,直到滿足小根堆。

插入:

void HeapPush(HP* php, HPDataType x)
{
	assert(php);
	if (php->size == php->capacity)
	{
		int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = (HPDataType*)malloc(sizeof(HPDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("malloc");
			exit(-1);
		}
		php->a = tmp;
		php->capacity = newcapacity;
	}
	php->a[php->size] = x;
	php->size++;
	AdjustUp(php->a, php->size - 1);
}

向上調(diào)整算法:

void AdjustUp(HPDataType* a, int child)
{
	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 Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

4.2.4 堆的刪除

刪除堆是刪除堆頂?shù)臄?shù)據(jù),將堆頂?shù)臄?shù)據(jù)根最后一個(gè)數(shù)據(jù)一換,然后刪除數(shù)組最后一個(gè)數(shù)據(jù),再進(jìn)行向下調(diào)整算法。
向下調(diào)整算法:以小根堆來舉例,從該結(jié)點(diǎn)開始向下找子結(jié)點(diǎn),如果子結(jié)點(diǎn)小于該結(jié)點(diǎn),就把子結(jié)點(diǎn)和該結(jié)點(diǎn)交換,再繼續(xù)向下調(diào)整,直到滿足小根堆

刪除:

void HeapPop(HP* php)
{
	assert(php);
	assert(php->size > 0);
	Swap(&php->a[0], &php->a[php->size - 1]);
	php->size--;
	AdjustDown(php->a, php->size, 0);
}

向下調(diào)整算法:

void AdjustDown(HPDataType* a, int size, int parent)
{
	int child = parent * 2 + 1;
	while (child < size)
	{
		if (child + 1 < size && (a[child + 1] < a[child]))
		{
			child++;
		}
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

4.2.5 取堆頂數(shù)據(jù)

堆頂元素就是數(shù)組下標(biāo)為0的元素

HPDataType HeapTop(HP* php)
{
	assert(php);
	assert(php->size > 0);
	return php->a[0];
}

4.2.6 堆的判空

size為0即為空

bool HeapEmpty(HP* php)
{
	assert(php);
	return php->size == 0;
}

4.2.7 堆的數(shù)據(jù)個(gè)數(shù)

size的大小就是數(shù)據(jù)個(gè)數(shù)

int HeapSize(HP* php)
{
	assert(php);
	return php->size;
}

4.3 堆的應(yīng)用

4.3.1 堆排序

堆排序即利用堆的思想來進(jìn)行排序,總共分為兩個(gè)步驟:
1.建堆
升序:建大堆
降序:建小堆
2.利用堆刪除思想來進(jìn)行排序

void HeapSort(int* arr, int size)
{
	//排升序建大堆,排降序建小堆
	//向上調(diào)整建堆O(N*logN)
	//int i = 0;
	//for (i = 1; i < size; i++)
	//{
	//	AdjustUp(arr, i);
	//}

	//向下調(diào)整建堆O(N)
	int i = 0;
	for (i = (size - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(arr, size, i);
	}

	int end = size - 1;
	while (end > 0)
	{
		Swap(&arr[0], &arr[end]);
		AdjustDown(arr, end, 0);
		end--;
	}
}

int main()
{
	int arr[10] = { 23,45,48,123,12,49,80,15,5,35 };
	HeapSort(arr, 10);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

4.3.2 TOP-K問題

TOP-K問題:即求數(shù)據(jù)結(jié)合中前K個(gè)最大的元素或者最小的元素,一般情況下數(shù)據(jù)量都比較大。
比如:專業(yè)前10名、世界500強(qiáng)、富豪榜、游戲中前100的活躍玩家等。
思路:
1.用數(shù)據(jù)集合中前K個(gè)元素來建堆
求前k個(gè)最大的元素,則建小堆
求前k個(gè)最小的元素,則建大堆
2.用剩余的N - K個(gè)元素依次與堆頂元素來比較,不滿足則替換堆頂元素
將剩余N - K個(gè)元素依次與堆頂元素比完之后,堆中剩余的K個(gè)元素就是所求的前K個(gè)最小或者最大的元素。

void PrintTopK(int* a, int n, int k)
{
	//1.建堆--用a中前k個(gè)元素建堆
	int* kMaxHeap = (int*)malloc(sizeof(int)*k);
	assert(kMaxHeap);
	int i = 0;
	for (i = 0; i < k; i++)
	{
		kMaxHeap[i] = a[i];
	}
	for (i = (k - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(kMaxHeap, k, i);
	}

	//2.將剩余n-k個(gè)元素依次與堆頂元素交換,不滿則則替換
	int j = 0;
	for (j = k; j < n; j++)
	{
		if (a[j] > kMaxHeap[0])
		{
			kMaxHeap[0] = a[j];
			AdjustDown(kMaxHeap, k, 0);
		}
	}
	for (i = 0; i < k; i++)
	{
		printf("%d ", kMaxHeap[i]);
	}
}

void TestTopk()
{
	int n = 10000;
	int* a = (int*)malloc(sizeof(int) * n);
	srand(time(0));
	for (int i = 0; i < n; i++)
	{
		a[i] = rand() % 1000000;
	}
	a[5] = 1000000 + 1;
	a[1231] = 1000000 + 2;
	a[531] = 1000000 + 3;
	a[5121] = 1000000 + 4;
	a[115] = 1000000 + 5;
	a[2335] = 1000000 + 6;
	a[9999] = 1000000 + 7;
	a[76] = 1000000 + 8;
	a[423] = 1000000 + 9;
	a[3144] = 1000000 + 10;
	PrintTopK(a, n, 10);
}

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

5. 二叉樹的鏈?zhǔn)酱鎯?chǔ)

二叉樹的鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)是指,用鏈表來表示一棵二叉樹,即用鏈來指示元素的邏輯關(guān)系。
通常的方法是鏈表中每個(gè)結(jié)點(diǎn)由三個(gè)域組成,數(shù)據(jù)域和左右指針域,左右指針分別用來給出該結(jié)點(diǎn)左孩子和右孩子所在的鏈結(jié)點(diǎn)的存儲(chǔ)地址。
鏈?zhǔn)浇Y(jié)構(gòu)又分為二叉鏈和三叉鏈。

5.1 鏈?zhǔn)蕉鏄涞慕Y(jié)點(diǎn)定義

typedef int BTDataType;

typedef struct BinaryTreeNode
{
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
	BTDataType data;
}BTNode;

5.2 結(jié)點(diǎn)創(chuàng)建

BTNode* CreatBTNode(BTDataType x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	assert(node);
	node->data = x;
	node->left = NULL;
	node->right = NULL;
	return node;
}

由于二叉樹的創(chuàng)建比較復(fù)雜,所以下面我們來手動(dòng)模擬一個(gè)簡單的二叉樹,便于后邊操作的實(shí)現(xiàn)

5.3 模擬創(chuàng)建二叉樹

BTNode* CreatBinaryTree()
{
	BTNode* node1 = CreatBTNode(1);
	BTNode* node2 = CreatBTNode(2);
	BTNode* node3 = CreatBTNode(3);
	BTNode* node4 = CreatBTNode(4);
	BTNode* node5 = CreatBTNode(5);
	BTNode* node6 = CreatBTNode(6);

	node1->left = node2;
	node1->right = node4;
	node2->left = node3;
	node4->left = node5;
	node4->right = node6;

	return node1;
}

5.4 二叉樹的遍歷

二叉樹的遍歷有:前序/中序/后序/層序的遞歸結(jié)構(gòu)遍歷:
1.前序遍歷(Preorder Traversal 亦稱先序遍歷)——訪問根結(jié)點(diǎn)的操作發(fā)生在遍歷其左右子樹之前。
2.中序遍歷(Inorder Traversal)——訪問根結(jié)點(diǎn)的操作發(fā)生在遍歷其左右子樹之中(間)。
3.后序遍歷(Postorder Traversal)——訪問根結(jié)點(diǎn)的操作發(fā)生在遍歷其左右子樹之后。
4.層序遍歷(Level Traversal)——從所在二叉樹的根結(jié)點(diǎn)出發(fā),首先訪問第一層的樹根結(jié)點(diǎn),然后從左到右訪問第2層上的結(jié)點(diǎn),接著是第三層的結(jié)點(diǎn),以此類推,自上而下,自左至右逐層訪問樹的結(jié)點(diǎn)的過程就是層序遍歷。

5.4.1 前序遍歷

void PreOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("# ");
		return;
	}

	printf("%d ", root->data);
	PreOrder(root->left);
	PreOrder(root->right);
}

5.4.2 中序遍歷

void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("# ");
		return;
	}

	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}

5.4.3 后序遍歷

void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("# ");
		return;
	}

	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->data);
}

5.4.4 層序遍歷

層序遍歷稍微復(fù)雜一點(diǎn),需要隊(duì)列來實(shí)現(xiàn),我們這里就之前使用之前創(chuàng)建好的隊(duì)列,不再過多展示,核心思路是:先判斷該結(jié)點(diǎn)是不是空,如果不是就進(jìn)隊(duì),再判斷隊(duì)是不是空,如果不是先打印出此時(shí)隊(duì)頭元素,然后刪除隊(duì)頭元素,接下來再分別判斷打印的隊(duì)頭元素的左孩子和右孩子是不是為空,不是空就繼續(xù)入隊(duì)。這樣循環(huán)迭代即層序遍歷。

void LevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);

	if (root)
	{
		QueuePush(&q, root);
	}
	while (!QueueEmpty(&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);
}

5.5 二叉樹結(jié)點(diǎn)個(gè)數(shù)及高度等操作

5.5.1 二叉樹的結(jié)點(diǎn)個(gè)數(shù)

因?yàn)槎鏄涞淖笞訕浜陀易訕涠伎梢苑謩e看成單獨(dú)的二叉樹,所以核心思路是遞歸計(jì)算左子樹和右子樹的結(jié)點(diǎn)個(gè)數(shù),最后返回再加1就是該二叉樹的結(jié)點(diǎn)個(gè)數(shù)。

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

5.5.2 二叉樹葉子結(jié)點(diǎn)的個(gè)數(shù)

左右子樹都為空的結(jié)點(diǎn)就是葉子結(jié)點(diǎn),這里也采用遞歸的思路,把二叉樹分為左子樹和右子樹,左子樹也可以分為左子樹和右子樹,遞歸計(jì)算并返回即可求的整棵樹的葉子結(jié)點(diǎn)個(gè)數(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);
}

5.5.3 二叉樹第k層的結(jié)點(diǎn)個(gè)數(shù)

這里的思路是,求根結(jié)點(diǎn)的第k層的結(jié)點(diǎn)個(gè)數(shù),可以轉(zhuǎn)換成求該結(jié)點(diǎn)的左孩子的第k-1層的結(jié)點(diǎn)個(gè)數(shù)+該結(jié)點(diǎn)的右孩子的第k-1層的結(jié)點(diǎn)個(gè)數(shù),遞歸下去,結(jié)束后返回的即為根結(jié)點(diǎn)第k層的結(jié)點(diǎn)個(gè)數(shù)。

int BinaryTreeLevelKSize(BTNode* root, int k)
{
	assert(k >= 1);
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}

	return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);

}

5.5.4 查找二叉樹中值為x的結(jié)點(diǎn)

這里的思路是,如果該結(jié)點(diǎn)就是要求的結(jié)點(diǎn),直接返回該結(jié)點(diǎn),如果不是就遞歸查找該結(jié)點(diǎn)的左子樹和右子樹,找到就返回。

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;
}

5.5.5 計(jì)算二叉樹的深度

二叉樹的深度就是該二叉樹的左子樹和右子樹的最大深度再+1,這里的思路是,遞歸計(jì)算左子樹的深度和右子樹的深度,每次返回都是以某個(gè)結(jié)點(diǎn)為根的二叉樹的深度,最后返回的就是該二叉樹的深度。

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

	int LeftDepth = BinaryTreeDepth(root->left);
	int RightDepth = BinaryTreeDepth(root->right);

	return LeftDepth > RightDepth ? LeftDepth + 1 : RightDepth + 1;

}

5.5.6 判斷是否為完全二叉樹

這里也要用到隊(duì)列,核心思路是利用完全二叉樹的性質(zhì),完全二叉樹的非空結(jié)點(diǎn)一定是連在一起的,一旦出現(xiàn)空結(jié)點(diǎn),則空結(jié)點(diǎn)后面的所有結(jié)點(diǎn)都應(yīng)該為空,如果還有非空結(jié)點(diǎn),就不是完全二叉樹。

int BinaryTreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);

	if (root)
	{
		QueuePush(&q, root);
	}
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front)
		{
			QueuePush(&q, front->left);
			QueuePush(&q, front->right);
		}
		else
		{
			break;
		}
	}
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front)
		{
			QueueDestroy(&q);
			return false;
		}
	}
	QueueDestroy(&q);
	return true;
}

6. 結(jié)尾

到這里,二叉樹的概念及二叉樹順序結(jié)構(gòu)和鏈?zhǔn)浇Y(jié)構(gòu)的實(shí)現(xiàn)和應(yīng)用就介紹完了,二叉樹作為數(shù)據(jù)結(jié)構(gòu)中的重點(diǎn)和難點(diǎn)需要反復(fù)學(xué)習(xí),理解透徹,非??简?yàn)大家的理解能力和基本功,本人也是一個(gè)初學(xué)者,文中難免有很多地方出現(xiàn)錯(cuò)誤和紕漏,此文僅供大家學(xué)習(xí)和參考。如果本文對(duì)大家學(xué)習(xí)二叉樹有幫助的話,博主感到非常榮幸。
最后,感謝各位大佬的耐心閱讀和支持,覺得本篇文章寫的不錯(cuò)的朋友可以三連關(guān)注支持一波,如果有什么問題或者本文有錯(cuò)誤的地方大家可以私信我,也可以在評(píng)論區(qū)留言討論,再次感謝各位。文章來源地址http://www.zghlxwxcb.cn/news/detail-420279.html

到了這里,關(guān)于數(shù)據(jù)結(jié)構(gòu)(C語言實(shí)現(xiàn))——二叉樹的概念及二叉樹順序結(jié)構(gòu)和鏈?zhǔn)浇Y(jié)構(gòu)的實(shí)現(xiàn)(堆排序+TOP-K問題+鏈?zhǔn)蕉鏄湎嚓P(guān)操作)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 數(shù)據(jù)結(jié)構(gòu)入門(C語言版)二叉樹的順序結(jié)構(gòu)及堆的概念及結(jié)構(gòu)實(shí)現(xiàn)應(yīng)用

    數(shù)據(jù)結(jié)構(gòu)入門(C語言版)二叉樹的順序結(jié)構(gòu)及堆的概念及結(jié)構(gòu)實(shí)現(xiàn)應(yīng)用

    普通的二叉樹是不適合用數(shù)組來存儲(chǔ)的,因?yàn)榭赡軙?huì)存在大量的空間浪費(fèi)。而完全二叉樹更適合使用順序結(jié)構(gòu)存儲(chǔ)。現(xiàn)實(shí)中我們通常把堆(一種二叉樹)使用 順序結(jié)構(gòu)的數(shù)組來存儲(chǔ) ,需要注意的是 這里的堆和操作系統(tǒng)虛擬進(jìn)程地址空間中的堆是兩回事 ,一個(gè)是 數(shù)據(jù)結(jié)構(gòu) ,一

    2023年04月19日
    瀏覽(28)
  • 【C語言 數(shù)據(jù)結(jié)構(gòu)】二叉樹的遍歷

    【C語言 數(shù)據(jù)結(jié)構(gòu)】二叉樹的遍歷

    所謂先序遍歷二叉樹,指的是從根結(jié)點(diǎn)出發(fā),按照以下步驟訪問二叉樹的每個(gè)結(jié)點(diǎn): 訪問當(dāng)前結(jié)點(diǎn); 進(jìn)入當(dāng)前結(jié)點(diǎn)的左子樹,以同樣的步驟遍歷左子樹中的結(jié)點(diǎn); 遍歷完當(dāng)前結(jié)點(diǎn)的左子樹后,再進(jìn)入它的右子樹,以同樣的步驟遍歷右子樹中的結(jié)點(diǎn); 先序遍歷這棵二叉樹的過

    2024年02月04日
    瀏覽(23)
  • 【數(shù)據(jù)結(jié)構(gòu)】樹、二叉樹的概念和二叉樹的順序結(jié)構(gòu)及實(shí)現(xiàn)

    【數(shù)據(jù)結(jié)構(gòu)】樹、二叉樹的概念和二叉樹的順序結(jié)構(gòu)及實(shí)現(xiàn)

    之前我們學(xué)習(xí)了順序表、鏈表以及棧和隊(duì)列這些數(shù)據(jù)結(jié)構(gòu),但這些數(shù)據(jù)結(jié)構(gòu)都是線性的(一對(duì)一)。接下來要學(xué)習(xí) 非線性的數(shù)據(jù)結(jié)構(gòu)——樹(二叉樹) ,相比前面的,樹的結(jié)構(gòu)更加復(fù)雜,話不多說,直接進(jìn)入正題吧。 樹是一種 非線性的數(shù)據(jù)結(jié)構(gòu) ,它是 一對(duì)多(也有可能是

    2024年02月07日
    瀏覽(27)
  • 【數(shù)據(jù)結(jié)構(gòu)—二叉樹的鏈?zhǔn)浇Y(jié)構(gòu)實(shí)現(xiàn)】

    【數(shù)據(jù)結(jié)構(gòu)—二叉樹的鏈?zhǔn)浇Y(jié)構(gòu)實(shí)現(xiàn)】

    提示:文章寫完后,目錄可以自動(dòng)生成,如何生成可參考右邊的幫助文檔 文章目錄 前言 一、二叉樹的存儲(chǔ)結(jié)構(gòu) 二、二叉樹鏈?zhǔn)浇Y(jié)構(gòu)的實(shí)現(xiàn) 2.1手動(dòng)構(gòu)建一課樹 2.2二叉樹的遍歷 三、二叉樹鏈?zhǔn)浇Y(jié)構(gòu)的實(shí)現(xiàn) 3.1前序遍歷(遞歸) 3.2中序遍歷(遞歸) 3.3后序遍歷(遞歸) 3.4層序遍歷(非遞

    2024年02月03日
    瀏覽(24)
  • 【數(shù)據(jù)結(jié)構(gòu) —— 二叉樹的鏈?zhǔn)浇Y(jié)構(gòu)實(shí)現(xiàn)】

    【數(shù)據(jù)結(jié)構(gòu) —— 二叉樹的鏈?zhǔn)浇Y(jié)構(gòu)實(shí)現(xiàn)】

    樹是一種非線性的數(shù)據(jù)結(jié)構(gòu),它是由n(n=0)個(gè)有限結(jié)點(diǎn)組成一個(gè)具有層次關(guān)系的集合。 把它叫做樹是因?yàn)樗雌饋硐褚豢玫箳斓臉?,也就是說它是根朝上,而葉朝下的。 1.有一個(gè) 特殊的結(jié)點(diǎn),稱為根結(jié)點(diǎn) ,根節(jié)點(diǎn)沒有前驅(qū)結(jié)點(diǎn) 2.除根節(jié)點(diǎn)外, 其余結(jié)點(diǎn)被分成M(M0)個(gè)互不相交

    2024年02月05日
    瀏覽(27)
  • 【數(shù)據(jù)結(jié)構(gòu)】二叉樹的實(shí)現(xiàn)

    【數(shù)據(jù)結(jié)構(gòu)】二叉樹的實(shí)現(xiàn)

    一棵二叉樹是結(jié)點(diǎn)的一個(gè)有限集合,該集合分為兩點(diǎn): 一是為空和二是由一個(gè)根節(jié)點(diǎn)加上兩棵別稱為左子樹和右子樹的二叉樹組成從圖上看出有2個(gè)性質(zhì): 二叉樹不存在度大于2的結(jié)點(diǎn) 二叉樹的子樹有左右之分,次序不能顛倒,因此二叉樹是有序樹 對(duì)于任意的二叉樹都是由以下

    2024年02月02日
    瀏覽(19)
  • 【數(shù)據(jù)結(jié)構(gòu)】二叉樹的順序結(jié)構(gòu)及實(shí)現(xiàn)

    【數(shù)據(jù)結(jié)構(gòu)】二叉樹的順序結(jié)構(gòu)及實(shí)現(xiàn)

    目錄 1. 二叉樹的順序結(jié)構(gòu) 2. 堆的概念及結(jié)構(gòu) 3. 堆的實(shí)現(xiàn) 3.1 堆向下調(diào)整算法 3.2 堆的創(chuàng)建 3.3 建堆時(shí)間復(fù)雜度 3.4 堆的插入 3.5 堆的刪除 3.6 堆的代碼實(shí)現(xiàn) 4. 堆的應(yīng)用 4.1 堆排序 4.2 TOP-K問題 普通的二叉樹是不適合用數(shù)組來存儲(chǔ)的,因?yàn)榭赡軙?huì)存在大量的空間浪費(fèi)。而完全二叉

    2024年02月08日
    瀏覽(23)
  • 數(shù)據(jù)結(jié)構(gòu):二叉樹的鏈?zhǔn)浇Y(jié)構(gòu)的實(shí)現(xiàn)

    ? 目錄 ?1.通過前序遍歷構(gòu)建二叉樹 2.?二叉樹的銷毀 ?3.二叉樹的遍歷 4.?二叉樹的節(jié)點(diǎn)個(gè)位和二叉樹的葉子節(jié)點(diǎn)個(gè)位數(shù) 5.?二叉樹的的k層節(jié)點(diǎn)數(shù)和查找值為x的節(jié)點(diǎn) 6.?判斷二叉樹是否為完全二叉樹和求二叉樹的高度h 二叉樹的前序遍歷 二叉樹的中序遍歷 二叉樹的后序遍歷

    2024年02月12日
    瀏覽(30)
  • 【數(shù)據(jù)結(jié)構(gòu)】二叉樹的鏈?zhǔn)浇Y(jié)構(gòu)及實(shí)現(xiàn)

    【數(shù)據(jù)結(jié)構(gòu)】二叉樹的鏈?zhǔn)浇Y(jié)構(gòu)及實(shí)現(xiàn)

    目錄 1. 前置說明 2. 二叉樹的遍歷 2.1 前序、中序以及后序遍歷 2.2 層序遍歷 3.?節(jié)點(diǎn)個(gè)數(shù)及高度等 4. 二叉樹的創(chuàng)建和銷毀 在學(xué)習(xí)二叉樹的基本操作前,需先要?jiǎng)?chuàng)建一棵二叉樹,然后才能學(xué)習(xí)其相關(guān)的基本操作。由于現(xiàn)在大家對(duì)二叉樹結(jié)構(gòu)掌握還不夠深入,為了降低大家學(xué)習(xí)成

    2024年02月08日
    瀏覽(25)
  • 【數(shù)據(jù)結(jié)構(gòu)】二叉樹的前中后序遍歷(C語言)

    【數(shù)據(jù)結(jié)構(gòu)】二叉樹的前中后序遍歷(C語言)

    [二叉樹] 顧名思義就是有 兩個(gè)分支節(jié)點(diǎn)的樹,不僅如此,除了葉子外的所有節(jié)點(diǎn)都具有兩個(gè)分支節(jié)點(diǎn); 由于結(jié)構(gòu)像一棵倒立的樹,顧名思義為二叉樹 ; 如下圖所示,該圖即為一棵 野生的二叉樹 ; 既然二叉樹為樹,固然有著和樹一樣的部分( 葉子、根、分支… ) 這些也成為

    2024年02月17日
    瀏覽(26)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包