排序二叉树--二叉树线索化

参考

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;
}

七、二叉树的线索化 

中序线索化 

先序线索化--因为访问D的时候还是回到跟B因此爱的魔力转圈圈 

注意处理它不是前驱线索 

八、二叉树的WPL计算 

答案一 

 

 

答案二 

 

 

 

九、并查集注意路径压缩优化 

 

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值