数据结构与算法学习--二叉树及二叉搜索树

可以看下以前对数的总结https://blog.csdn.net/sjin_1314/article/details/8507490
在这里插入图片描述

下面是二叉树的遍历,创建及销毁的函数实现,层次遍历依赖队列;队列实现可以去github上查看https://github.com/jin13417/algo/tree/master/c-cpp/23_binarytree/tree

/*************************************************************************
 > File Name: binarytree.c
 > Author:  jinshaohui
 > Mail:    [email protected]
 > Time:    18-11-12
 > Desc:    
 ************************************************************************/
#include<assert.h>

#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include"list_queue.h"

typedef struct _treenode
{
	int data;
	struct _treenode *lchild;
	struct _treenode *rchild;
}Tnode,Tree;

void binarytree_create(Tree **Root)
{
	int a = 0;
	printf("\r\n输入节点数值((当输入为100时,当前节点创建完成))):");
	scanf("%d",&a);


	if (a == 100)
	{
		*Root = NULL;
	}
	else
	{
		*Root = (Tnode *)malloc(sizeof(Tnode));
		if (*Root == NULL)
		{
			return;
		}

		(*Root)->data = a;
		printf("\r\n create %d 的左孩子:",a);
		binarytree_create(&((*Root)->lchild));
		printf("\r\n create %d 的右孩子:",a);
		binarytree_create(&((*Root)->rchild));
	}

	return ;
}

void binarytree_destory(Tree *root)
{
	if (root == NULL)
	{
		return;
	}

	binarytree_destory(root->lchild);
	binarytree_destory(root->rchild);
	free(root);
}

/*先序遍历:根结点--》左子树---》右子树*/
void binarytree_preorder(Tree *root)
{
	if (root == NULL)
	{
		return;
	}
	printf(" %d ",root->data);
	binarytree_preorder(root->lchild);
	binarytree_preorder(root->rchild);
    return;
}
/*中序遍历:左子树--》跟节点---》右子树*/
void binarytree_inorder(Tree *root)
{
	if (root == NULL)
	{
		return;
	}
	binarytree_inorder(root->lchild);
	printf(" %d ",root->data);
	binarytree_inorder(root->rchild);
    return;
}
/*后序遍历:左子树---》右子树-》根节点*/
void binarytree_postorder(Tree *root)
{
	if (root == NULL)
	{
		return;
	}
	binarytree_postorder(root->lchild);
	binarytree_postorder(root->rchild);
	printf(" %d ",root->data);
    return;
}

void binarytree_levelorder(Tree * root)
{
	list_queue *queue = NULL;
	Tnode * node = NULL;

	if(root == NULL)
	{
		return;
	}

	queue = list_queue_create();

	/*根节点先入队*/
	list_queue_enqueue(queue,(void *)root);

	while(!list_queue_is_empty(queue))
	{
		list_queue_dequeue(queue,(void *)&node);
		printf(" %d ",node->data);

		if(node->lchild != NULL)
		{
			list_queue_enqueue(queue,(void *)node->lchild);
		}

		if(node->rchild != NULL)
		{
			list_queue_enqueue(queue,(void *)node->rchild);
		}
	}

	free(queue);

}
/*打印叶子节点*/
void binarytree_printfleaf(Tree *root)
{
	if (root == NULL)
	{
		return;
	}

	if ((root->lchild == NULL) && (root->rchild == NULL))
	{
		printf(" %d ",root->data);
	}
	else
	{
		binarytree_printfleaf(root->lchild);
		binarytree_printfleaf(root->rchild);
	}
}
/*打印叶子的个数*/
int binarytree_getleafnum(Tree*root)
{
	if (root == NULL)
	{
		return 0;
	}

	if ((root->lchild == NULL) && (root->rchild == NULL))
	{
		return 1;
	}
	
	return binarytree_getleafnum(root->lchild) + binarytree_getleafnum(root->rchild);

}
/*打印数的高度*/
int binarytree_gethigh(Tree *root)
{
	int lhigh = 0;
	int rhigh = 0;
	
	if (root == NULL)
	{
		return 0;
	}

	lhigh = binarytree_gethigh(root->lchild);
	rhigh = binarytree_gethigh(root->rchild);

	return ((lhigh > rhigh)?(lhigh + 1):(rhigh + 1));
}

