1. 程式人生 > >C語言基本資料結構之二(二叉樹的三種遍歷,節點數以及深度演算法)

C語言基本資料結構之二(二叉樹的三種遍歷,節點數以及深度演算法)

關於二叉樹的定義,網上有比較好的介紹,在這裡就簡單介紹二叉樹的一些性質

二叉樹的基本性質

1)二叉樹的第i層上至多有 2^(i-1)(i ≥1)個結點;
2)深度為 h 的二叉樹中至多含有 2^h – 1 個結點;
3)若在任意一棵二叉樹中,有 n0 個葉子結點,有 n2 個度為 2 的結點,則:n0 = n2 + 1。

特殊形式的二叉樹

1)滿二叉樹
特點:深度為h且含有2h-1個結點的二叉樹,為滿二叉樹。圖示滿二叉樹,結點編號為自上而下,自左而右。
2)完全二叉樹(左圖)
特點:指深度為k的,有n個結點的,且每一個結點都與深度為k的滿二叉樹中編號從1至n的結點一一對應,完全一致,則為完全二叉樹。(右圖)
3)平衡二叉樹
特點:又稱AVL樹,它或為一棵空樹,或具如下性質:其左子樹和右子樹都是平衡二叉樹,且左、右子樹的深度之差的絕對值不超過1。左、右子樹的深度之差為平衡因子,平衡二叉樹的平衡因子只能為0,-1,1。

關於二叉樹的儲存方式(順序和鏈式儲存)

(1) 順序儲存結構
用一組連續的儲存單元存放二叉樹的資料元素。結點在陣列中的相對位置蘊含著結點之間的關係。 其所需的儲存單元數為:2^h-1= 24-1 = 15,若父結點在陣列中i下標處,其左孩子在2*i處,右孩子在2*i+1處。
(2)鏈式儲存結構 鏈式儲存結構的每個結點由資料域、左指標域和右指標域組成。左指標和右指標分別指向下一層的二叉樹
              放二叉樹的資料元素。結點在陣列中的相對位置蘊含著結點之間的關係

關於二叉樹的三種遍歷方式

(1)先序遍歷(D L R): 訪問根結點,按先序遍歷左子樹,按先序遍歷右子樹。
(2)中序遍歷(L D R): 按中序遍歷左子樹,訪問根結點,按中序遍歷右子樹。
(3)後序遍歷(L R D): 按後序遍歷左子樹,按後序遍歷右子樹,訪問根結點。

還是直接上程式碼吧~~這裡用的是鏈式儲存結構,相對順序儲存結構,前者所需儲存容量更小,更易於理解~~ 二叉樹的結構體
struct Tree{
	int data;//這裡可以改成你想要的資料型別
	tree *left;
	tree *right;
};
初始化二叉樹,新增資料
tree *initTree(tree* H){
	H = NULL;
	int data = 0;
	printf(" 輸入data \n ");
	scanf("%d",&data);
	if(data!=0){
		H = (tree *)malloc(sizeof(tree));
		H->data = data;
		printf(" t data is %d \n",H->data);
		printf(" 請輸入左字樹data \n");
		H->left = initTree(H->left);
		printf(" 請輸入右字樹data \n");
		H->right = initTree(H->right);
	}
	return H;
}
先序,中序,後序遍歷的遞迴演算法(ps:遞迴真是個好東西~~,寫出來的程式碼就是簡潔~~)
/*
先序遍歷
*/
void DLR(tree* T){
	if(NULL!=T){
		printf(" data is %5d \n ",T->data);
		DLR(T->left);
		DLR(T->right);
	}
}
/*
中序遍歷
*/
void LDR(tree* T){
	if(NULL!=T){
		LDR(T->left);
		printf(" data is %5d \n",T->data);
		LDR(T->right);
	}
}
/*
後序遍歷
*/
void LRD(tree* T){
	if(NULL!=T){
		LRD(T->left);
		LRD(T->right);
		printf(" data is %5d \n",T->data);
	}
}
二叉樹的層次遍歷
void LOrder(tree* T) /* 層次遍歷二叉樹T */
{ treeQ[MAXNODE];     /* 輔助佇列,MAXNODE為最大的佇列容量 */ 
  int f,r;               /* 佇列的首、尾指標 */
  if (T == NULL) return; /* 空樹,直接返回 */
  f = -1;                /* 隊首,隊尾指標初始化 */ 
  r = 0;
  Q[r] = T;              /* 樹根進隊 */
  while( f != r )
   { f++;
     printf(“%d”,Q[f]->data);   /* 訪問隊首結點的資料域 */
     if (Q[f]->left!= NULL)  /* 將隊首結點的左孩子入佇列 */
      { r++;
        Q[r] = Q[f]->left;  }
     if (Q[f]->right!= NULL)  /* 將隊首結點的右孩子入佇列 */
      { r++;
        Q[r] = Q[f]->right;  }
   } 
}


