数据结构基础 查找

线性表的查找技术

线性表一般有两种存储结构:顺序存储结构链接存储结构

顺序查找

基本思想:

  • 从线性表的一端向另一端逐个将关键码与给定值进行比较;
  • 若相等,则查找成功,给出该记录在表中的位置;
  • 若查找失败,则给出失败信息。

(1)顺序表的顺序查找
设置哨兵,将它放在查找方向的“尽头”处,这样每次比较后都无需判断查找位置是否越界。
Search.h

//
// Copyright: Created by 野尽, Ye Jin. 596859576@qq.com
// Author: 野尽
// Date: 2020/4/7
// Description: 
//
#ifndef SEQLIST_CLASSTEMPLATEINHFILE__SEARCH_H
#define SEQLIST_CLASSTEMPLATEINHFILE__SEARCH_H

#include <iostream>
using namespace std;

//
// Function: SeqSearchSeqList
// Description: 顺序表的顺序查找
// Calls: NULL
// Table Accessed: NULL
// Table Updated: NULL
// Input: int r[] 待查找序列, int n 序列长度, int k 待查找元素
// Output: 待查找元素下标,若查找失败则返回0
// Return: 待查找元素下标,若查找失败则返回0
// Others: NULL
//
int SeqSearchSeqList(int r[], int n, int k)
{
    // 设置下标0作为哨兵
    r[0] = k;
    int i = n - 1;
    while (r[i] != k) {

        cout<<r[i]<<" ";
        i--;
    }
    cout<<endl;

    return i;
}

#endif //SEQLIST_CLASSTEMPLATEINHFILE__SEARCH_H

main.cpp

#include "Search.h"

int main() {

 SeqSearchSeqList
    const int n = 11;
    // 待查找序列的下标0元素是哨兵,此位置初始化任意一个数,此例中初始为0
    // 序列从下标1开始
    int a[n] = {0,7,5,4,2,6,9,1,8,3,10};
    int key = 7;

    // 当查找位置为0时,说明查找失败
    int pos = SeqSearchSeqList(a, n, key);
    if (pos != 0)
        cout<<"待查找值 "<<key<<" 的位置是 " << pos <<endl;
    else
        cout<<"未发现待查找值 "<<key<<endl;
    cout<<endl;

    key = 12;
    // 当查找位置为0时,说明查找失败
    pos = SeqSearchSeqList(a, n, key);
    if (pos != 0)
        cout<<"待查找值 "<<key<<" 的位置是 " << pos <<endl;
    else
        cout<<"未发现待查找值 "<<key<<endl;
    cout<<endl;
    
    return 0;
}

测试结果:

10 3 8 1 9 6 2 4 5 
待查找值 7 的位置是 1

10 3 8 1 9 6 2 4 5 7 
未发现待查找值 12

(2)单链表的顺序查找
Search.h

//
// Copyright: Created by 野尽, Ye Jin. 596859576@qq.com
// Author: 野尽
// Date: 2020/4/7
// Description: 
//
#ifndef SEQLIST_CLASSTEMPLATEINHFILE__SEARCH_H
#define SEQLIST_CLASSTEMPLATEINHFILE__SEARCH_H

#include <iostream>
#include "LinkList.h"
using namespace std;

//
// Function: SeqSearchLinkList
// Description: 单链表的顺序查找
// Calls: NULL
// Table Accessed: NULL
// Table Updated: NULL
// Input: Node<int> * first 链表的头指针, int k 待查找值
// Output: NULL
// Return: NULL
// Others: NULL
//
int SeqSearchLinkList(Node<int> * first, int k)
{
    Node<int> * p = first->next;
    int pos = 1;

    while (p != NULL && p->data != k)
    {
        p = p->next;
        pos++;
    }

    if (p != NULL && p->data == k)
        return pos;
    else
        return 0;
}

#endif //SEQLIST_CLASSTEMPLATEINHFILE__SEARCH_H

main.cpp

#include "Search.h"

