1. 程式人生 > 其它 >Data structure Week1.Day6

Data structure Week1.Day6

技術標籤:筆記資料結構二叉樹

樹形結構

1、樹的基本概念

​ 是一種表示層次關係(一對多)的資料結構

​ 有且僅有一個特定的節點、該節點沒有前驅、被稱為根節點

​ 剩餘的n個節點互不相交的子集、其中的每個子集也都是一棵樹

​ 注意:樹型結構具有遞迴性(樹中有樹)

2、樹的表示方法

​ 倒懸樹、巢狀發、凹凸發

3、樹的專業術語

​ 節點:組成樹的基礎元素、同時節點也可看做一棵樹

​ 節點的度:該節點子樹的數量

​ 樹的度(樹的密度):該樹所有節點的數量

​ 樹的高度:樹的層數

​ 樹的深度:樹的最大層次數

​ 節點的層次:根節點的層次1 從1開始不是0

​ 葉子節點:節點的度為0的節點

​ 雙親和孩子:節點的子樹被稱為孩子節點、該節點就是孩子節點的雙親

​ 兄弟:同一個雙親的節點之間兄弟相稱

​ 堂兄弟:雙親是兄弟

​ 祖先節點:從根節點出發到該節點的所有節點

​ 子孫:一個節點的子樹中任意一個節點

​ 森林:n個互不相交的數的結合稱為森林

4、樹的儲存

​ 樹可以順序儲存、鏈式儲存、也可以混合儲存,根據儲存的資訊不同、有以下表示方法:

雙親表示法

​ 順序:

位置data雙親
0A-1
1B0
2C0
3D2
4E1
5F1
6G4
7H4

優點:方便找到雙親 缺點:查詢孩子節點不方便

typedef struct TreeNode
{
    char data;
    int parent;
}TreeNode;

typedef struct Tree
{
TreeNode* arr; size_t cal; size_t cnt; }Tree; Tree* create_tree(cal) { Tree* tree =malloc(sizeof(Tree)); tree->arr = malloc(sizeof(TreeNode)*cal); tree->cal = cal; tree->cnt = 0; return tree; } bool add_tree(Tree* tree,char data,char parent) { if(tree->
cnt == tree->cal) { tree->cal *= 2; tree->arr = realloc(tree->arr,tree->cal); } if('\0' == parent) { tree->arr[0].data = data; tree->arr[0].parent = -1; tree->cnt++; return true; } for(int i=0;i<tree->cnt;i++) { if(tree->arr[i].data == parent) { tree->arr[tree->cnt].data = data; tree->arr[tree->cnt++].parent = i; return ture; } } return false; } void show_tree(Tree* tree) { for(int i=0;i<tree->cnt;i++) { printf("index:%d data:%c parent:%d\n",i.tree->arr[i].data,tree->arr[i].data,tree->arr[i].parent); } } int main() { Tree* tree = create_tree(10); add_tree(tree,'A','\0'); add_tree(tree,'B','A'); add_tree(tree,'C','A'); add_tree(tree,'D','C'); add_tree(tree,'E','B'); add_tree(tree,'F','B'); add_tree(tree,'G','E'); show_tree(tree); }

孩子表示法

順序:浪費大量空間 找孩子方便、但是找雙親麻煩

位置data孩子
0A1,2
1B4,5
2C3
3D
4E6,7
5F
6G
7H

鏈式:相對上面的順序節約了空間

位置data孩子
0A1->2->NULL
1B4->5->NULL
2C3->NULL
3D->NULL
4E6->7->NULL
5F->NULL
6G->NULL
7H->NULL

兄弟表示法

​ 雙親的孩子指標域只儲存第一個孩子節點、兄弟指標域只儲存第一個兄弟節點

​ 優點:方便查詢兄弟

​ 缺點:查詢雙親比較麻煩

總結:普通樹不常用、一般會轉換為二叉樹使用。

二叉樹:

​ 是一種常用的樹型結構、處理起來比普通樹要簡單、而且普通樹可以很方便的轉換成二叉樹。

定義

​ 節點數最多為2、二叉樹是n個有限元素的結合、該有一個稱為根的元素及兩個不相交的、被分別稱為左子樹和右子樹的二叉樹組成、是有序樹。當集合為空時、稱該二叉樹為空二叉樹。

特殊的二叉樹

​ 滿二叉樹:每一層的節點數都是2^(i-1)個

​ 完全二叉樹:深度為k,有n個結點的二叉樹當且僅當其每一個結點都與深度為k的滿二叉樹中編號從1到n的結點一一對應時,稱為完全

二叉樹