int main()
{
	Tree *root = NULL;

	setenv("MALLOC_TRACE","1.txt",1);
    mtrace();
	
	printf("\r\n创建二叉树:");
	binarytree_create(&root);
	printf("\r\n先序遍历二叉树:");
	binarytree_preorder(root);
	printf("\r\n中序遍历二叉树:");
	binarytree_inorder(root);
	printf("\r\n后序遍历二叉树:");
	binarytree_postorder(root);
	printf("\r\n层次遍历二叉树:");
	binarytree_levelorder(root);

	printf("\r\n打印二叉树叶子节点:");
	binarytree_printfleaf(root);
	printf("\r\n打印二叉树叶子节点个数:%d",binarytree_getleafnum(root));
	printf("\r\n打印二叉树高度:%d",binarytree_gethigh(root));

	binarytree_destory(root);

    muntrace();
	return 0;
}

二叉搜索树
定义:二叉查找树(Binary Search Tree),又被称为二叉搜索树。设x为二叉查找树中的一个结点,x节点包含关键字key,节点x的key值记为key[x]。如果y是x的左子树中的一个结点,则key[y] <= key[x];如果y是x的右子树的一个结点,则key[y] >= key[x]。
在二叉查找树中:
(01) 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(02) 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(03) 任意节点的左、右子树也分别为二叉查找树。
(04) 没有键值相等的节点(no duplicate nodes)。

在实际应用中,二叉查找树的使用比较多。下面,用C语言实现二叉查找树。

/*************************************************************************
 > File Name: binarysearchtree.h
 > Author:  jinshaohui
 > Mail:    [email protected]
 > Time:    18-11-12
 > Desc:    
 ************************************************************************/
#ifndef __BINARY_SEARCH_TREE__
#define __BINARY_SEARCH_TREE__
typedef int mytype;

typedef struct _bstree_node
{
	mytype data;
	struct _bstree_node *lchild;
	struct _bstree_node *rchild;
}bstree_node;

typedef struct _bstree
{
    int size;
    int (*compare)(mytype key1,mytype key2);
	int (*destory)(mytype data);
	bstree_node *root;
}bstree;

typedef int (*compare_fuc)(mytype key1,mytype key2);
typedef int (*destory_fuc)(mytype data);

#define bstree_is_empty(tree)  (tree->size == 0)

bstree *bstree_create(compare_fuc compare,destory_fuc destory);

#endif
/*************************************************************************
 > File Name: binarysearchtree.c
 > Author:  jinshaohui
 > Mail:    [email protected]
 > Time:    18-11-12
 > Desc:    
 ************************************************************************/
#include<assert.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include"binarysearchtree.h"


bstree *bstree_create(compare_fuc compare,destory_fuc destory)
{
	bstree *tree = NULL;

	tree = (bstree*)malloc(sizeof(bstree));
	if (tree == NULL)
	{
		return NULL;
	}

	tree->size = 0;
    tree->compare = compare;
    tree->destory = destory;
	tree->root = NULL;
    return tree;
}

bstree_node *bstree_search(bstree *tree,mytype data)
{
	bstree_node *node = NULL;
	int res = 0;

	if ((tree == NULL) || (bstree_is_empty(tree)))
	{
		return NULL;
	}
    node = tree->root;

	while(node != NULL)
	{
		res = tree->compare(data,node->data);
		if(res == 0)
		{
			return node;
		}
		else if (res > 0)
		{
			node = node->rchild;
		}
		else
		{
			node = node->lchild;
		}
	}
   
	return NULL;
}

int bstree_insert(bstree * tree, mytype data)
{
    bstree_node *node = NULL;
    bstree_node *tmp = NULL;
	int res = 0;

	if (tree == NULL)
	{
		return -1;
	}

	node = (bstree_node *)malloc(sizeof(bstree_node));
	if (node == NULL)
	{
		return -2;
	}

	node->data = data;
	node->lchild = NULL;
	node->rchild = NULL;

	/*如果二叉树为空,直接挂到根节点*/
	if (bstree_is_empty(tree))
	{
        tree->root = node;
		tree->size++;
		return 0;
	}

	tmp = tree->root;

	while(tmp != NULL)
	{
		res = tree->compare(data,tmp->data);
		if (res > 0) /*去右孩子查找*/
		{
			if (tmp->rchild == NULL)
			{
				tmp->rchild = node;
				tree->size++;
				return 0;
			}
		    tmp = tmp->rchild;
		}
		else /*去左孩子查找*/
		{
			if(tmp->lchild == NULL)
			{
				tmp->lchild = node;
				tree->size++;
				return 0;
			}
			tmp = tmp->lchild;
		}
	}
    
	return -3;
}

