二叉排序树BST的插入,查询和删除,c/c++描述

  关于查找,对于表的线性存储,可以采用顺序查找,二分查找,插值查找,斐波那契查找和分块查找。为了同时提高表的查询和插入删除性能,可以采用链式存储,采用二叉树结构。
  二叉排序树,binary sort tree 。 建立对应于表的二叉排序树,要求树里 : 左子节点的关键字 < 根节点的关键字 < 右子节点的关键字。这样,如果按树的中序输出,可以得到表里记录的关于关键字值的递增排列。所以二叉排序树实现了对表里记录的有序存储。
  表用一位数组存储,关键字就是数组里元素的值,要求不能有值相同的元素,或者称为记录。
  对二叉排序树的插入删除和查询效率都很高,对于平衡二叉树来讲,接近于折半查找的效率。
  BST的建立过程,就是树里节点的插入过程。其是递归的。从BST里查找记录,也是递归的。从BST里删除节点,要区分该节点的位置。
  若删除的节点是叶节点,直接删除即可。
  若删除的节点只有左子树或者右子树,则需要在排序树里保留左子树或者右子树。
  若删除的节点既有左子树又有右子树,则需要对其左子树和右子树合并,合并后的子树的根节点为原左子树的最右下角节点或者,原右子树的最左下角节点。因为我们要保证删除节点后的树仍然是二叉排序树,其中序排列(左根右),是表里记录的递增排列。
  左子树的最右下节点是左子树的中序值最大节点。右子树的最左下节点,是右子树的中序值最小节点。这两个节点,都适合作为左右子树合并后的新的根节点。
  若最右下节点含有左子节点或者最左下节点含有右子节点,则还要在树里保留这些子节点。
  删除节点的情况,除了要先找到该被删除节点,还要找到其父母节点的位置,以保证整个表里节点的连续性。
  删除节点时还要区分被删节点是否是根节点。两种情况下的程序组织是不一样的,因为根节点在被删除前,root需要指向BST新的根。而且root是没有父母节点的。
  各函数功能如下:
  函数insertBST:插入法建立BST。因为例题中首个插入节点是4 ,所以根节点的值始终为4.
  函数searchBSTRecursion : 用递归方法查找BST里是否含有数值data,有,则输出根节点到被查节点的路径。类似于递归方法老鼠走迷宫的方案,用一个数组作为该函数参数,记录走过的路径、遍历过的节点。
  函数searchBSTNoRecursion:用非递归的方法查找BST里,是否有数值data,同样用一个数组存储遍历过的节点数据。查找时,都要考虑BST里没有被查数据的情况。因为BST已经中序有序,不必用广度优先的遍历了。虽然调用二叉树的广度优先遍历方法也可以。
  函数inOrderTraverse:输出BST的中序遍历结果,其应该是递增的,以检查BST的建立和删除过程是否正确。
  函数displayBST:输出BST的逗号表达式形式,以检验二叉树的建立是否正确,这是一个复习题。其实用中序遍历输出也可以。故只调用了该函数一次,因为其结果不直观。
  函数deleteBST(Node*& root, int data):从BST里删除指定的数据节点。该函数最为复杂,费脑筋。要综合考虑树是否为空树,是否包含待删节点,待删节点是否为根节点,待删节点是否还有左右子树。具体过程结合上面分析。该函数我自己写的,略嫌繁琐,但结果是正确的,没有用递归。
  以下是全部代码,先是main函数所在源文件:

#include<iostream>
using namespace std;

struct Node {
	int data;
	Node* ptLeftChild;
	Node* ptRightChild;
};

extern void insertBST(Node * & root,int data);
extern void searchBSTRecursion(Node*& root, int data,int path[],int length);
extern void searchBSTNoRecursion(Node*& root, int data,int path[],int length);
extern void deleteBST(Node*& root, int data);
extern void inOrderTraverse(Node*& root);
extern void displayBST(Node*& root);