二叉樹的性質

  • ​ 性質1:二叉樹的第i層上至多有2^(i-1)個節點
  • ​ 性質2:深度為h的二叉樹、至多有2^h -1個節點
  • ​ 性質3:二叉樹中有n0個葉子節點,有n2個度為2的節點,則有n0=n2+1
  • ​ 性質4:具有n個節點的完全二叉樹深為log2x+1
  • ​ 性質5:若對一棵有n個節點的完全二叉樹進行順序編號(1≤i≤n),那麼,對於編號為i(i≥1)的節點:

​ 當i=1時,該節點為根,它無雙親節點

​ 當i>1時,該節點的雙親節點的編號為i/2

​ 若2i≤n,則有編號為2i的左節點,否則沒有左節點

​ 若2i+1≤n,則有編號為2i+1的右節點,否則沒有右節點

​ 二叉樹的操作:

​ 構建、銷燬、遍歷、高度、密度、插入、刪除、查詢、求左、求右

​ 二叉樹的儲存:

​ 順序:必須嚴格按照二叉樹節點書序儲存、空位置使用特殊資料代替

​ 資料項:儲存節點的記憶體首地址 容量

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>
#include"list_queue.h"
//#define TYPE char

typedef struct BinTree
{
	TYPE* arr;
	size_t cal;
}BinTree;

BinTree* create_tree(TYPE* arr,size_t len)
{
	BinTree* tree = malloc(sizeof(BinTree));
	tree->arr = malloc(sizeof(TYPE)*len);
	memcpy(tree->arr,arr,len*sizeof(TYPE));
	tree->cal = len;
	return tree;
}

void _dlr_show(BinTree* tree,size_t index)
{
	if(index-1 >= tree->cal) return;
	printf("%c ",tree->arr[index-1]);
	_dlr_show(tree,index*2);//left subtree
	_dlr_show(tree,index*2+1);//right subtree
}

void _ldr_show(BinTree* tree,size_t index)
{	
	if(index-1 >= tree->cal) return;
	_ldr_show(tree,index*2);//left subtree
	printf("%c ",tree->arr[index-1]);
	_ldr_show(tree,index*2+1);//right subtree
}

void _lrd_show(BinTree* tree,size_t index)
{	
	if(index-1 >= tree->cal) return;
	_lrd_show(tree,index*2);//left subtree
	_lrd_show(tree,index*2+1);//right subtree
	printf("%c ",tree->arr[index-1]);
}

void tier_show_tree(BinTree* tree)//Sequence traversal
{
	ListQueue* queue = create_list_queue();
	push_list_queue(queue,1);
	while(!empty_list_queue(queue))
	{
		size_t index = head_list_queue(queue);
		size_t left = index*2;
		size_t right = index*2+1;
		if(left-1 < tree->cal && '#'!=tree->arr[left-1])
		{
			push_list_queue(queue,left);
		}
		if(right-1 < tree->cal && '#' != tree->arr[right-1])
		{
			push_list_queue(queue,right);
		}
		printf("%c ",tree->arr[index-1]);
		pop_list_queue(queue);
	}
	destroy_list_queue(queue);
	printf("\n");
}

void dlr_show(BinTree* tree)
{
	_dlr_show(tree,1);
}

void ldr_show(BinTree* tree)
{
	_ldr_show(tree,1);
}

void lrd_show(BinTree* tree)
{
	_lrd_show(tree,1);
}

void destroy_tree(BinTree* tree)
{
	free(tree->arr);
	free(tree);
}

int main(int argc,const char* argv[])
{
		char* str = "ABCD#EF####GH";
		BinTree* tree = create_tree(str,strlen(str));
		dlr_show(tree);
		printf("\n");
		ldr_show(tree);
		printf("\n");
		lrd_show(tree);
		printf("\n");
		tier_show_tree(tree);
}

二叉樹的遍歷:

​ 前序遍歷:根-左-右

​ 中序遍歷:左-根-右

​ 後序遍歷:左-右-根

​ 層序遍歷:從上到先-從左到右、必須要與佇列配合使用

​ 注意:前中後由根節點遍歷位置決定、並且左右子樹的次序不能調換

​ 注意:根據前序+中序 或者 中序+後序的組合 來還原一棵唯一的樹 前+後不能!

樹:

​ 平衡二叉樹

​ 完全二叉樹

​ 有序二叉樹

圖:

​ 有向圖

​ 無向圖

​ 圖的儲存

​ 深度優先遍歷

​ 廣度優先遍歷

​ 最短路徑

演算法:

​ 查詢

​ 排序

​ 動態規劃

​ 時間複雜度