二叉排序树

前言

数据结构中,线性表分为无序线性表和有序线性表
无序线性表就是无序,插入和删除没有任何规律,查找时要遍历整棵树,效率低
有序线性表:有较高插入和删除效率,并且具备较高查找效率。因此二叉排序树诞生

参考

定义

二叉排序树又称二叉查找树、二叉搜索树。是一种特殊的二叉树。
若左子树不为空,则二叉树上所有结点的值均小于或等于它根结点的值
若右子树为不空,而二叉树上所有结点的值均岛屿或等于它根结点的值
左右子树分别又是一棵二叉排序树

二叉排序树常用函数

建树

typedef struct node{
	int data;
	struct node* l;
	struct node* r;
	struct node* father;
} Node;
typedef struct {
	Node* root;
} Tree;

查找

查找指定value值的结点

若查找关键字等于根结点,成功
否则
若小于根结点,查找其左子树
若大于根结点,查找其右子树
同理,在左右子树上类似

Node* SearchBST(Node* node,int value){
	if(node==NULL||node->data==value)
		return node;
	else if(value<node->data)
	return SearchBST(node->l,value);
	else SearchBST(node->r,value);
}
查找最大结点值
Node* _max(Node* node){
	if(node==NULL) return node;
	while(node->r!=NULL) node=node->r;
	return node;
}
int max_search(Tree* tree){
	Node* node=_max(tree->root);
	return node->data;
}
	printf("%d\n",max_search(&tree));
查找最小结点值
Node* _min(Node* node){
	if(node==NULL) return node;
	while(node->l!=NULL) node=node->l;
	return node;
}
int min_search(Tree* tree){
	Node* node=_min(tree->root);
	return node->data;
}
	printf("%d\n",min_search(&tree));
查找前驱

如果x存在左孩子,x的前驱结点为左子树的最大值
如果x没有左子树:
(1)x是一个右孩子,它的前驱结点为它的父亲结点
(2)x是一个左孩子,查找最低的父亲结点,该父亲结点要具有右孩子,找到的这个最低父亲结点就是x的前驱结点

Node* pre_node(Node* node){
	if(node->l!=NULL)
		return _max(node->l);
	Node* temp=node->father;
	while(temp!=NULL&&node==temp->l){
		node=temp;
		temp=temp->father;
	}
	return temp;
}
查找后继

如果x存在右孩子,x的后继结点为右子树的最小值
如果x没有右子树:
(1)x是一个左孩子,它的后继结点为它的父亲结点
(2)x是一个右孩子,查找最低的父亲结点,该父亲结点要具有左孩子,找到的这个最低父亲结点就是x的后继结点

Node* post_node(Node* node){
	if(node->r!=NULL){
		return _min(node->r);
	}
	Node* temp=node->father;
	while(temp!=NULL&&node==temp->r){
		node=temp;
		temp=temp->father;
	}
	return temp;
}

插入

若二叉排序树为空,则插入结点为根结点。
否则,继续在左右子树上查找
树中已有,不再插入。
树中没有,查找至某结点左子树或者右子树为空为止。插入应为该结点的左孩子或者右孩子。插入元素一定是叶子结点。
不同插入次序生成不同形态的二叉排序树

void insert(Tree* tree,int value){
	Node* node=(Node*)malloc(sizeof(Node));
	node->data=value;
	node->l=node->r=node->father=NULL;
	Node* temp=tree->root;//当前比较结点
	if(temp==NULL){
		tree->root=node;
		return;
	}
	Node* temp1;
	while(temp!=NULL){
		temp1=temp;
		if(value<temp->data) 
			temp=temp->l;
		else if(value>temp->data)
			temp=temp->r;
	} 
	node->father=temp1;
	if(node->data<temp1->data)
		temp1->l=node;
	else temp1->r=node;
}

删除

删除要考虑三种情况:
(1)删除结点为叶子结点
(2)删除结点只有左子树或者只有右子树
(3)删除结点又有左子树又有右子树
相应解决办法:
情况一:其双亲结点指针域的值改为“空”
情况二:其双亲结点的相应指针域的值改为被删除结点的左子树或右子树
情况三:以其前驱(后继)代替,然后再删除该前驱(后继)结点

Node* deleteNode(Node* node,int value){
	if(node==NULL) 
		return NULL;
	if(node->data==value){
		if(node->l!=NULL&&node->r!=NULL){
			Node* temp=node->r;
			while(temp->l!=NULL)
				temp=temp->l;
			node->data=temp->data;
			node->r=deleteNode(node->r,temp->data);
		}
		else{
			if(node->l!=NULL){
				node->data=node->l->data;
				delete(node->l);
			}
			else if(node->r!=NULL){
				node->data=node->r->data;
				delete(node->r);
			}
			else delete(node);
		}
		return NULL;
	}
	else if(value>node->data)
		node->r=deleteNode(node->r,value);
	else if(value<node->data)
		node->l=deleteNode(node->l,value);
	return node;
}

遍历

遍历与普通二叉树相同。二叉排序树的中序遍历是递增有序

void preorder(Node* node) {
	if(node!=NULL){
		printf("%d\n",node->data);
		preorder(node->l);
		preorder(node->r);
	}
	return;
}
void inorder(Node* node){
	if(node!=NULL){
		inorder(node->l);
		printf("%d\n",node->data);
		inorder(node->r);
	} 
} 
void postorder(Node*node){
	if(node!=NULL){
		postorder(node->l);
		postorder(node->r);
		printf("%d\n",node->data);
	}
}

树的高度

int get_height(Node* node){
	if(node==NULL)return 0;
	else{
		int l_height=get_height(node->l);
		int r_height=get_height(node->r);
		return max(l_height,r_height)+1;
	}
}

思考

斜树:所有结点都只有左子树的二叉树叫左斜树;所有结点都只有右子树的二叉树叫右斜树。
所以平均情况下查找的复杂度为O(lgn)
最坏情况下查找的复杂度为O(n)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值