二叉排序树(二叉链表实现)

二叉排序树(二叉查找树)的定义:

二叉排序树或者是一棵空树,或者是一棵具有以下性质的二叉树:

(1)若它的左子树不为空,则左子树上所有结点的值均小于根结点的值;

(2)若它的又子树 不为空,则右子树上所有结点的值均大于根结点的值;

(3)它的左、右子树都是二叉排序树。

二叉排序树的定义是递归的。由此可得到二叉排序树的一个重要性质:中序遍历一棵二叉排序树可得到有序递增序列。

二叉排序树结点数据结构的定义(包括关键字项和其他数据项):

//每个结点数据域的数据类型 
typedef struct
	KeyType key; //关键字项 
	InfoType otherinfo; //其他数据项 
}ElemType;
//二叉排序树结点的数据结构 
typedef struct BSTNode{
	ElemType data; //数据域 
	struct BSTNode *lchild,*rchild; //左右孩子指针域 
}BSTNode,*BSTree;

下面的操作,我们使用简化的数据结构定义,我们这里将结点的数据域直接指定为int类型:

typedef struct BSTNode{
	int data; //数据域 
	struct BSTNode *lchild,*rchild; //左右孩子指针域 
}BSTNode,*BSTree;

二叉排序树的递归查找:

(1)若树为空,查找失败,返回空指针;

(2)若树非空,将给定的值key和结点元素值T->data比较:

a.若key 等于 T->data,查找成功,返回根结点的地址;

b.若key 小于 T->data,递归查找左子树;

c.若key 大于 T->data,递归查找右子树。

//二叉排序树的递归查找
BSTree SearchBST(BSTree &T, int key){
	//在根指针T所指的二叉树中查找关键字等于key的数据元素
	//若查找成功,则返回指向该数据元素结点的指针,否则返回空指针
	if(!T || key==T->data){
		return T;
	} else if(key<T->data){
		return SearchBST(T->lchild, key);
	}else {
		return SearchBST(T->rchild, key);
	}
}

二叉排序树的插入:

(1)若树为空,将新结点S做为根结点插入到空树中;

(2)若树非空,将新结点的值key与T->data做比较:

a.若key小于T->data,则将新结点S插入到左子树;

b.若key大于T->data,则将新结点S插入到右子树。

//二叉排序树的递归插入算法 
void InsertBST(BSTree &T, int e){
	if(!T){
		BSTNode *s=new BSTNode;
		s->data=e;
		s->lchild=NULL;
		s->rchild=NULL;
		T=s;
	} else if(e<T->data){
		InsertBST(T->lchild, e);
	}else if(e>T->data){
		InsertBST(T->rchild, e);
	}
}

创建二叉排序树:

(1)将二叉排序树初始化为空树;

(2)读入一个关键字为key的新结点;

(2)如果输入的key不是输入结束标志,循环以下操作:

a.将此结点插入到二叉排序树中;

b.读入一个关键字为key的新结点。

//二叉排序树的创建
void CreateBST(BSTree &T){
	T=NULL;
	int e;
	printf("请输入根点元素值(-1表示输入结束):");
	scanf("%d", &e);
	//输入-1表示结束 
	while(e!=-1){
		InsertBST(T, e);
		printf("请输入结点元素值(-1表示输入结束):");
		scanf("%d", &e);
	}
} 

二叉排序树的删除:

(1)若*p结点为叶子结点, 即凡和P R 均为空树。 由千删去叶子结点不破坏整棵树的结构,
则只需修改其双亲结点的指针即可。
f->lchild = NULL;