int bstree_delete(bstree *tree,mytype data)
{
	bstree_node *node = NULL;/*要删除的节点*/
	bstree_node *pnode = NULL;/*要删除节点的父节点*/
	bstree_node *minnode = NULL;/*要删除节点的父节点*/
	bstree_node *pminnode = NULL;/*要删除节点的父节点*/
    mytype tmp = 0;
	int res = 0;

	if ((tree == NULL) || (bstree_is_empty(tree)))
	{
		return -1;
	}

	node = tree->root;
	while ((node != NULL) && ((res = tree->compare(data,node->data)) != 0))
	{
		pnode = node;
		if(res > 0)
		{
            node = node->rchild;
		}
		else
		{
            node = node->lchild;
		}
	}
	/*说明要删除的节点不存在*/
	if (node == NULL)
	{
		return -2;
	}

    /*1、如果要删除node有2个子节点,需要找到右子树的最小节点minnode,
	 * 更新minnode和node节点数据,这样minnode节点就是要删除的节点
	 * 再更新node和pnode节点指向要删除的节点*/
	if ((node->lchild != NULL) && (node->rchild != NULL))
	{
		minnode = node->rchild;
		pminnode = node;

		while(minnode->lchild != NULL)
		{
			pminnode = minnode;
			minnode = minnode->lchild;
		}

		/*node 节点和minnode节点数据互换*/
        tmp = node->data;
		node->data = minnode->data;
		minnode->data = tmp;
		/*更新要删除的节点和其父节点*/
		node = minnode;
		pnode = pminnode;
	}

	/*2、当前要删除的节点只有左孩子或者右孩子时,直接父节点的直向删除的节点*/
	if (node->lchild != NULL)
	{
        minnode = node->lchild;
	}
	else if (node->rchild != NULL)
	{
		minnode = node->rchild;
	}
	else
	{
		minnode = NULL;
	}

	if (pnode == NULL)/*当要删除的时根节点时,*/
	{
		tree->root = minnode;
	}
	else if (pnode->lchild == node)
	{
		pnode->lchild = minnode;
	}
	else
	{
		pnode->rchild = minnode;
	}
    tree->size--;
	free (node);

	return 0;
}

/*采用递归方式删除节点*/
void bstree_destory_node(bstree *tree,bstree_node *root)
{
	if (root == NULL)
	{
		return;
	}

	bstree_destory_node(tree,root->lchild);
	bstree_destory_node(tree,root->rchild);
	free(root);
}

/*二叉搜索树销毁*/
void bstree_destory(bstree *tree)
{
	bstree_destory_node(tree,tree->root);
	free(tree);
	return;
}

/*中序遍历打印树节点*/
void bstree_inorder_node(bstree_node *root)
{
	bstree_node *node = NULL;
	if (root == NULL)
	{
		return;
	}

	bstree_inorder_node(root->lchild);
	printf(" %d ",root->data);
	bstree_inorder_node(root->rchild);
    return;
}

void bstree_dump(bstree *tree)
{
	bstree_node *node = NULL;
	if ((tree == NULL) || (bstree_is_empty(tree)))
	{
		printf("\r\n 当前树是空树");
	}
	printf("\r\nSTART-----------------%d------------\r\n",tree->size);
	bstree_inorder_node(tree->root);
	printf("\r\nEND---------------------------------",tree->size);

}

int bstree_compare(mytype key1,mytype key2)
{
	if (key1 == key2)
	{
		return 0;
	}
	else if (key1 > key2)
	{
		return 1;
	}
	else
	{
		return -1;
	}
}

int main()
{
	bstree *tree = NULL;
	bstree_node *node = NULL;
	mytype data = 0;
	int res = 0;

	setenv("MALLOC_TRACE","1.txt",1);
    mtrace();

	tree = bstree_create(bstree_compare,NULL);
	assert(tree != NULL);

    while(1)
	{
		printf("\r\n插入一个数字,输入100时退出:");
		scanf("%d",&data);
		if(data == 100)break;
		res = bstree_insert(tree,data);
		printf("\r\n %d 插入%s成功",data,(res != 0)?("不"):(" "));
	}
	bstree_dump(tree);

    while(1)
	{
		printf("\r\n查询一个数字,输入100时退出:");
		scanf("%d",&data);
		if(data == 100)break;
		node = bstree_search(tree,data);
		printf("\r\n %d %s存在树中",data,(node == NULL)?("不"):(" "));
	}
	bstree_dump(tree);
    while(1)
	{
		printf("\r\n删除一个数字,输入100时退出:");
		scanf("%d",&data);
		if(data == 100)break;
		res = bstree_delete(tree,data);
		printf("\r\n %d 删除%s成功",data,(res != 0)?("不"):(" "));
	    bstree_dump(tree);
	}

	bstree_destory(tree);

    muntrace();

	return 0;
}

思考:1、什么样的二叉树适合使用数组来存储
完全二叉树,堆排序就是一种完全二叉树使用数组来处理的。
2、散列表和二叉搜索树对比
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/jsh13417/article/details/84064076