1. 程式人生 > >二叉查詢樹C語言實現及其視覺化

二叉查詢樹C語言實現及其視覺化

0, 二叉搜尋樹的定義:(二叉查詢樹)(二叉排序樹)
      (1)若左子樹非空,則左子樹上的所有的節點的值都小於根節點的值
      (2)若右子樹非空,則右子樹上的所有的節點的值都大於根節點的值

      (3)其左右子樹都是二叉搜尋樹

                 

1,二叉查詢樹的表示法

struct TreeNode;
typedef struct TreeNode *PtrSearchTree;
typedef PtrSearchTree SearchTree;
struct TreeNode
{
	int value;
	PtrSearchTree left;
	PtrSearchTree right;
};

2,二叉查詢樹的插入:插入的元素始終位於葉子節點。

void insert(SearchTree* tree, int value)
{
	if( *tree == NULL )
	{
		if( ! ((*tree) = (PtrSearchTree)malloc(sizeof(struct TreeNode))) )
		{
			printf("insert malloc error\n");
			exit(0);
		}
		(*tree)->value = value;
		(*tree)->left = (*tree)->right = NULL;
	}
	else
	{
		if( value < (*tree)->value )
			insert(&((*tree)->left), value);
		else
			insert(&((*tree)->right), value);
	}
}
3,二叉查詢樹的建立,呼叫插入函式即可。

note:

1  SearchTree tree = NULL;其中的 “= NULL”,在window下的gcc進行編譯執行時可以省略, 但是在linux編譯執行時如果沒有將其值設定為NULL, 則提醒了“段錯誤”。應該是編譯器的不同造成的, 不過為每個指標賦值,而不是由其變為野指標確實是個好的習慣。

2   getchar()是為了吃掉使用者輸入的數字之間的空格,並且在使用者輸入完成按下Enter鍵之後可以捕獲到‘\n’.

SearchTree create()
{
	SearchTree tree = NULL;
	printf("Create Binary Search Tree\nplease enter the element, seperated by space, and stop input by Enter:\n");
	int key;
	while(1)
	{
		scanf("%d", &key);
		insert(&tree, key);
		if( getchar() == '\n' )
			break;
	}
	return tree;
}
4, 二叉查詢樹的視覺化。為了對其進行視覺化,需要藉助與graphviz,他的安裝在上一篇中有簡單的介紹,並且其中使用的dot語言可在官網檢視,很容易學習。
void visualization(SearchTree tree, char* filename)
{
	FILE *fw;
	if( NULL == (fw = fopen(filename, "w")) )
	{
		printf("open file error");
		exit(0);
	}
	fprintf(fw, "digraph\n{\nnode [shape = Mrecord, style = filled, color = black, fontcolor = white];\n");
	write2dot(tree, fw);
	fprintf(fw, "}");
	fclose(fw);
}
void write2dot(SearchTree tree, FILE* fw)
{
	if(tree == NULL)
		return ;
	else
	{
		fprintf(fw, "%d [label = \"<f0> | <f1> %d | <f2> \", color = black, fontcolor = white, style = filled];\n", tree->value, tree->value);
	}
	if(tree->left)
	{
		fprintf(fw, "%d [label = \"<f0> | <f1> %d | <f2> \", color = black, fontcolor = white, style = filled];\n", tree->left->value, tree->left->value);
		fprintf(fw, "%d:f0:sw -> %d:f1;\n", tree->value, tree->left->value);
	}
	if(tree->right)
	{
		fprintf(fw, "%d [label = \"<f0> | <f1> %d | <f2> \", color = black, fontcolor = white, style = filled];\n", tree->right->value, tree->right->value);
		fprintf(fw, "%d:f2:se -> %d:f1;\n", tree->value, tree->right->value);
	}
	write2dot(tree->left, fw);
	write2dot(tree->right, fw);
}
函式註釋:

         (1)  visualization函式將引數tree指定的樹,使用dot語言寫入到引數filename指定的檔案中(檔案以.dot為字尾)

         (2) write2dot函式相當於一個遍歷樹的過程,在遍歷過程中, 構成該樹的dot檔案。

