数据结构之查找算法

这里为大家介绍几个常用的查找算法和二叉排序树的相关代码,包括顺序查找、折半查找、分块查找、基于二叉排序树的查找删除等

1、顺序查找
顺序查找法是逐一比较指定的关键字和线性表中的各个元素的关键字,直到查找成功或者查找失败,具体实现代码如下:

/**
 * 顺序查找
 * @param s:查找源 
 * @param n :数据源长度
 * @param key :关键字 
 * @return :返回成功的位置或-1
 */
int search(int s[], int n, int key) {
    int i;
    for (i = 0; i < n && s[i] != key; i++);
    if (i < n)
        return i;
    else
        return -1;
}

对于上面的顺序查找算法还是可以进行改进的,每次在for循环中都要比较两次,这无疑是花费更长的时间,因此我们可以在表的末端增加空的单元格用于存储要查找的关键字,如此便不需要比较 i 和 n 的大小了,因为它总是会查找成功,如果返回值为 n 则说明查找失败了,改进的代码如下:


/**
 * 顺序查找法,
 * @param s :按关键字排列的表
 * @param n :顺序表的长度
 * @param key :关键字
 * @return :关键字所在的位置
 */
int search(int s[], int n, int key) {
    int i;
    for (i = 0; s[i] != key; ++i);
    if (i < n)
        return i;
    else
        return -1;
}

// 在创建数据源和查找关键字的时候 保存 key 值到最后一个位置
sourceArray [LENGTH] = iKey;
iPosition = search(sourceArray, LENGTH, iKey);

2、折半查找
折半查找又被称为二分法查找法,不过该方法要求待查询的数据源必须是按关键字大小排序的顺序表。折半查找的优点很明显,它具有比较次数少、查找速度快,但缺点是必须是有序表,且插入和删除比较困难,因此它不适合用于经常变动的列表。

具体代码:

/**
 * 折半查找法,适用于顺序排列的表
 * @param s :按关键字排列的表
 * @param n :顺序表的长度
 * @param key :关键字
 * @return :关键字所在的位置
 */
int binSearch(int s[], int n, int key) {
    int low, high, mid;
    low = 0;
    high = n - 1;
    while (low <= high) {
        // 计算中间位置序号
        mid = (low + high) / 2;
        if (s[mid] == key)
            return mid;
        else if (s[mid] > key)
            high = mid - 1;
        else
            low = mid + 1;
    }
    return -1;
}

3、分块查找
分块查找法对于列表也是有要求的,它需要将列表做成有索引顺序的结构,将数据源分成若干块,构造索引表,每一个索引项对应一个块的起始位置和最大或最小关键字

4、二叉排序树
对于二叉排序树的相关概念在这里就不介绍了,这里主要说一下它的相关代码


typedef struct binaryTree {
    int data;
    struct binaryTree *left;
    struct binaryTree *right;
} BinarySortTree;

/**
 * 在一个二叉树中插入元素
 * @param t :二叉排序树
 * @param key:关键字
 */
void insert(BinarySortTree *t, int key)
{
    BinarySortTree *p, *parent, *head;

    //申请内存空间
    p = (BinarySortTree *) malloc(sizeof(BinarySortTree *));
    if ( !p )
    {
        printf("申请内存出错!\n");
        exit(0);
    }

    //保存结点数据
    p->data = key;
    //左右子树置空
    p->left = p->right = NULL;
    head = t;

    //查找需要添加的父结点
    while (head)
    {
        parent = head;
        if (key < head->data) //若关键字小于结点的数据
            head = head->left; //在左子树上查找
        else                 //若关键字大于结点的数据 
            head = head->right;  //在右子树上查找
    }
    //判断添加到左子树还是右子树 
    if (key < parent->data) {
        //小于父结点,添加到左子树
        parent->left = p;
    }
    else
    {
        //大于父结点,添加到右子树
        parent->right = p;
    }
}

/**
 * 创建二叉排序树,通过上面所定义的插入函数
 * @param t :二叉树
 * @param data :数据源数组
 * @param n :个数
 */
void create(BinarySortTree *t, int data[], int n)
{
    int i;
    t->data = data[0];
    t->left = t->right = NULL;
    for (i = 1; i < n; i++) {
        insert(t, data[i]);
    }
}

/**
 * 中序遍历
 * @param t
 */
void inOrder(BinarySortTree *t)
{
    if (t)//树不为空,则执行如下操作
    {
        inOrder(t->left); //中序遍历左子树
        printf("%d ", t->data); //输出结点数据
        inOrder(t->right); //中序遍历右子树/
    }
    return;
}

BinarySortTree *search(BinarySortTree *t, int key) {
    if (!t || t->data == key) //结点为空,或关键字相等 
        return t;          //返回结点指针
    else if (key > t->data) //关键字大于结点数据
        return (search(t->right, key));
    else
        return (search(t->left, key));
}

//删除结点
void delete(BinarySortTree *t, int key) {
    BinarySortTree *p, *parent, *l, *l1;
    int child = 0;//0表示左子树,1表示右子树 
    if (!t) return;     //二叉排序树为空,则退出
    p = t;
    parent = p;
    while (p)           //二叉排序树有效 
    {
        if (p->data == key) {
            if (!p->left && !p->right) //叶结点(左右子树都为空) 
            {
                if (p == t) //被删除的是根结点 
                {
                    free(p);//释放被删除结点 
                } else if (child == 0) //父结点为左子树 
                {
                    parent->left = NULL; //设置父结点左子树为空 
                    free(p); //释放结点空间 
                } else //父结点为右子树 
                {
                    parent->right = NULL; //设置父结点右子树为空 
                    free(p); //释放结点空间 
                }
            } else if (!p->left) //左子树为空,右子树不为空
            {
                if (child == 0) //是父结点的左子树
                    parent->left = p->right;
                else //是父结点的右子树             
                    parent->left = p->left;
                free(p); //释放被删除结点
            } else if (!p->right)//右子树为空,左子树不为空
            {
                if (child == 0) //是父结点的左子树
                    parent->right = p->right;
                else //是父结点的右子树             
                    parent->right = p->left;
                free(p); //释放被删除结点       
            } else  //左右子树都不为空 
            {
                l1 = p; //保存左子树的父结点 
                l = p->right; //从当前结点的右子树进行查找 
                while (l->left) //左子树不为空 
                {
                    l1 = l;
                    l = l->left; //查找左子树 
                }
                p->data = l->data; //将左子树的数据保存到被删除结点
                l1->left = NULL; //设置父结点的左子树指针为空 
                free(l1); //释放左子树占的内存空间
            }
            p = NULL;
        } else if (key < p->data) //需删除记录的关键字小于结点的数据 
        {
            child = 0;//标记在当前结点左子树查找
            parent = p; //保存当前结点作父结点 
            p = p->left; //查找右子树 
        } else //需删除记录的关键字大于结点的数据 
        {
            child = 1;//标记在当前结点右子树查找
            parent = p;//保存当前结点作父结点 
            p = p->right; //查找右子树 
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值