計算二叉樹的深度;
/*計算樹的深度*/
int deep(tree* H){
	int d1 = 0;
	int d2 = 0;
	if(NULL!=H){
		d1 = deep(H->left) +1;
		d2 = deep(H->right) +1;
	}
	return d1>=d2? d1:d2;
}
計算總的節點數和葉子數
//計算總的節點數
int node(tree* H){
	int n = 0;
	if(NULL!=H){
		n = node(H->left)+node(H->right) +1;
	}
	return n;
}
//計算葉子節點
int CountLeaf(tree* H){
	if(NULL==H) return 0;
	if((NULL==H->left)&&(NULL==H->right)){
		return 1;
	}
	return CountLeaf(H->left) + CountLeaf(H->right);
}
全部程式碼如下
#include <stdio.h>
#include <malloc.h>
typedef  struct Tree tree ;
/*
定義二叉樹的結構體
*/
struct Tree{
	int data;
	tree *left;
	tree *right;
};
tree *p[100];
/*
初始化二叉樹
*/
tree *initTree(tree* H){
	H = NULL;
	int data = 0;
	printf(" 輸入data \n ");
	scanf("%d",&data);
	if(data!=0){
		H = (tree *)malloc(sizeof(tree));
		H->data = data;
		printf(" t data is %d \n",H->data);
		printf(" 請輸入左字樹data \n");
		H->left = initTree(H->left);
		printf(" 請輸入右字樹data \n");
		H->right = initTree(H->right);
	}
	return H;
}
/*
先序遍歷
*/
void DLR(tree* H){
	if(NULL!=H){
		printf(" data is %5d \n ",H->data);
		DLR(H->left);
		DLR(H->right);
	}
}

/*
中序遍歷
*/
void LDR(tree* H){
	if(NULL!=H){
		LDR(H->left);
		printf(" data is %5d \n",H->data);
		LDR(H->right);
	}
}

/*
後序遍歷
*/
void LRD(tree* H){
	if(NULL!=H){
		LRD(H->left);
		LRD(H->right);
		printf(" data is %5d \n",H->data);
	}
}

/*
計算樹的深度
*/
int deep(tree* H){
	int d1 = 0;
	int d2 = 0;
	if(NULL!=H){
		d1 = deep(H->left) +1;
		d2 = deep(H->right) +1;
	}
	return d1>=d2? d1:d2;
}
//計算總的節點數
int node(tree* H){
	int n = 0;
	if(NULL!=H){
		n = node(H->left)+node(H->right) +1;
	}
	return n;
}
//計算葉子節點
int CountLeaf(tree* H){
	if(NULL==H) return 0;
	if((NULL==H->left)&&(NULL==H->right)){
		return 1;
	}
	return CountLeaf(H->left) + CountLeaf(H->right);
}
void main(){
	tree *H = (tree*)malloc(sizeof(tree)) ;
	 H = initTree(H);
	 printf("DLR : \n");
	 DLR(H);
	 printf("LDR : \n");
	 LDR(H);
	 printf("LRD : \n");
	 LRD(H);
	 printf("\n deep is %5d \n ",deep(H));
	 printf(" CountLeaf is %5d \n",CountLeaf(H));
	 printf(" node number is %5d  \n",node(H));
}