int main() {

// SeqSearchLinkList
    const int n = 10;
    int a[n] = {7,5,4,2,6,9,1,8,3,10};
    int key = 9;

    LinkList<int> linkList(a, n);
    linkList.PrintList();

    // 得到链表头指针
    Node<int> * p = linkList.GetFirstPointer();
    // 当查找位置为0时,说明查找失败
    int pos = SeqSearchLinkList(p, key);
    if (pos != 0)
        cout<<"待查找值 "<<key<<" 的位置是 " << pos <<endl;
    else
        cout<<"未发现待查找值 "<<key<<endl;
    cout<<endl;

    key = 12;
    // 当查找位置为0时,说明查找失败
    pos = SeqSearchLinkList(p, key);
    if (pos != 0)
        cout<<"待查找值 "<<key<<" 的位置是 " << pos <<endl;
    else
        cout<<"未发现待查找值 "<<key<<endl;
    cout<<endl;

    return 0;
}

测试结果:

 7 5 4 2 6 9 1 8 3 10
待查找值 9 的位置是 6

未发现待查找值 12

注意:单链表的查找需要引用#include "LinkList.h",这个头文件在我博客中有,复制下来直接用就行了。

折半查找

折半查找要求线性表中的记录必须 按关键码有序,并且必须采用 顺序存储

基本思想:

  • 有序表 中,取中间记录作为比较对象,若给定值与中间记录的关键码相等,则查找成功;
  • 若给定值小于中间记录的关键码,则在中间记录的左半区继续查找;
  • 若给定值大于中间记录的关键码,则在中间记录的右半区继续查找;
  • 不断重复上述步骤,直到查找成功,或所查找的区域无记录。

(1)非递归算法
Binary.h

//
// Copyright: Created by 野尽, Ye Jin. 596859576@qq.com
// Author: 野尽
// Date: 2020/4/7
// Description: 
//
#ifndef SEQLIST_CLASSTEMPLATEINHFILE__SEARCH_H
#define SEQLIST_CLASSTEMPLATEINHFILE__SEARCH_H

#include <iostream>
#include "LinkList.h"
using namespace std;

//
// Function: BinarySearchRecurse
// Description: 折半查找的非递归算法
// Calls: NULL
// Table Accessed: NULL
// Table Updated: NULL
// Input: int r[] 待查找序列, int n 序列长度, int k 待查找值
// Output: 若查找成功,则返回待查找值的位置;若失败,则返回0.
// Return: 若查找成功,则返回待查找值的位置;若失败,则返回0.
// Others: NULL
//
int BinarySearchRecurse(int r[], int n, int k)
{
    int low = 1;
    int high = n;

    while (low<=high)
    {
        int mid = (low + high) / 2;

        if (k < r[mid])
            high = mid - 1;
        else if (k > r[mid])
            low = mid + 1;
        else
            return mid;
    }

    return 0;
}

#endif //SEQLIST_CLASSTEMPLATEINHFILE__SEARCH_H

main.cpp

#include "Search.h"

int main() {

// BinarySearchRecurse
    const int n = 15;
    int a[n] = {1,2,3,9,12,15,22,25,27,31,33,34,35,36,41};
    int key = 12;

    // 当查找位置为0时,说明查找失败
    int pos = BinarySearchRecurse(a, n, key);
    if (pos != 0)
        cout<<"待查找值 "<<key<<" 的位置是 " << pos <<endl;
    else
        cout<<"未发现待查找值 "<<key<<endl;
    cout<<endl;

    key = 45;
    // 当查找位置为0时,说明查找失败
    pos = BinarySearchRecurse(a, n, key);
    if (pos != 0)
        cout<<"待查找值 "<<key<<" 的位置是 " << pos <<endl;
    else
        cout<<"未发现待查找值 "<<key<<endl;
    cout<<endl;

    return 0;
}

测试结果:

待查找值 12 的位置是 4

未发现待查找值 45

(2)折半查找的递归算法
Binary.h

