数据结构之二叉搜索树

1. 二叉搜索树的概念
     二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
若它的左子树不为空,则左子树上所有节点的值都小于根节点的值,若它的右子树不为空,则它右子树上所有节点的值都大于根节点的值,它的左右子树也分别为二叉搜索树。
2. 二叉搜索树实现---> 循环

typedef int DataType;
typedef struct BSTreeNode
{
struct BSTreeNode* _pLeft;
struct BSTreeNode* _pRight;
DataType _data;
}BSTNode;

// 初始化二叉搜索树
void InitBSTree(BSTNode** pRoot);

// 插入值为data的元素
void InsertBSTree(BSTNode** pRoot, DataType data);

// 删除值为data的结点
void DeleteBSTree(BSTNode** pRoot, DataType data);

// 在二叉搜索树中查找值为data的结点
BSTNode* FindBSTree(BSTNode* pRoot, DataType data);

// 中序遍历二叉搜索树
void PreOrder(BSTNode* pRoot);

// 销毁二叉搜索树
void DestroyBSTree(BSTNode** pRoot);
#define _CRT_SECURE_NO_WARNINGS 
#ifndef BsTree_h
#define BsTree_h
#include<stdio.h>
#include<malloc.h>
#include<assert.h>
typedef int DataType;
typedef struct BsTreeNode{
	struct BsTreeNode * pleft;
	struct BsTreeNode * pright;
	DataType data;
}BsTreeNode;
BsTreeNode *Buynode(DataType data){//获取一个新节点
	BsTreeNode* pnewnode = NULL;
	pnewnode = (BsTreeNode*)malloc(sizeof(BsTreeNode));
	if (pnewnode == NULL){
		assert(0);
		return NULL;
	}
	pnewnode->data = data;
	pnewnode->pleft = NULL;
	pnewnode->pright = NULL;
	return pnewnode;
}
void InitBsTree(BsTreeNode** proot){//初始化二叉搜索树
	assert(proot);
	*proot = NULL;
}
void InsertBsTree(BsTreeNode** proot, DataType data){//插入新节点
	assert(proot);
	BsTreeNode *pcur = *proot;
	BsTreeNode *parent = *proot;
	if (*proot == NULL){
		*proot = Buynode(data);
	}
	else{
		while (pcur){
			if (data < pcur->data){
				parent = pcur;
				pcur = pcur->pleft;
			}
			else if (data>pcur->data){
				parent = pcur;
				pcur = pcur->pright;
			}
			else{
				return;
			}
		}
		if (data < parent->data){
			parent->pleft = Buynode(data);
		}
		else{
			parent->pright = Buynode(data);
		}
	}
}
void midorder(BsTreeNode *proot){//中序遍历二叉搜索树
	if (proot){
		midorder(proot->pleft);
		printf("%d", proot->data);
		midorder(proot->pright);
	}

}
int FindBsTree(BsTreeNode *proot, DataType data){//查找值为data的节点
	assert(proot);
	BsTreeNode* pcur=proot;
	while (pcur){
		if (data < pcur->data){
			pcur = pcur->pleft;
		}
		else if (data>pcur->data){
			pcur = pcur->pright;
		}
		else{
			printf("找到了!");
			return pcur->data;
		}
	}
	printf("未找到!");

}
void destoryBsTree(BsTreeNode**proot){//按照后序遍历来销毁二叉搜索树
	assert(proot);
	if (*proot){
		destoryBsTree(&(*proot)->pleft);
		destoryBsTree(&(*proot)->pright);
		free((*proot));
		*proot = NULL;
	}
}
void delect(BsTreeNode**proot, DataType data){//删除任意位置上的节点
	assert(proot);
	if (*proot == NULL){
		return;
	}
	BsTreeNode*pcur = *proot;
	BsTreeNode* parent = *proot;
	while (pcur){
		if (data < pcur->data){
			parent = pcur;
			pcur = pcur->pleft;
		}
		else if (data>pcur->data){
			parent = pcur;
			pcur = pcur->pright;
		}
		else{
			break;
		}
	}
	if (NULL == pcur){
		return;
	}
	else{
		if (pcur->pright == NULL){//只有左孩子,或者是叶子结点
			if (pcur == *proot){//如果要删除节点是根,要更新根节点
				*proot = pcur->pleft;
			}
			else{//要删除节点不是根节点
				if (pcur = parent->pleft){//要删除节点是双亲的左孩子
					parent->pleft = pcur->pleft;
				}
				else if (pcur = parent->pright){//要删除节点是双亲的右孩子
					parent->pright = pcur->pleft;
				}
			}

		}
		else if (pcur->pleft == NULL){//只有右孩子
			if (pcur == *proot){
				*proot = pcur->pright;
			}
			else{
				if (pcur = parent->pleft){
					parent->pleft = pcur->pright;
				}
				else if (pcur = parent->pright){
					parent->pright = pcur->pright;
				}
			}
		}
		else{//左右孩子都有,在其右子树上找一个最小节点来替换删除
			BsTreeNode* pdel = pcur->pright;
			parent = pcur;//注意删除8的情况,8没有左子树,要将其parent更新
			while (pdel->pleft){//查找最小节点(注意:查找的最小节点一定没有左孩子,也不可能是根)
				parent = pdel;
				pdel = pdel->pleft;
			}
			pcur->data = pdel->data;
			if (pcur = parent->pleft){
				parent->pleft = pcur->pright;
			}
			else if (pcur = parent->pright){
				parent->pright = pcur->pright;
			}
		}
	}
}


 
 