程式的執行過程例項如下:

執行完成後會在同目錄下產生一個.dot檔案,在本程式中檔名為:searchtree.dot

使用dot命令產生圖片,如下圖所示,就生成了名為searchtree.png的圖片。

檢視圖片如下:

                         

5, 二叉樹的刪除

若刪除元素為葉子節點,則直接刪除,將原本指向該節點的雙親節點的相應的指標域置空,

若刪除度為1的節點,將其輸出節點的子樹直接掛在刪除節點的父節點上,

若刪除度為2的節點,找其左子樹的最大值或者右子樹的最小值替代該節點的值,然後在其左子樹或者右子樹刪除找到的最大值或者最小值。

SearchTree delete(SearchTree tree, int value)
{
	PtrSearchTree temp = NULL;
	if( !tree )
	{
		printf("have no element(delete): %d\n", value);
		return NULL;
	}
	else if( value < tree->value )
		tree->left = delete(tree->left, value);
	else if( value > tree->value )
		tree->right = delete(tree->right, value);
	else
	{
		if( tree->left && tree->right )
		{
			temp = find_min(tree->right);
			tree->value = temp->value;
			tree->right = delete(tree->right, temp->value);
		}
		else
		{
			temp = tree;
			if( !(tree->left) )tree = tree->right;
			else if( !(tree->right) )tree = tree->left;
			free(temp);
		}
	}
	return tree;
}
在程式中刪除83,得到如下的二叉樹:

                                

6,查詢(遞迴和迭代)

                  note:函式的返回型別為指標型別。

SearchTree find_recursion(SearchTree tree, int value)
{
	if( !tree )
	{
		printf("have no element(find): %d\n", value);
		return NULL;
	}
	if( value < tree->value )
		find_recursion(tree->left, value);
	else if( value > tree->value )
		find_recursion(tree->right, value);
	else
		return tree;
}
SearchTree find_iteration(SearchTree tree, int value)
{
	while(tree)
	{
		if( value < tree->value )
			tree = tree->left;
		else if( value > tree->value )
			tree = tree->right;
		else
			return tree;
	}
	printf("have no element(find): %d\n", value);
	return NULL;
}

原始碼

#include<stdio.h>
#include<stdlib.h>

struct TreeNode;
typedef struct TreeNode *PtrSearchTree;
typedef PtrSearchTree SearchTree;
struct TreeNode
{
	int value;
	PtrSearchTree left;
	PtrSearchTree right;
};

SearchTree create();
void insert(SearchTree* tree, int value);
void write2dot(SearchTree tree, FILE* fw);
void visualization(SearchTree tree, char* filename);
SearchTree find_min(SearchTree tree);
SearchTree find_max(SearchTree tree);
SearchTree find_iteration(SearchTree tree, int value);
SearchTree find_recursion(SearchTree tree, int value);
SearchTree delete(SearchTree tree, int value);

int main(int argc, char** argv)
{
	SearchTree s_tree_1 = create();
	visualization(s_tree_1, "searchtree.dot");

	PtrSearchTree min = find_min(s_tree_1);
	PtrSearchTree max = find_max(s_tree_1);
	printf("the min and max is %d, %d, respectively\n", min->value, max->value);
	int search = 83;
	PtrSearchTree find_result_1 = find_iteration(s_tree_1, search);
	PtrSearchTree find_result_2 = find_iteration(s_tree_1, search);
	if( find_result_1 && find_result_2 )
		printf("search for %d, and the result from iteration and recursion is: %d, %d\n", search, find_result_1->value, find_result_2->value);

	s_tree_1 = delete(s_tree_1, 83);
	visualization(s_tree_1, "searchtree_afterdelete.dot");
	return 0;
}