大概就這麼多了。想起了在補充吧~~



3)平衡二叉樹

特點:又稱AVL樹,它或為一棵空樹,或具如下性質:其左子樹和右子樹都是平衡二叉樹,且左、右子樹的深度之差的絕對值不超過1。左、右子樹的深度之差為平衡因子,平衡二叉樹的平衡因子只能為3)平衡二叉樹
特點:又稱AVL樹,它或為一棵空樹,或具如下性質:其左子樹和右子樹都是平衡二叉樹,且左、右子樹的深度之差的絕對值不超過1。左、右子樹的深度之差為平衡因子,平衡二叉樹的平衡因子只能為0,-1,1。

相關推薦

C語言基本資料結構節點數以深度演算法

關於二叉樹的定義,網上有比較好的介紹,在這裡就簡單介紹二叉樹的一些性質 二叉樹的基本性質 1)二叉樹的第i層上至多有 2^(i-1)(i ≥1)個結點; 2)深度為 h 的二叉樹中至多含有 2^h – 1 個結點; 3)若在任意一棵二叉樹中,有 n0 個葉子結點,有 n2

C語言複習資料結構簡單的輸入和輸出操作

C語言複習之簡單的二叉樹的僅輸入輸出操作 1:結構體 typedef struct TreeNode{ _Data value; struct TreeNode * father; struct TreeNode * right; stru

【圖解資料結構】 一組動畫徹底理解

二叉樹的遍歷是指從根結點出發,按照某種次序依次訪問二叉樹中所有結點,使得每個結點被訪問一次且僅被訪問一次。 在二叉樹的遍歷中存在三種較為常用的遍歷方式:前序遍歷、中序遍歷、後序遍歷。接下來我將嘗試著用三組動畫向讀者詳細的介紹這三種遍歷方式的邏輯思路,希望讓讀者看到任何的二叉樹都能在腦海中快速的勾勒出動畫。

方式通過兩重構java實現

重構方法參考文章【重構二叉樹(Java實現):https://blog.csdn.net/wangbingcsu/article/details/51372695】 文章目錄 二叉樹類 三種遍歷方式 前序遍歷 中序遍歷 後序遍歷

的非遞迴思路JAVASCRIPT)

二叉樹在圖論中是這樣定義的:二叉樹是一個連通的無環圖,並且每一個頂點的度不大於3。有根二叉樹還要滿足根結點的度不大於2。有了根結點之後,每個頂點定義了唯一的父結點,和最多2個子結點。然而,沒有足夠的資訊來區分左結點和右結點。如果不考慮連通性,允許圖中有多個連通分

方式

二叉樹的遍歷,如果是手工畫圖,還可以使用投影法快速得到遍歷序列。 以下圖二叉樹為例,講解投影法快速得到遍歷序列的過程。 (1)          中序遍歷 中序遍歷就像在無風的情況下,太陽直射

Java實現演算法

</pre><p></p><p>參考網上一些資料測試整理了一下二叉樹遍歷的Java實現程式碼。</p>二叉樹三種遍歷方式:先序遍歷、中序遍歷、後序遍歷。<p>首先定義二叉樹類:</p>&l

方式的遞迴和迴圈實現

轉載自:http://blog.csdn.net/pi9nc/article/details/13008511 二叉樹是一種非常重要的資料結構,很多其他資料機構都是基於二叉樹的基礎演變過來的。二叉樹有前、中、後三種遍歷方式,因為樹的本身就是用遞迴定義的,因此採用遞迴的方

實現