(2)若*p结点只有左子树PL或者只有右子树PR , 此时只要令PL 或PR直接成为其双亲结点
*f的左子树即可。f->lchild = p ->lchild; (或f->lchild= p ->rchild;)
(3) 若*p结点的左子树和右子树均不空。在删去*p结点之前,中序遍历
该二叉树得到的序列为{ …CL,C … QL,Q,SL,S,P,PR,F … }'在删去*p之后,为保持其他元素之间的相对位
置不变,可以有两种处理方法:
a.令*p的左子树为*f的左子树, 而*p的右子树为*s的右子树。f->lchild = p ->lchild; s ->rchild = p ->rchild;
b.令*p 的直接前驱(或直接后继) 替代*p, 然后再从二叉排序树中删去它的直接前驱(或
直接后继)。 当以直接前驱*s替代*p时, 由千*s只有左子树S L , 则在删去*s
之后,只要令S L 为*s的双亲*q的右子树即可

//从二叉排序树中删除关键字等于key的结点 
void DeleteBST(BSTree &T, int key){
	BSTree p, f; //查找关键字等于key的结点*p, *f为*p的双亲结点 
	p=T; f=NULL; //初始化
	while(p){
		if(key==p->data){
			break;
		}
		f=p;
		if(p->data>key){
			p=p->lchild; //在左子树中查找 
		}else{
			p=p->rchild; //在右子树中查找 
		}
	} 
	if(!p){
		return; //找不到要删除的结点 
	}
	/*------考虑3种情况实现p所指子树内部的处理:*p 左右子树均不空、无右子树、无左子树-------*/ 
	BSTree q, s;
	//1.被删结点左右子树都非空 
	if((p->lchild) && (p->rchild)){	
		q=p;
		s=p->lchild;
		//在*p的左紫苏中查找器直接前驱结点,即最右下的结点
		while(s->rchild){
			q=s;
			s=s->rchild;//向右到尽头 
		} 
		p->data=s->data; //s指向被删除结点的前驱 
		if(q!=p){
			q->rchild=s->lchild;//重接*q的右子树 
		}else{
			q->lchild=s->lchild;//接*q的左子树 
		}
		delete s;
		return;
	} else if(!p->rchild){
		//被删除结点无右子树,重接左子树
		 q=p;
		 p=p->lchild;
	} else if(!p->lchild){
		//被删除结点无左子树,重接右子树
		q=p;
		p=p->rchild;
	}
	if(!f){
		T=p;
	} else if(q==f->lchild){
		f->lchild=p;
	}else{
		f->rchild=p;
	}
	delete p;
}

 

上述操作的完整代码实现如下:

#include<stdio.h>
#define MAXSIZE 100
using namespace std;

typedef struct BSTNode{
	int data; //数据域 
	struct BSTNode *lchild,*rchild; //左右孩子指针域 
}BSTNode,*BSTree;

//二叉排序树的递归查找
BSTree SearchBST(BSTree &T, int key){
	//在根指针T所指的二叉树中查找关键字等于key的数据元素
	//若查找成功,则返回指向该数据元素结点的指针,否则返回空指针
	if(!T || key==T->data){
		return T;
	} else if(key<T->data){
		return SearchBST(T->lchild, key);
	}else {
		return SearchBST(T->rchild, key);
	}
}

//二叉排序树的递归插入算法 
void InsertBST(BSTree &T, int e){
	if(!T){
		BSTNode *s=new BSTNode;
		s->data=e;
		s->lchild=NULL;
		s->rchild=NULL;
		T=s;
	} else if(e<T->data){
		InsertBST(T->lchild, e);
	}else if(e>T->data){
		InsertBST(T->rchild, e);
	}
}

//二叉排序树的创建
void CreateBST(BSTree &T){
	T=NULL;
	int e;
	printf("请输入根点元素值(-1表示输入结束):");
	scanf("%d", &e);
	//输入-1表示结束 
	while(e!=-1){
		InsertBST(T, e);
		printf("请输入结点元素值(-1表示输入结束):");
		scanf("%d", &e);
	}
} 

