关于查找,对于表的线性存储,可以采用顺序查找,二分查找,插值查找,斐波那契查找和分块查找。为了同时提高表的查询和插入删除性能,可以采用链式存储,采用二叉树结构。
二叉排序树,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小时。