3 . 递归实现二叉搜索树中查找、插入和删除方法
// 以递归方式实现二叉搜索树
void InitBSTree(BSTNode** pRoot);
BSTNode* FindBSTree(BSTNode* pRoot, DataType data);
int InsertBSTree(BSTNode** pRoot, DataType data);
int DeleteBSTree(BSTNode** pRoot, DataType data);
void PreOrder(BSTNode* pRoot);
void DestroyBSTree(BSTNode** pRoot);
int FindBsTree2(BsTreeNode *proot, DataType data){//递归查找
	if (proot == NULL){
		return 0;
	}
	else if (proot->data == data){
		return 1;
	}
	else if (proot->data > data){
		 return FindBsTree2(proot->pleft, data);
	}
	else if (proot->data > data){
		return FindBsTree2(proot->pright, data);
	}
}
void InsertBsTree2(BsTreeNode** proot, DataType data){//递归插入
	assert(proot);
	if (NULL == *proot){
		*proot = Buynode(data);
	}
	else{
		if (data < (*proot)->data){
			 InsertBsTree(&(*proot)->pleft, data);
		}
		if (data >(*proot)->data){
			InsertBsTree(&(*proot)->pright, data);
		}
		else
			return;
	}
}
//递归删除未写(对每个节点的处理相当于对根的处理)
#endif


3. 二叉搜索树中的应用
a.判断一个单词是否拼写正确
   将单词集合放入二叉搜索树中,每个节点为char*类型,然后用strcmp进行查找,只要在单词集合中找到单词则认为拼写正确。
b.请模拟实现一个简单的字典
          每个节点以键值对的方式来存储(<单词   中文含义>)底层就是个struct结构体。
c. log文件中有许多异常重复的ip地址,请统计每个异常ip出现了多少次
         以键值对的方式来存储(<ip,count>),在这个二叉搜索树中来查找ip,没有则插入,有则count++.
4. 分析二叉搜索树性能
    插入和删除操作都必须先查找,最优的情况下,也就是二叉搜索树为完全二叉树,其查找的时间复杂度为树的高度:log2n,但最坏的情况下,也就是二叉搜索树退化为单支树,就相当于一个链表,其时间复杂度也退化成了o(n).
5. 了解平衡树AVL树和红黑树
       因此,两位俄罗斯数学家在1962年发明了一个解决上述问题的方法,当向二叉搜索树中插入新节点后,如果能保证每个节点左右子树高度之差的绝对值不超过1,即降低树的高度,从而减少平均搜索长度。红黑树是一科二叉搜索树,它在每个节点上增加了一个存储位来表示节点的颜色,可以是red或者black,通过对任何一条从根节点到叶子结点简单路径上的颜色来约束,红黑树保证最长路径不超过最短路径的两倍,因而近似平衡,而且在实际应用中发现,红黑树性能确实比AVL树性能高。

猜你喜欢

转载自blog.csdn.net/superwangxinrui/article/details/80321943