//从二叉排序树中删除关键字等于key的结点 
void DeleteBST(BSTree &T, int key){
	BSTree p, f; //查找关键字等于key的结点*p, *f为*p的双亲结点 
	p=T; f=NULL; //初始化
	while(p){
		if(key==p->data){
			break;
		}
		f=p;
		if(p->data>key){
			p=p->lchild; //在左子树中查找 
		}else{
			p=p->rchild; //在右子树中查找 
		}
	} 
	if(!p){
		return; //找不到要删除的结点 
	}
	/*------考虑3种情况实现p所指子树内部的处理:*p 左右子树均不空、无右子树、无左子树-------*/ 
	BSTree q, s;
	//1.被删结点左右子树都非空 
	if((p->lchild) && (p->rchild)){	
		q=p;
		s=p->lchild;
		//在*p的左紫苏中查找器直接前驱结点,即最右下的结点
		while(s->rchild){
			q=s;
			s=s->rchild;//向右到尽头 
		} 
		p->data=s->data; //s指向被删除结点的前驱 
		if(q!=p){
			q->rchild=s->lchild;//重接*q的右子树 
		}else{
			q->lchild=s->lchild;//接*q的左子树 
		}
		delete s;
		return;
	} else if(!p->rchild){
		//被删除结点无右子树,重接左子树
		 q=p;
		 p=p->lchild;
	} else if(!p->lchild){
		//被删除结点无左子树,重接右子树
		q=p;
		p=p->rchild;
	}
	if(!f){
		T=p;
	} else if(q==f->lchild){
		f->lchild=p;
	}else{
		f->rchild=p;
	}
	delete p;
}

//中序遍历二叉树 
void InOrderTraveTree(BSTree &T){
	if(T){
		InOrderTraveTree(T->lchild);
		printf("%d ", T->data);
		InOrderTraveTree(T->rchild);
	}	
}

int main(){
	BSTree T;
	CreateBST(T);
	printf("中序遍历二叉排序树:\n");
	InOrderTraveTree(T); 
	printf("\n");
	
	int key;
	printf("输入要查找的结点值:");
	scanf("%d", &key);
	BSTree p=SearchBST(T, key);
	if(!p){
		printf("查找失败.\n");
	}else{
		printf("查找成功.\n");
	}
	
	/*int insertKey;
	printf("输入要插入的结点值:");
	scanf("%d", &insertKey);
	InsertBST(T, insertKey);
	printf("插入后遍历结果:\n");
	InOrderTraveTree(T);
	printf("\n"); */
	
	int delKey;
	printf("请输入要删除的key:");
	scanf("%d", &delKey);
	DeleteBST(T, delKey);
	printf("删除后遍历的结果:\n");
	InOrderTraveTree(T); 
} 

 

  • 7
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
二叉链表是一种常用的数据结构,可以用来实现二叉排序树二叉排序树是一种特殊的二叉树,它满足以下两个条件: 1. 左子树上所有节点的值都小于根节点的值; 2. 右子树上所有节点的值都大于根节点的值。 在C++中,我们可以通过定义一个二叉树结构体来实现二叉排序树。具体实现步骤如下: 1. 定义二叉树结构体: ``` struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} }; ``` 2. 实现入操作: ``` void insert(TreeNode*& root, int val) { if (!root) { root = new TreeNode(val); return; } if (val < root->val) { insert(root->left, val); } else if (val > root->val) { insert(root->right, val); } } ``` 3. 实现查找操作: ``` bool search(TreeNode* root, int val) { if (!root) { return false; } if (root->val == val) { return true; } else if (val < root->val) { return search(root->left, val); } else { return search(root->right, val); } } ``` 4. 实现删除操作: ``` void remove(TreeNode*& root, int val) { if (!root) { return; } if (root->val == val) { if (!root->left && !root->right) { delete root; root = NULL; } else if (!root->left) { TreeNode* temp = root; root = root->right; delete temp; } else if (!root->right) { TreeNode* temp = root; root = root->left; delete temp; } else { TreeNode* temp = root->right; while (temp->left) { temp = temp->left; } root->val = temp->val; remove(root->right, temp->val); } } else if (val < root->val) { remove(root->left, val); } else { remove(root->right, val); } } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值