SearchTree create()
{
	SearchTree tree = NULL;
	printf("Create Binary Search Tree\nplease enter the element, seperated by space, and stop input by Enter:\n");
	int key;
	while(1)
	{
		scanf("%d", &key);
		insert(&tree, key);
		if( getchar() == '\n' )
			break;
	}
	return tree;
}
void insert(SearchTree* tree, int value)
{
	if( *tree == NULL )
	{
		if( ! ((*tree) = (PtrSearchTree)malloc(sizeof(struct TreeNode))) )
		{
			printf("insert malloc error\n");
			exit(0);
		}
		(*tree)->value = value;
		(*tree)->left = (*tree)->right = NULL;
	}
	else
	{
		if( value < (*tree)->value )
			insert(&((*tree)->left), value);
		else
			insert(&((*tree)->right), value);
	}
}
void visualization(SearchTree tree, char* filename)
{
	FILE *fw;
	if( NULL == (fw = fopen(filename, "w")) )
	{
		printf("open file error");
		exit(0);
	}
	fprintf(fw, "digraph\n{\nnode [shape = Mrecord, style = filled, color = black, fontcolor = white];\n");
	write2dot(tree, fw);
	fprintf(fw, "}");
	fclose(fw);
}
void write2dot(SearchTree tree, FILE* fw)
{
	if(tree == NULL)
		return ;
	else
	{
		fprintf(fw, "%d [label = \"<f0> | <f1> %d | <f2> \", color = black, fontcolor = white, style = filled];\n", tree->value, tree->value);
	}
	if(tree->left)
	{
		fprintf(fw, "%d [label = \"<f0> | <f1> %d | <f2> \", color = black, fontcolor = white, style = filled];\n", tree->left->value, tree->left->value);
		fprintf(fw, "%d:f0:sw -> %d:f1;\n", tree->value, tree->left->value);
	}
	if(tree->right)
	{
		fprintf(fw, "%d [label = \"<f0> | <f1> %d | <f2> \", color = black, fontcolor = white, style = filled];\n", tree->right->value, tree->right->value);
		fprintf(fw, "%d:f2:se -> %d:f1;\n", tree->value, tree->right->value);
	}
	write2dot(tree->left, fw);
	write2dot(tree->right, fw);
}
SearchTree find_min(SearchTree tree)
{
	if( !tree )
		return NULL;
	else
		if( !(tree->left) ) return tree;
		else
			find_min(tree->left);
}
SearchTree find_max(SearchTree tree)
{
	if( !tree )
		return NULL;
	else
		if( !(tree->right) ) return tree;
		else find_max(tree->right);
}
SearchTree find_recursion(SearchTree tree, int value)
{
	if( !tree )
	{
		printf("have no element(find): %d\n", value);
		return NULL;
	}
	if( value < tree->value )
		find_recursion(tree->left, value);
	else if( value > tree->value )
		find_recursion(tree->right, value);
	else
		return tree;
}
SearchTree find_iteration(SearchTree tree, int value)
{
	while(tree)
	{
		if( value < tree->value )
			tree = tree->left;
		else if( value > tree->value )
			tree = tree->right;
		else
			return tree;
	}
	printf("have no element(find): %d\n", value);
	return NULL;
}
SearchTree delete(SearchTree tree, int value)
{
	PtrSearchTree temp = NULL;
	if( !tree )
	{
		printf("have no element(delete): %d\n", value);
		return NULL;
	}
	else if( value < tree->value )
		tree->left = delete(tree->left, value);
	else if( value > tree->value )
		tree->right = delete(tree->right, value);
	else
	{
		if( tree->left && tree->right )
		{
			temp = find_min(tree->right);
			tree->value = temp->value;
			tree->right = delete(tree->right, temp->value);
		}
		else
		{
			temp = tree;
			if( !(tree->left) )tree = tree->right;
			else if( !(tree->right) )tree = tree->left;
			free(temp);
		}
	}
	return tree;
}