数据结构与算法 ——二叉排序树

二叉排序树

一、概念

基础概念:二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:

  1. 左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  2. 右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
  3. 左、右子树也分别为二叉排序树

通俗理解

  1. 查找过程有点像二分查找,都只需要O(logn)。 但是是以“链表”形式存储的二分查找,所以插入过程只需要在末尾添加新元素,而不需要去移动元素。提高了插入的速度

局限性
由于二叉排序树的“不平衡”,所以在一些特定的情况下,会退化成单链表。 所以后来才会出现了二叉平衡树、红黑树,这种在二叉排序树的基础上,增加了平衡限定条件的特殊二叉排序树。

二、代码及过程

/**
*
*二叉排序树
*Data:2019年5月11日
*
*/

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

typedef struct treeNode{
	int val;
	treeNode *left,*right;
}treeNode,*tree;

// 查找节点
int searchNode(tree T,int key,tree f,tree &p){
	if(T == NULL){ // 未找到
		p = f;
		return -1;
	}

	if(T->val == key){ // 找到当前节点
		return 1;
	}
	else if(T->val < key){ // 要查找的值大于当前节点,在右子树查找
		return searchNode(T->right,key,T,p);
	}else{
		return searchNode(T->left,key,T,p); // 在左子树查找
	}
}

// 插入节点
int insertNode(tree &T,int key){
	tree p;

	// 未找到该节点,执行插入操作
	if(searchNode(T,key,NULL,p) == -1){
		tree node = (treeNode*)malloc(sizeof(treeNode));
		node->val = key;
		node->left = node->right = NULL;

		if(p == NULL){	//被插入的节点为根节点
			T = node;
		}
		// 要插入的节点大于当前节点,则在右子树
		else if(key > p->val){
			p->right = node;
		}else{ // 在左子树
			p->left = node;
		}
		return 1;
	}else{
		// 存在该节点,直接返回
		return -1;
	}
}

// 删除节点的操作
int deleteAction(tree &T,int key){
	tree p,q,s;
	p = T;

	// 分三种情况讨论
	// 1.如果左孩子为空,则直接让右孩子顶替当前节点
	if(T->left == NULL){
		T = T->right;
		free(p);
		return 1;
	}
	// 2.如果右孩子为空,同理
	else if(T->right == NULL){
		T = T->left;
		free(p);
		return 1;
	}
	// 3.如果左右孩子都不为空
	else{
		s = T->left;
		q = s;
		//	找到次小于当前节点的值
		while(s->right != NULL){
			q = s;
			s = s->right;
		}
		
		if(q != s){
			T->val = s->val;
			q->right = s->left;
		}else{
			T->val = s->val;
			T->left = q->left;
		}
		return 1;
	}
	// 删除失败
	return -1;
}

// 删除节点
int deleteNode(tree &T,int key){
	// 未找到要删除的节点
	if(T == NULL){
		return -1;
	}

	// 查找删除节点位置
	if(T->val == key){
		// 执行删除操作
		return deleteAction(T,key);
	}
	else if(key < T->val){
		return deleteNode(T->left,key);
	}
	else{
		return deleteNode(T->right,key);
	}
}

// 输出节点
void show(tree T){
	if(T == NULL){
		return;
	}
	show(T->left);
	printf("%3d",T->val);
	show(T->right);
}

void main(){
	tree T = NULL;
	tree p;

	int n,key;
	do{
		show(T);
		printf("\n**************************************\n");
		printf("\n请输入操作: 1.查找   2.插入   3.删除   0.退出\n");
		scanf("%d",&n);
		switch(n){
		case 1: printf("\n请输入要查找的值:"); 
				scanf("%d",&key);
				if(searchNode(T,key,NULL,p) == -1){
					printf("\n未找到该节点!\n");
				}else{
					printf("\n查找成功!\n");
				}
				break;
		case 2: printf("\n请输入要插入的值:"); 
				scanf("%d",&key);
				insertNode(T,key);
				break;
		case 3: printf("\n请输入要删除的值:"); 
				scanf("%d",&key);
				deleteNode(T,key);
				break;
		}
	}while(n != 0);
}

三、复杂度

平均时间复杂度: O(nlogn)
空间复杂度: O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值