1. 程式人生 > >二叉樹插入和刪除操作的遞迴實現(c語言)

二叉樹插入和刪除操作的遞迴實現(c語言)

連結串列和陣列是最常見的資料結構,對於資料結構來說,查詢(Find),最大最小值(FindMinFindMax),插入(Insert)和刪除(Delete)操作是最基本的操作。對於連結串列和陣列來說,這些操作的時間界為ON),其中N為元素的個數。陣列的插入和刪除需要對其他一些元素進行額外的移動操作,連結串列的查詢操作是按順序進行的,元素比較多的時候遍歷操作需要花很多的時間。

直觀上來講,陣列和連結串列都是線性結構,而二叉樹每個節點的基本元素有三個,即關鍵字(Element),左孩子(Left)和右孩子(Right),整體上呈現分支結構,這樣每個結構的長度就縮短了。因為二叉樹有一個基本性質,即對每個節點來說,其左子樹的所有節點關鍵字不大於該節點的關鍵字大小,其右子樹的所有節點的關鍵字不小於該節點的關鍵字大小,所以使得對二叉樹資料結構的基本操作都是沿分支路徑進行的(它的結構使得這一操作是正確的),操作時間大大減少。可以證明,如果一棵二叉樹的樹高為h

,則上述操作的時間界是Oh)。

#include <stdio.h>
#include <stdlib.h>
#ifndef _Tree_H
struct TreeNode;
typedef struct TreeNode *Position;
typedef struct TreeNode *SearchTree;

SearchTree MakeEmpty(SearchTree T);
Position Find(int X, SearchTree T);
Position FindMin(SearchTree T);
Position FindMax(SearchTree T);
SearchTree Insert(int X, SearchTree T);
SearchTree Delete(int X, SearchTree T);
#endif /*_Tree_H*/


struct TreeNode
{
	int Element;
	SearchTree Left;
	SearchTree Right;
};

/*把一棵樹清空*/
SearchTree
MakeEmpty(SearchTree T)
{
	if (T != NULL)
	{
		MakeEmpty(T->Left);
		MakeEmpty(T->Right);
		free(T);
	}
	return NULL;
}

/*查詢操作*/
/*方法:從根節點開始,將欲查詢的元素X與節點關鍵字作比較,如果比X小,則沿該節點右子樹進行查詢,
         如果比X大,則沿該節點左子樹進行查詢*/
Position
Find(int X, SearchTree T)
{
	if (T == NULL)
		return NULL; 
	if (X < T->Element)
		return Find(X, T->Left);
	else
	if (X>T->Element)
		return Find(X, T->Right);
	else
		return T;
}

/*查詢最小元素*/
/*方法:從根節點開始,沿左子樹進行尋訪,直到找到最左分支路徑上最深的節點*/
Position
FindMin(SearchTree T)
{
	if (T == NULL)
		return NULL;
	else
	if (T->Left == NULL)//最左分支路徑上的最後一點節點;
		return T;
	else
		return FindMin(T->Left);//對於不滿足條件的節點,沿其左子樹進行尋訪;
}

/*查詢最大元素*/
/*方法:從根節點開始,沿右子樹進行尋訪,直到找到最右分支路徑上最深的節點*/
/*對於Insert(X,T)函式來說,只有形參T==NULL時,返回值發生變化,否則每次遞迴結束,
 返回值都和形參相等,此時T->Left/Right=Insert()不改變樹的結構。*/
Position
FindMax(SearchTree T)
{
	if (T == NULL)
		return NULL;
	else
	if (T->Right == NULL)//最右分支路徑上的最後一個節點;
		return T;
	else
		return FindMax(T->Right);//對於不滿足條件的節點,沿其右子樹進行尋訪;
}

/*插入操作*/
/*方法:從根節點開始,通過將待插入元素X與節點元素進行比較,把X插入到尋訪路徑的最後一個節點上*/
SearchTree
Insert(int X, SearchTree T)
{
	if (X < T->Element)
		T->Left = Insert(X, T->Left);
	else
	if (X>T->Element)
		T->Right = Insert(X, T->Right);/*沿路徑進行尋訪,直到找到能夠插入待插入元素的位置節點T1。T1表示路徑上的最後一個節點,
						X或是其左孩子,或是其右孩子。當T==NULL時,Insert新建立一個葉節點T1,將關鍵字X存入其中。
					        然後Insert函式執行完畢,返回新節點T1,由於遞迴結束,所以跳轉到前一級遞迴程式程式碼
						T1->Left/Right=Insert()處繼續執行,將T2放到T1的正確位置上,同時當前遞迴也結束,再退
						回到上一級遞迴處繼續執行,以後的遞迴處執行的語句都不改變樹的結構。*/
	else
	if (T==NULL)                      //將元素X放到新的節點中;
	{
		T = (SearchTree)malloc(sizeof(struct TreeNode));
		if (T == NULL)
			printf("Out of space!!!");
		else
		{
			T->Element = X;
			T->Left = T->Right = NULL;
		}
	}
	return T;
}

/*刪除操作*/
/*方法:先找到要刪除的元素X所在的節點,然後按照該節點T的結構分成三種情況:
      case1:T為葉節點。處理方法:直接將T刪除即可,把T置為NULL;
      case2:T有且僅有一個子樹。處理方法:將T刪除,然後將其子樹移到T的位置;
      case3:T有兩個子樹。處理方法:先找到X的後繼Y(Y一定在T的右子樹中),然
	         後將T與Y交換,最後把Y刪除。*/
SearchTree
Delete(int X, SearchTree T)
{
	Position TmpCell;
	if (T == NULL)
		printf("Element not find!!!");
	else
	if (X<T->Element)
		T->Left = Delete(X, T->Left);
	else
	if (X>T->Element)
		T->Right = Delete(X, T->Right);//沿路徑對刪除元素X進行尋訪;
	else
	if (T->Left&&T->Right)            //case3
	{
		TmpCell = FindMin(T->Right);  //尋找T的後繼Y;
		T->Element = TmpCell->Element;//交換T和Y;
		T->Right = Delete(T->Element, T->Right);//刪除後繼Y;
	}
	else                             //case1和case2;
	{
		TmpCell = T;
		if (T->Left == NULL)
			T = T->Right;
		else if (T->Right == NULL)
			T = T->Left;
		free(TmpCell);
	}
	return T;
}