参考
Binary Search Tree Visualization (usfca.edu)
一、构建排序二叉树
注意引用 tree
/**
* 构造二叉排序树
* @param tree
* @param x
*/
void buildTree(BSTree &tree,ElementType &x){
if (tree==NULL){
tree=(BSTree) calloc(1, sizeof(BSTNode));
tree->data=x;
//注意
return;
}
if (x>tree->data){
buildTree(tree->rchild,x);
}
if (x<tree->data){
buildTree(tree->lchild,x);
}
if (x==tree->data){
return;
}
}
二、查询排序二叉树的目标节点
注意引用 tree
//查找
int getPosition(BSTree &tree,int postion,ElementType x){
if (tree!=NULL&&x==tree->data){
return tree->data;
}
if (x>tree->data){
return getPosition(tree->rchild,0,x);
} else{
return getPosition(tree->lchild,0,x);
}
}
三、删除二叉排序树的节点
注意引用
注意左子树右子树都不为空的情况 删除的时候递归删除 因为我们不知道它的父亲节点
注意记得删除前改变被删除的位置的地址
//删除节点
void delTNode(BSTree &tree,ElementType x){
if (tree==NULL){
return;
}
BSTNode *temp=tree;
if (x>temp->data){
delTNode(tree->rchild,x);
}
if (x<temp->data){
delTNode(tree->lchild,x);
}
if (x==temp->data){
if (temp->lchild==NULL&&temp->rchild!=NULL){
//注意记得改变此时被删除的位置的地址
tree=temp->rchild;
free(temp);
}
if (temp->rchild==NULL&&temp->lchild!=NULL){
//注意记得改变此时被删除的位置的地址
tree=temp->lchild;
free(temp);
}
if (temp->lchild==NULL&&temp->rchild==NULL){
//注意记得改变此时被删除的位置的地址
tree=NULL;
free(temp);
}
if (temp->lchild!=NULL&&temp->rchild!=NULL){
//左右子树都不为空
//找左子树的左右边
//或者找右子树的最左边来代替
temp=temp->lchild;
while (temp->rchild!=NULL){
temp=temp->rchild;
}
tree->data=temp->data;
//因为这时候有俩个一样的值了 我们要确认我们要删除的是哪个值
//因此这里应该删除这个节点的左子树上那个替死鬼
delTNode(tree->lchild,temp->data);
}
}
}
四、完整代码
#include <stdio.h>
#include <stdlib.h>
typedef int ElementType;
typedef struct BSTNode{
ElementType data;
BSTNode *rchild;
BSTNode *lchild;
}BSTNode,*BSTree;
/**
* 构造二叉排序树
* @param tree
* @param x
*/
void buildTree(BSTree &tree,ElementType &x){
if (tree==NULL){
tree=(BSTree) calloc(1, sizeof(BSTNode));
tree->data=x;
//注意
return;
}
if (x>tree->data){
buildTree(tree->rchild,x);
}
if (x<tree->data){
buildTree(tree->lchild,x);
}
if (x==tree->data){
return;
}
}
//查找
int getPosition(BSTree &tree,int postion,ElementType x){
if (tree!=NULL&&x==tree->data){
return tree->data;
}
if (x>tree->data){
return getPosition(tree->rchild,0,x);
} else{
return getPosition(tree->lchild,0,x);
}
}
//删除节点
void delTNode(BSTree &tree,ElementType x){
if (tree==NULL){
return;
}
BSTNode *temp=tree;
if (x>temp->data){
delTNode(tree->rchild,x);
}
if (x<temp->data){
delTNode(tree->lchild,x);
}
if (x==temp->data){
if (temp->lchild==NULL&&temp->rchild!=NULL){
//注意记得改变此时被删除的位置的地址
tree=temp->rchild;
free(temp);
}
if (temp->rchild==NULL&&temp->lchild!=NULL){
//注意记得改变此时被删除的位置的地址
tree=temp->lchild;
free(temp);
}
if (temp->lchild==NULL&&temp->rchild==NULL){
//注意记得改变此时被删除的位置的地址
tree=NULL;
free(temp);
}
if (temp->lchild!=NULL&&temp->rchild!=NULL){
//左右子树都不为空
//找左子树的左右边
//或者找右子树的最左边来代替
temp=temp->lchild;
while (temp->rchild!=NULL){
temp=temp->rchild;
}
tree->data=temp->data;
//因为这时候有俩个一样的值了 我们要确认我们要删除的是哪个值
//因此这里应该删除这个节点的左子树上那个替死鬼
delTNode(tree->lchild,temp->data);
}
}
}
//中序遍历 对于二叉排序树来说中序遍历就是从小到大依次排序
void inOrder(BSTree tree){
if (tree==NULL){
return;
}
inOrder(tree->lchild);
printf("%3d",tree->data);
inOrder(tree->rchild);
}
int main() {
BSTree tree;
ElementType str[7]={56,20,30,1,3,78,9};
//注意
tree=(BSTree) calloc(1, sizeof(BSTNode));
tree->data=56;
for (int i = 1; i < 7; ++i) {
buildTree(tree,str[i]);
}
ElementType x;
x=getPosition(tree,0,1);
printf("%d\n",x);
delTNode(tree,1);
inOrder(tree);
return 0;
}
五、折半查找OJ练习
读取10个元素 87 7 60 80 59 34 86 99 21 3,然后建立二叉查找树, 中序遍历输出3 7 21 34 59 60 80 86 87 99, 针对有序后的元素,存入一个长度为10的数组中,通过折半查找找到21的下标(下标为2), 然后输出2
//折半查找
int getPosition(ElementType A[],ElementType x,int low,int high){
if (low>=high){
return -1;
}
int mid=(low+high)/2;
if (A[mid]==x){
return mid;
}
if (x>A[mid]){
return getPosition(A,x,mid+1,high);
} else{
return getPosition(A,x,low,mid-1);
}
}
完整代码
#include <stdio.h>
#include <stdlib.h>
/**
* 读取10个元素 87 7 60 80 59 34 86 99 21 3,然后建立二叉查找树,
* 中序遍历输出3 7 21 34 59 60 80 86 87 99,
* 针对有序后的元素,存入一个长度为10的数组中,通过折半查找找到21的下标(下标为2),然后输出2
*/
typedef int ElementType;
typedef struct BSTNode{
ElementType data;
BSTNode *rchild;
BSTNode *lchild;
}BSTNode,*BSTree;
/**
* 构造二叉排序树
* @param tree
* @param x
*/
void buildTree(BSTree &tree,ElementType &x){
if (tree==NULL){
tree=(BSTree) calloc(1, sizeof(BSTNode));
tree->data=x;
//注意
return;
}
if (x>tree->data){
buildTree(tree->rchild,x);
}
if (x<tree->data){
buildTree(tree->lchild,x);
}
if (x==tree->data){
return;
}
}
//查找
int getPosition(BSTree &tree,int postion,ElementType x){
if (tree!=NULL&&x==tree->data){
return tree->data;
}
if (x>tree->data){
return getPosition(tree->rchild,0,x);
} else{
return getPosition(tree->lchild,0,x);
}
}
//删除节点
void delTNode(BSTree &tree,ElementType x){
if (tree==NULL){
return;
}
BSTNode *temp=tree;
if (x>temp->data){
delTNode(tree->rchild,x);
}
if (x<temp->data){
delTNode(tree->lchild,x);
}
if (x==temp->data){
if (temp->lchild==NULL&&temp->rchild!=NULL){
//注意记得改变此时被删除的位置的地址
tree=temp->rchild;
free(temp);
}
if (temp->rchild==NULL&&temp->lchild!=NULL){
//注意记得改变此时被删除的位置的地址
tree=temp->lchild;
free(temp);
}
if (temp->lchild==NULL&&temp->rchild==NULL){
//注意记得改变此时被删除的位置的地址
tree=NULL;
free(temp);
}
if (temp->lchild!=NULL&&temp->rchild!=NULL){
//左右子树都不为空
//找左子树的左右边
//或者找右子树的最左边来代替
temp=temp->lchild;
while (temp->rchild!=NULL){
temp=temp->rchild;
}
tree->data=temp->data;
//因为这时候有俩个一样的值了 我们要确认我们要删除的是哪个值
//因此这里应该删除这个节点的左子树上那个替死鬼
delTNode(tree->lchild,temp->data);
}
}
}
//中序遍历 对于二叉排序树来说中序遍历就是从小到大依次排序
void inOrder(BSTree tree){
if (tree==NULL){
return;
}
inOrder(tree->lchild);
printf("%3d",tree->data);
inOrder(tree->rchild);
}
int i=0;
//中序遍历 对于二叉排序树来说中序遍历就是从小到大依次排序
void inOrderI(BSTree tree,ElementType A[]){
if (tree==NULL){
return;
}
inOrderI(tree->lchild,A);
A[i++]=tree->data;
printf("%3d",tree->data);
inOrderI(tree->rchild,A);
}
//折半查找
int getPosition(ElementType A[],ElementType x,int low,int high){
if (low>=high){
return -1;
}
int mid=(low+high)/2;
if (A[mid]==x){
return mid;
}
if (x>A[mid]){
return getPosition(A,x,mid+1,high);
} else{
return getPosition(A,x,low,mid-1);
}
}
int main() {
BSTree tree;
//注意
tree=(BSTree) calloc(1, sizeof(BSTNode));
ElementType x;
scanf("%d",&x);
tree->data=x;
for (int i = 1; i <= 9; ++i) {
scanf("%d",&x);
buildTree(tree,x);
}
ElementType A[10];
inOrderI(tree,A);
printf("\n");
int position=getPosition(A,21,0,9);
printf("%d\n", position);
return 0;
}
六、折半查找 (真题)中位数应用
注意最后是s / d 的位置的值
注意移动的时候数组长度是变化的
1. 判断哪个中位数小
保证消掉的元素个数是相等的
奇数个长度 消掉小的前面的所有元素 大的后面的所有元素
偶数个长度 消掉小的前面的所有元素及其它本身 大的后面的所有元素
2.退出循环的条件是 s1!=d1|| s2!=d2 --直到俩个数组中就s1d1都指向一个元素 s2d2同理
#include <stdio.h>
void NarrowScope(int n, int m1, int m2, int &s2, int &d1);
//不合并查找中位数--去掉数 --就是移动下标
int getMidA_B(int A[],int B[],int n){
//分别为 A B的 首尾 中位数 所在下标位置
int s1,s2,d1,d2,m1,m2;
s1=s2=0;d1=d2=n-1;
m1=(s1+d1)/2;
m2=(s2+d2)/2;
if (A[m1]==B[m2]){
return A[m1];
}
//去掉小哪个中位数之前的数 注意分奇偶
//去掉大的那个中位数之后的数 注意分奇偶
//循环判断哪个中位数大--缩小范围--直到俩个数组中都只剩下一个数s1=d1 s2=d2时 小的那个即为中位数
while (s1!=d1||s2!=d2){
m1=(s1+d1)/2;
m2=(s2+d2)/2;
if (A[m1]==B[m2]){
return A[m1];
}
if (A[m1]>B[m2]){
if ((s1+d1)%2==0){
//奇数个
//去掉大的之后的所有数
d1=m1;
//去掉小的之前的所有数
s2=m2;
} else{
//偶数个
//去掉大的 之后的所有数
d1=m1;
//去掉小的 中位数及之前的所有数
s2=m2+1;
}
}
if (A[m1]<B[m2]){
if ((s1+d1)%2==0){
//奇数个
//去掉大的之后的所有数
d2=m2;
//去掉小的之前的所有数
s1=m1;
} else{
//偶数个
//去掉大的 之后的所有数
d2=m2;
//去掉小的 中位数及之前的所有数
s1=m1+1;
}
}
}
//注意这里 要的是s / d 而不是m 因为最终s 与d会重合
return A[s1]>B[s2]?B[s2]:A[s1];
}
int main() {
int A[]={11,13,15,17,19};
int B[]={2,4,6,8,20};
int n=5;
int mid=getMidA_B(A,B,n);
printf("%d\n",mid);
return 0;
}