查找算法与二叉排序树

#顺序查找

顾名思义按照顺序依次与查找值进行比对最后返回位置,利用哨兵可以减少比对条件。也就是将第一个位置给空出来放入查找值,这个就是哨兵,然后从数组尾部依次往前与哨兵比对,比对成功返回位置,比对失败返回0.


//顺序查找
int SSearch(SSTable st,Elemtype key)
{
    int pos;
    st.elem[0] = key; //设置哨兵 从后往前找 可以简化查找条件
    for (pos = st.STbaleLen; st.elem[pos] != st.elem[0]; --pos) ;
    return pos;
}

#二分查找

也成为折半查找,在使用这个查找方法之前一定要将数组进行排序,数组长度每次折半,直到比对成功或者没有匹配到该值返回下标或者-1,设置两个指针分别指向数组开头与末尾,取下标中间值,让该位置的数组值与所查找值进行比对,如果大于查找值则说明需要查找的值在数组的后半段,那么这个时候就不需要再去查找数组前半段了,这个时候让指针low等于中间下标+1即可得到后半段数组,反之如果数组下标中间值小于需要查找的值那么就直接找数组前半段的值就可以了,如果相等直接返回下标,重复上述操作,让数组一直折半,就可以提升查找速度,循环条件为low指针小于high指针

//二分查找
int BinarySearch(SSTable ST,Elemtype key)
{
    //定义两个指针查找中间值
    int low = 0;
    int high = ST.STbaleLen - 1;
    while (low < high)
    {
        int mid = (low + high) /2;
        if(key < ST.elem[mid])
        {
            high = mid -1;
        } else if(key > ST.elem[mid])
        {
            low = mid +1;
        }else if(key == ST.elem[mid])
        {
            return mid;
        }
    }
    return -1;
}

#二叉排序树

 二叉排序树的创建实际上是由二叉排序树的查找与插入实现的,二叉排序树的创建原理,当根节点为空的时候,直接将结点插入进根节点,不为空时开始查找,当新创建节点值小于父节点的时候作为父结点的左子树,当大于父结点的值的时候作为父节点的右子树,循环此操作找到应该插入的位置再插入即可。下面给出两种方式 一种为非递归创建,一种为递归创建。

Tips:一般二叉排序树都是用中序遍历 因为中序遍历二叉排序树遍历出来的数值为升序

非递归创建:

#include <cstdlib>
#include "stdio.h"

typedef int KeyType;

typedef struct BiTnode{
    KeyType data;
    struct BiTnode *Lchild; //左子树
    struct BiTnode *Rchild; //右子树
}BiTnode, *BiTree;



void BST_Insert(BiTree &T,KeyType k) {
     BiTree TreeNew = (BiTnode *)calloc(1,sizeof (BiTnode)); //申请新节点
     TreeNew->data = k ; // 每次申请完先把值放入结点
    if(T == NULL)
    {
        T = TreeNew;
        return;
    }
    BiTree  parent;
    BiTree p = T;// 用来进行查找操作 以及记录父节点值
    while (p)   //这里就相当于二叉排序树的查找算法 因为是重复一种
       {       // 操作直到查找到应该放置的位置为空 所以用循环或者递归
        parent = p; // 记录每次的父结点
        if(k > p->data) //大于放右边
        {
            p = p->Rchild;
        }else if(k < p->data)
        {
            p = p->Lchild;
        } else{
            return  ; //然而二叉排序树中不能放入两个值相等的数
        }
    }
    //查找到要放的位置之后  需要记录他的父节点 因为要放置的位置一定是叶子结点的子树,因此此时P为NULL 不能对结点进行赋值
    if(k < parent->data)
    {
        parent->Lchild = TreeNew;
    }else if(k > parent->data)
    {
        parent->Rchild = TreeNew;
    }
}

//创建树
void CreateBST(BiTree &T, KeyType *str, int len) {
    int i;
    for (i = 0; i < len; i++) {  //把数组中每一个数据依次插入到二叉排序树中实现二叉排序树
        BST_Insert(T,str[i]);   //每一次插入都是相当于二叉排序树查找算法
    }
}

//中序遍历
void MidOrder(BiTree tree)
{
    if(tree != NULL)
    {
        MidOrder(tree->Lchild);
        printf("%3d",tree->data);
        MidOrder(tree->Rchild);
    }
}