int main() {
	int a[] = {4,9,0,1,8,6,3,5,2,7},length = 10;
	Node* root = NULL;

	for (int i = 0; i < length; i++)
		insertBST(root,a[i]);

	cout << "middle order traverse : ";
	inOrderTraverse(root);

	cout<<endl<<"逗号表达式表示该二叉树 :";
	displayBST(root);

	int path[20];
	cout << endl<<endl;
	searchBSTNoRecursion(root,6,path,0);
	searchBSTNoRecursion(root,11,path, 0);
	
	cout << endl;
	searchBSTRecursion(root,11,path,0);
	searchBSTRecursion(root, 6, path, 0);

	cout << endl << "delete 4 : ";
	deleteBST(root,4);
	inOrderTraverse(root);
	cout << endl;

	cout << endl << "dalete 5 : ";
	deleteBST(root,5);
	inOrderTraverse(root);
	cout << endl;

	cout << endl << "dalete 99 : ";
	deleteBST(root,99);

	return 0;
}

接着是各函数所在源文件:

#include<iostream>
using namespace std;

struct Node {
	int data;
	Node* ptLeftChild;
	Node* ptRightChild;
};

void insertBST(Node*& root, int data) {
	if (root == NULL) {
		root = new Node;
		root->data = data;
		root->ptLeftChild = root->ptRightChild = NULL;
		return;
	}

	if (root->data > data)
		insertBST(root->ptLeftChild, data);
	else if (root->data < data)
		insertBST(root->ptRightChild,data);
	else 
		cout << "key " <<data<<" repeated ! " << endl;
}

void searchBSTRecursion(Node*& root, int data,int path[],int length) {
	if (root == NULL) {
		cout << "recursion,list do not include this data : "<<data << endl;
		return;
	}

	if (root->data > data) {
		path[length] = root->data;
		length++;
		searchBSTRecursion(root->ptLeftChild, data, path, length);
	}
	else if (root->data < data) {
		path[length] = root->data;
		length++;
		searchBSTRecursion(root->ptRightChild,data,path,length);
	}
	else {
		cout << "recursion,path from root to " << data << " : ";
		for (int i = 0; i < length; i++)
			cout << path[i] << " ";
		cout << data << endl;
	}
}

void searchBSTNoRecursion(Node*& root, int data,int path[],int length) {
	Node* pt = root;
	while (pt != NULL) 
		if (pt->data > data) {
			path[length] = pt->data;
			length++;
			pt = pt->ptLeftChild;
		}
		else if (pt->data < data) {
			path[length] = pt->data;
			length++;
			pt = pt->ptRightChild;
		}
		else {
			cout << "no recursion ,from root to " << data << " : ";
			for (int i = 0; i < length; i++)
				cout << path[i] << ' ';
			cout << data << endl;
			return;
		}
	
	cout << "no recursion ,list has no this data : " << data << endl;
}