//
// Copyright: Created by 野尽, Ye Jin. 596859576@qq.com
// Author: 野尽
// Date: 2020/4/7
// Description: 
//
#ifndef SEQLIST_CLASSTEMPLATEINHFILE__SEARCH_H
#define SEQLIST_CLASSTEMPLATEINHFILE__SEARCH_H

#include <iostream>
#include "LinkList.h"
using namespace std;

//
// Function: BinarySearch
// Description: 折半查找的递归算法
// Calls: NULL
// Table Accessed: NULL
// Table Updated: NULL
// Input: int r[] 待查找序列, int low 区间低端, int high 区间高端, int k 待查找值
// Output: 若查找成功,则返回待查找值的位置;若失败,则返回0.
// Return: 若查找成功,则返回待查找值的位置;若失败,则返回0.
// Others: NULL
//
int BinarySearch(int r[], int low, int high, int k)
{
    if (low>high)
        return 0;
    else
    {
        int mid = (low + high) / 2;
        if (k<r[mid])
            return BinarySearch(r, low, mid - 1, k);
        else if (k>r[mid])
            return BinarySearch(r, mid + 1, high, k);
        else
            return mid;
    }
}
#endif //SEQLIST_CLASSTEMPLATEINHFILE__SEARCH_H

main.cpp

#include "Search.h"

int main() {

    // BinarySearch
    key = 15;
    // 当查找位置为0时,说明查找失败
    pos = BinarySearch(a, 1, n, key);
    if (pos != 0)
        cout<<"待查找值 "<<key<<" 的位置是 " << pos <<endl;
    else
        cout<<"未发现待查找值 "<<key<<endl;
    cout<<endl;

    key = 5;
    // 当查找位置为0时,说明查找失败
    pos = BinarySearchRecurse(a, n, key);
    if (pos != 0)
        cout<<"待查找值 "<<key<<" 的位置是 " << pos <<endl;
    else
        cout<<"未发现待查找值 "<<key<<endl;
    cout<<endl;

    return 0;
}

测试结果:

待查找值 15 的位置是 5

未发现待查找值 5

树表的查找技术

(1)二叉排序树
二叉排序树又称为二叉查找树,具有如下性质:

  • 若它的左子树不空,则左子树上所有结点的值均小于根结点的值;
  • 若它的右子树不空,则右子树上所有节点的值均大于根结点的值;
  • 它的左右子树均为二叉排序树。
    中序遍历二叉排序树可以得到一个按关键码有序的序列。

二叉树的插入

  • 若 root 为空,则将结点 s 作为根结点插入;
  • 否则,若s->data小于root->data,则把结点 s 插入到 root 的左子树中;
  • 否则把结点 s 插入到 root 的右子树中。

二叉树的构造

  • 依次取每个记录 r[i] ,执行下述操作;
  • 申请一个数据域为 r[i] 的结点 s ,令结点 s 的左右指针域为空;
  • 调用插入算法InsertBST,将结点 s 插入到二叉排序树中。

二叉排序树的 删除
二叉排序树执行删除操作时,需要注意执行删除之后,需要保证删除之后其仍为二叉排序树。
下面讨论在二叉排序树中删除最小结点。设待删除结点为 p,其双亲结点为 f,p 为 f 的左孩子。

有以下三种情况:
<1> p 为叶子结点,即 p 没有左子树也没有右子树

  • 由于删除 p 之后没有影响二叉排序树的特性,所以只需将被删除结点的双亲结点的相应指针域置为空指针,即 f->lchild = NULL。

<2> p 只有左子树 pL 或 只有右子树 pR

  • 此时,只需将 pL 或 pR 替换为 f 的左子树,即 f->lchild = p->lchild 或 f->lchild = p->rchild。

<3> p 既有左子树 pL 也有右子树 pR

  • 此时需要在被删除结点 p 的子树上找到一个大于 p 结点的最小值,或小于 p 结点的最大值来代替 p 的值,然后再删除结点 s。

实现:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值