二叉樹是一種非常重要的資料結構,很多其他資料機構都是基於二叉樹的基礎演變過來的。二叉樹有前、中、後三種遍歷方式,因為樹的本身就是用遞迴定義的,因此採用遞迴的方法實現三種遍歷,不僅程式碼簡潔且容易理解,但其開銷也比較大,而若採用非遞迴方法實現三種遍歷,則要用棧來模擬實現

遞迴非遞迴實現

二叉樹的三種遍歷方式包括: 前序遍歷中序遍歷後序遍歷 三種遍歷的遞迴方法都非常好實現,而且簡單易懂。非遞迴實現也是通過使用棧來模擬遍歷的過程。順便提一句,能用遞迴做的,基本都能用棧來實現。前序遍歷和中序遍歷的非遞迴寫法相對比較簡單,只需要模擬遍歷過程即可。後序遍歷非遞迴寫

(Java)

以前學資料結構的時候是用C學的,現在重新複習一下資料結構裡用的比較多的二叉樹,用Java實現。好啦,廢話不多說啦!! 我們知道二叉樹有三種遍歷方式:前序(根左右)、中序(左根右)、後序(左右根)。每種遍歷方式其實就是一個遞迴呼叫。 步驟: 1、將陣列中的元素賦值給二叉樹(通

方式先序、中序、後序

二叉樹遍歷方式分為三種:先序,中序和後序。 可以以根節點的位置為參考來記遍歷方式,在第一個為先序,中間為中序,最後為後序; 即:先序: 根左右;中序:左根右;後序:左右根。 借個圖: 每個節點左上角,底部,右上角分別對應先序,中序,後序時的取值點

非遞迴演算法

1.先序遍歷非遞迴演算法 #define maxsize 100 typedef struct {     Bitree Elem[maxsize];     int top; } SqStack; void PreOrderUnrec(Bitree t) {     SqStack s;     Stack

C語言資料結構 迷宮求解附完整程式碼

一、程式設計思路 1、題目:應用棧實現迷宮遊戲 要求:以書中3.2.4節迷宮求解為基礎實現迷宮遊戲,遊戲執行時顯示一個迷宮地圖(迷宮內容結構可以參照書中圖片,也可以自己編寫),玩家從地圖左上角的入口處進入迷宮,從右下角出口離開迷宮。玩家不能穿牆而過。本題目需在作

python基本資料型別字串

python中字串的替換方法主要有:center、rjust\ljust、expandtabs、format\format_map(格式化)、strip、rstrip\lstrip、replace和zfill。其中最重要的兩個方法是replace和format。 1、replace replace方法是用新子

linux核心分析--核心中的資料結構佇列

核心中的佇列是以位元組形式儲存資料的,所以獲取資料的時候,需要知道資料的大小。 如果從佇列中取得資料時指定的大小不對的話,取得資料會不完整或過大。 核心中關於佇列定義的標頭檔案位於:<linux/kfifo.h> include/linux/kfifo.h 標頭檔案中定義的函

c語言資料結構線性表歸併大概

線性表:n個具有相同特性的資料元素的有限序列。較為靈活,可根據需要増長或縮短。 兩線性表歸併演算法:(此時已知其元素按值非遞減排列) void MergeList(List La, List Lb,

資料結構頭結點連結串列的插入方式頭插法尾插法在pos處插入

建立頭結點 流程:首先建立頭結點表指標併為其分配空間——並將頭結點指向空,防止出現段錯誤。 程式碼: //建立頭結點 Node* Create_List () { //建立頭結點 Node* list = (Node*) malloc(

資料結構DFS遞迴與非遞迴鄰接表存圖

學習鄰接表存圖請看:https://blog.csdn.net/HPU_FRDHR/article/details/83957240  DFS (深度優先搜尋)        深度優先搜尋演算法(英語:Depth-First-S

C語言】用結構體陣列指標完成:有個學生資訊存放在結構體陣列中要求輸出全部資訊

//用結構體陣列指標完成:有三個學生資訊,存放在結構體陣列中,要求輸出全部資訊 #include <stdio.h> struct Stu { int num; char name[2