void deleteBST(Node*& root, int data) {
	if (root == NULL) {
		cout << "list is empty ! " << endl;
		return;
	}

	Node* ptDelete, * ptLeftMAX, * ptParentLeftMax, * ptParentDele = NULL;
	if (root->data == data) {
		ptDelete = root;
		if (root->ptLeftChild == NULL && root->ptRightChild == NULL) 
			root = NULL;
		else if (root->ptLeftChild != NULL && root->ptRightChild == NULL) 
			root = root->ptLeftChild;
		else if (root->ptLeftChild == NULL && ptDelete->ptRightChild != NULL) 
			root = root->ptRightChild;
		else if (root->ptLeftChild->ptRightChild == NULL) {
			root = root->ptLeftChild;
			root->ptRightChild = ptDelete->ptRightChild;
		}
		else {
			ptParentLeftMax = root->ptLeftChild;
			ptLeftMAX = ptParentLeftMax->ptRightChild;
			while (ptLeftMAX->ptRightChild != NULL) {
				ptParentLeftMax = ptLeftMAX;
				ptLeftMAX = ptParentLeftMax->ptRightChild;
			}
				
			root = ptLeftMAX;

			if (ptLeftMAX->ptLeftChild != NULL)
				ptParentLeftMax->ptRightChild = ptLeftMAX->ptLeftChild;
			else
				ptParentLeftMax->ptRightChild = NULL;
			
			root->ptLeftChild = ptDelete->ptLeftChild;
			root->ptRightChild = ptDelete->ptRightChild;
		}
		
		delete ptDelete;
		return;
	}

	ptDelete = root;
	int leftRight;  // 1 is left ,2 is right
	while (ptDelete != NULL && ptDelete->data != data) {
		ptParentDele = ptDelete;

		if (ptDelete->data > data) {
			ptDelete = ptParentDele->ptLeftChild;
			leftRight = 1;
		}
		else {
			ptDelete = ptParentDele->ptRightChild;
			leftRight = 2;
		}
	}

	if (ptDelete == NULL) {
		cout << "list is not empty, but has no this data : " << data << endl;
		return;
	}

	if(ptDelete->ptLeftChild == NULL && ptDelete->ptRightChild == NULL)
		if (leftRight == 1) 
			ptParentDele->ptLeftChild = NULL;
		else 
			ptParentDele->ptRightChild = NULL;
	else if(ptDelete->ptLeftChild != NULL && ptDelete->ptRightChild == NULL)
		if (leftRight == 1) 
			ptParentDele->ptLeftChild = ptDelete->ptLeftChild;
		else 
			ptParentDele->ptRightChild = ptDelete->ptLeftChild;
	else if(ptDelete->ptLeftChild == NULL && ptDelete->ptRightChild != NULL)
		if (leftRight == 1) 
			ptParentDele->ptLeftChild = ptDelete->ptRightChild;
		else 
			ptParentDele->ptRightChild = ptDelete->ptRightChild;
	else if (ptDelete->ptLeftChild->ptRightChild == NULL) 
		if (leftRight == 1) {
			ptParentDele->ptLeftChild = ptDelete->ptLeftChild;
			ptDelete->ptLeftChild->ptRightChild = ptDelete->ptRightChild;
		}
		else{
			ptParentDele->ptRightChild = ptDelete->ptLeftChild;
			ptDelete->ptLeftChild->ptRightChild = ptDelete->ptRightChild;
		}
	else {
		ptParentLeftMax = ptDelete->ptLeftChild;
		ptLeftMAX = ptParentLeftMax->ptRightChild;
		
		while (ptLeftMAX->ptRightChild != NULL) {
			ptParentLeftMax = ptLeftMAX;
			ptLeftMAX = ptParentLeftMax->ptRightChild;
		}
	
		if (leftRight == 1)
			ptParentDele->ptLeftChild = ptLeftMAX;
		else
			ptParentDele->ptRightChild = ptLeftMAX;

		if (ptLeftMAX->ptLeftChild != NULL)
			ptParentLeftMax->ptRightChild = ptLeftMAX->ptLeftChild;
		else
			ptParentLeftMax->ptRightChild = NULL;
	
		ptLeftMAX->ptLeftChild = ptDelete->ptLeftChild;
		ptLeftMAX->ptRightChild = ptDelete->ptRightChild;
	}

	delete ptDelete;
}

void inOrderTraverse(Node*& root) {
	if (root == NULL)
		return;

	inOrderTraverse(root->ptLeftChild);
	cout << root->data << ' ';
	inOrderTraverse(root->ptRightChild);
}

void displayBST(Node*& root) {
	if (root == NULL)
		return;

	cout << root->data;
	if (root->ptLeftChild != NULL || root->ptRightChild != NULL) {
		cout << '(';
		displayBST(root->ptLeftChild);
		
		if (root->ptRightChild != NULL) {
			cout << ',';
			displayBST(root->ptRightChild);
		}

		cout << ')';
	}
}

测试结果和对应的BST树如下:
在这里插入图片描述
在这里插入图片描述
谢谢阅读。为了编写健壮的delete函数,多花费了3小时。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值