void CreateBST(BiTree pTnode);

int main() {
    BiTree tree = NULL;
    //创建二叉排序树实际上就是二叉排序树查找与二叉排序树插入操作相结合
    KeyType str[7] = {54,20,66,40,28,79,58}; // 将要进入二叉排序树的值
    CreateBST(tree,str,7);
    MidOrder(tree);


    return 0;
}


递归方式: 主要是用到了引用这一特性 非常的巧妙 他会自动将插入父节点的子树中

int BST_Insert1(BiTree &T,KeyType k)
{
   if(T == NULL)
   {
       T =(BiTnode*)calloc(1,sizeof (BiTnode)); //calloc函数会自动将结构体初始化为NULL
       T->data = k;
       return 1;//表示插入成功
   } else if(k < T->data)
   {
       return BST_Insert1(T->Lchild,k); //调用函数 利用了引用的特性自动插入到父结点中
   } else if(k > T->data)
    {
        return BST_Insert1(T->Rchild,k);
    } else{
       return -1; //值相等 匹配失败
   }
}

#二叉顺序树删除结点

 如果删除的值小于根节点的值 那么根据二叉顺序树的特性应该去该根节点的左子树去找,如果大于根节点的值应该去右子树中寻找,如果值相同 那就说明需要删除的就是该结点,这里分两种情况 删除叶子结点或者删除根节点删除叶子结点 因为叶子结点的特性为 要么两个子树都为空 要么其中一个为空的结点为叶子结点 因此在删除叶子节点之后只需要他的左子树或者右子树代替他就可以了 还是满足二叉顺序树的规则,第二种情况 删除的为根结点 当你删除的为根节点的时候 如果不找结点代替 该树就会被拆成多个子树 这显然是不符合规定的  因此我们就可以找左子树中的最右结点或者右子树的最左结点 因为左子树的最右结点即为左子树中最大的结点,并且左子树的中的最大值一定是小于根节点中右子树的最小值的, 而右子树的最左结点为右子树中最小的结点 找这两种结点其中一个上去代替都不会破坏二叉排序树的规则,最后把对应的值给替换上去 不可以用结点直接替换 因为最后结点可能还有左子树或右子树,在根节点的左子树中找到替换的结点并且删除。

//删除结点  通过递归实现 通过递归找到值并且删除
int DeleteNode(BiTree &root,KeyType k)
{
    if(root == NULL)
    {
        return -1; //如果传入的结点为空那么删除失败
    } else if(k < root->data) // 如果删除的值小于根节点的值 那么根据二叉顺序树的特性应该去该根节点的左子树去找
    {
        DeleteNode(root->Lchild,k); //递归寻找该值
    } else if(k > root->data)
    {
        DeleteNode(root->Rchild,k); //右子树同理
    } else{ //如果值相同 那就说明需要删除的就是该结点,这里分两种情况 删除叶子结点或者删除根节点
        //删除叶子结点 因为叶子结点的特性为 要么两个子树都为空 要么其中一个为空的结点为叶子结点
        //因此在删除叶子节点之后只需要他的左子树或者右子树代替他就可以了 还是满足二叉顺序树
         // 创建临时节点存储根节点
        if(root->Lchild == NULL) // 左子树为空 右子树顶上去
        {
            BiTree tempNode = root;
            root = root->Rchild;
            free(tempNode);
        } else if(root->Lchild == NULL)// 右子树为空 左子树顶上去
        {
            BiTree tempNode = root;
            root = root->Lchild;
            free(tempNode);
        } else{
            //第二种情况 删除的为根结点 当你删除的为根节点的时候 如果不找结点代替
            //该树就会被拆成多个子树 这显然是不符合规定的
            // 因此我们就可以找左子树中的最右结点或者右子树的最左结点
            //因为左子树的最右结点即为左子树中最大的结点 而右子树的最左结点为右子树中最小的结点
            //找这两种结点其中一个上去代替都不会破坏二叉排序树的规则
            BiTree tempNode = root->Lchild; //左子树的最右结点
            while (tempNode->Rchild != NULL)
            {
                tempNode = tempNode->Rchild;
            }
            root->data = tempNode->data; //把对应的值给替换上去 不可以用结点直接替换 因为最后结点可能还有左子树或右子树
            DeleteNode(root->Lchild,tempNode->data); // 在根节点的左子树中找到代替根节点的结点并删除
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值