C++数据结构的一些代码(查找部分)

本文探讨了动态查找中的二叉排序树实现,包括查找、插入和删除操作,其中删除函数有待优化。同时,介绍了哈希查找的线性探测、平方探测和链地址法三种方法,并提供了相关代码示例。通过引用代替二级指针优化了二叉排序树的插入和删除操作,简化了代码。此外,展示了不同哈希冲突解决策略对查找效率的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

五、查找

1.动态查找

1.1二叉排序树

相关功能有查找,插入,删除;难点在于二级指针的使用。
下述代码的删除函数应当还有待优化。

#include <iostream>
using namespace std;

class TreeNode
{
public:
    int data;
    TreeNode *left, *right;

    TreeNode() { left = right = NULL; }
    TreeNode(int key) : data(key) { left = right = NULL; }
};
class BinTree
{
public:
    TreeNode *root;

    BinTree(int arr[], int n) : root(NULL)
    {
        for (int i = 0; i < n; i++)
        {
            Insert(root, arr[i]);
        }
    }
    //当前节点,查找值,当前节点的双亲结点,如果找到则等于找到结点的指针,否则等于查找到的最后一个结点,函数返回false
    //这个二级指针太关键了,传入的是外界指针p的指针地址,然后对*p的操作就是直接操作外界指针的地址,从而达到改变外界指针的目的
    bool Search(TreeNode *r, int key, TreeNode *parent, TreeNode **p)
    {
        if (r == NULL)
        {
            *p = parent; //p等于查找到的最后一个结点,函数返回false
            return false;
        }
        else if (r->data == key)
        {
            *p = r;
            return true;
        }
        else if (r->data > key)
        {
            return Search(r->left, key, r, p);
        }
        else if (r->data < key)
        {
            return Search(r->right, key, r, p);
        }
        return false;
    }
    bool Insert(TreeNode *r, int key)
    {
        TreeNode *p;

        if (!Search(r, key, NULL, &p))
        {
            TreeNode *temp = new TreeNode(key);

            if (p == NULL)   //表示此时根节点为空
                root = temp; //注意这里需要直接对root进行修改,对r这个形参的修改是无效的,当然也可以用二级指针解决这个问题
            else if (key > p->data)
                p->right = temp;
            else if (key < p->data)
                p->left = temp;

            return true;
        }
        else //树中存在一样的结点,则插入失败
            return false;
    }
    void Delete(TreeNode **p)
    {
        TreeNode *temp = *p; //临时指针,用于指向需要删除的结点

        if ((*p)->left == NULL) //没有左结点,就直接把右边的全部移上来
        {
            *p = (*p)->right;
            delete temp;
        }
        else if ((*p)->right == NULL) //没有右结点,就直接把左边的全部移上来
        {
            *p = (*p)->left;
            delete temp;
        }
        else //既有左结点又有右结点,两种方法
        {
            //左删法,找到本结点左边最右结点,与本结点替换后,删去
            TreeNode *lchild = (*p)->left;
            while (lchild->right)
            {
                temp = lchild; //让temp指向最右结点的上一个结点
                lchild = lchild->right;
            }
            (*p)->data = lchild->data; //换值
            if (temp == *p)            //temp没有移动
                temp->left = lchild->left;
            else
                temp->right = lchild->left;

            delete lchild;

            //右删法,找到本结点左边最左结点,与本结点替换后,删去
        }
    }
    bool DeleteNode(TreeNode **r, int key) //必须把树根传进来,不然删不掉结点
    {
        if (!*r)
            return false;

        if (key == (*r)->data)
        {
            Delete(r);
            return true;
        }
        else if (key < (*r)->data)
            return DeleteNode(&(*r)->left, key);
        else if (key > (*r)->data)
            return DeleteNode(&(*r)->right, key);

        return false;
    }
    void Inorder(TreeNode *r)
    {
        if (r == NULL)
            return;

        Inorder(r->left);
        cout << r->data << ' ';
        Inorder(r->right);
    }
};

int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        int *arr = new int[n];
        for (int i = 0; i < n; i++)
            cin >> arr[i];

        BinTree bt(arr, n);
        bt.Inorder(bt.root);
        cout << endl;

        int m;
        cin >> m;
        while (m--)
        {
            int x;
            cin >> x;
            bt.DeleteNode(&bt.root, x);
            bt.Inorder(bt.root);
            cout << endl;
        }

        delete[] arr;
    }

    return 0;
}

/*
样例输入
1
6
22 33 55 66 11 44
3
66
22
77

样例输出
11 22 33 44 55 66

11 22 33 44 55

11 33 44 55

11 33 44 55
*/

用引用代替二级指针

#include <iostream>
using namespace std;

class TreeNode
{
public:
    int data;
    TreeNode *left, *right;

    TreeNode() { left = right = NULL; }
    TreeNode(int key) : data(key) { left = right = NULL; }
};
class BinTree
{
public:
    TreeNode *root;

    BinTree(int arr[], int n) : root(NULL)
    {
        for (int i = 0; i < n; i++)
        {
            Insert(root, arr[i]);
        }
    }
    bool Search(TreeNode *&r, int key, TreeNode *parent, TreeNode *&p)
    {
        if (r == NULL)
        {
            p = parent;
            return false;
        }
        else if (r->data == key)
        {
            p = r;
            return true;
        }
        else if (key < r->data)
            return Search(r->left, key, r, p);
        else if (key > r->data)
            return Search(r->right, key, r, p);

        return false;
    }
    bool Insert(TreeNode *&r, int key)
    {
        TreeNode *p;
        if (!Search(r, key, NULL, p))
        {
            TreeNode *temp = new TreeNode(key);
            if (p == NULL)
                r = temp;
            else if (key < p->data)
                p->left = temp;
            else if (key > p->data)
                p->right = temp;

            return true;
        }
        else
            return false;
    }
    void Delete(int key) { Delete(root, key); }
    void Delete(TreeNode *&r, int key)
    {
        if (!r)
            return;
        else if (key < r->data)
            Delete(r->left, key);
        else if (key > r->data)
            Delete(r->right, key);
        else
        {
            TreeNode *temp = r;
            if (r->left == NULL)
            {
                r = r->right;
                delete temp;
            }
            else if (r->right == NULL)
            {
                r = r->left;
                delete temp;
            }
            else //找到左边最大的结点与需要删除的结点交换
            {
                TreeNode *lchild = r->left;
                while (lchild->right)
                {
                    temp = lchild;
                    lchild = lchild->right;
                }
                r->data = lchild->data;
                if (temp == r)
                    temp->left = lchild->left;
                else
                    temp->right = lchild->left;
                delete lchild;
            }
        }
    }
    void InOrder(TreeNode *r)
    {
        if (!r)
            return;

        InOrder(r->left);
        cout << r->data << ' ';
        InOrder(r->right);
    }
};

int main(int argc, char const *argv[])
{
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        int *arr = new int[n];
        for (int i = 0; i < n; i++)
            cin >> arr[i];

        BinTree bt(arr, n);
        bt.InOrder(bt.root);
        cout << endl;

        int m;
        cin >> m;
        while (m--)
        {
            int key;
            cin >> key;
            bt.Delete(key);
            bt.InOrder(bt.root);
            cout << endl;
        }

        delete[] arr;
    }
    return 0;
}

2.哈希查找

2.1线性探测

#include <iostream>
using namespace std;

#define NULLKEY -999

class HashTable
{
public:
    int *table;
    int length;

    HashTable(int l) : length(l)
    {
        table = new int[length];
        for (int i = 0; i < length; i++)
            table[i] = NULLKEY;

        int n; //关键字数
        cin >> n;
        while (n--)
        {
            int key;
            cin >> key;
            Insert(key);
        }
    }
    int Hash(int key) { return key % 11; }
    void Insert(int key)
    {
        int addr = Hash(key);
        while (table[addr] != NULLKEY)
        {
            addr = (addr + 1) % length;
        }
        table[addr] = key;
    }
    bool Search(int key, int &cnt, int &addr)
    {
        cnt = 0;
        addr = Hash(key);

        while (true)
        {
            cnt++;

            if (key == table[addr])
                return true;
            else if (table[addr] == NULLKEY)
                return false;

            addr = (addr + 1) % length;
        }
    }
    void Search(int key)
    {
        int cnt, addr;
        if (Search(key, cnt, addr))
            cout << 1 << ' ' << cnt << ' ' << addr + 1 << endl;
        else
            cout << 0 << ' ' << cnt << endl;
    }
    void Show()
    {
        for (int i = 0; i < length; i++)
        {
            if (table[i] == NULLKEY)
                cout << "NULL ";
            else
                cout << table[i] << ' ';
        }
    }
};

int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int m; //哈希表长
        cin >> m;
        HashTable ht(m);
        ht.Show();

        int k;
        cin >> k;
        while (k--)
        {
            int key;
            cin >> key;
            ht.Search(key);
        }
    }

    return 0;
}

2.2平方探测(二次探测)

#include <iostream>
using namespace std;

#define NULLKEY -99999

class HashTable
{
public:
    int *table;
    int length;

    HashTable(int m) : length(m)
    {
        table = new int[length];
        for (int i = 0; i < length; i++)
            table[i] = NULLKEY;

        int n;
        cin >> n;
        while (n--)
        {
            int key;
            cin >> key;
            Insert(key);
        }
    }
    int Hash(int key) { return key % 11; }
    void Insert(int key)
    {
        for (int i = 2, sym = 1, d = 0; d <= length / 2; i++)
        {
            int addr = Hash(key);
            addr = (addr + sym * d * d) % length;
            if (addr < 0)
                addr += length;

            if (table[addr] == NULLKEY)
            {
                table[addr] = key;
                return;
            }

            if (i % 2 == 0)
            {
                sym = 1;
                d++;
            }
            else
                sym = -1;
        }
    }
    bool Search(int key, int &cnt, int &addr)
    {
        cnt = 0;
        for (int i = 2, sym = 1, d = 0; d <= length / 2; i++)
        {
            cnt++;
            addr = Hash(key);
            addr = (addr + sym * d * d) % length;
            if (addr < 0)
                addr += length;

            if (key == table[addr])
                return true;
            if (table[addr] == NULLKEY)
                return false;

            if (i % 2 == 0)
            {
                sym = 1;
                d++;
            }
            else
                sym = -1;
        }
        return false;
    }
    void Search(int key)
    {
        int cnt, addr;
        if (Search(key, cnt, addr))
            cout << 1 << ' ' << cnt << ' ' << addr + 1;
        else
            cout << 0 << ' ' << cnt;
        cout << endl;
    }
    void Show()
    {
        for (int i = 0; i < length; i++)
        {
            if (table[i] == NULLKEY)
                cout << "NULL";
            else
                cout << table[i];

            if (i < length - 1)
                cout << ' ';
        }
        cout << endl;
    }
};

int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int m;
        cin >> m;
        HashTable ht(m);
        ht.Show();

        int k;
        cin >> k;
        while (k--)
        {
            int key;
            cin >> key;
            ht.Search(key);
        }
    }

    return 0;
}

/*
样例输入:
1
12 10
22 19 21 8 9 30 33 4 41 13
4
22
15
30
41

样例输出:
22 9 13 NULL 4 41 NULL 30 19 8 21 33
1 1 1
0 3
1 3 8
1 6 6
*/

2.3链地址法

#include <iostream>
using namespace std;

#define NULLKEY -99999
#define TABLELEN 11

class Node
{
public:
    int data;
    Node *next;

    Node() : data(NULLKEY) { next = NULL; }
    Node(int key) : data(key) { next = NULL; }
};
class HashTable
{
public:
    Node *table;
    int length;

    HashTable() : length(TABLELEN)
    {
        table = new Node[length];
        for (int i = 0; i < length; i++)
            table[i].data = 0; //头结点存放结点个数

        int n;
        cin >> n;
        while (n--)
        {
            int key;
            cin >> key;
            Insert(key);
        }
    }
    int Hash(int key) { return key % 11; }
    void Insert(int key) //头插法
    {
        Node *temp = new Node(key);
        int addr = Hash(key);
        Node *p = &table[addr];

        temp->next = p->next;
        p->next = temp;
        table[addr].data++;
    }
    // void Insert(int key) //尾插法
    // {
    //     Node *temp = new Node(key);
    //     int addr = Hash(key);
    //     Node *p = &table[addr];
    //     while (p->next)
    //     {
    //         p = p->next;
    //     }
    //     p->next = temp;
    //     table[addr].data++;
    // }
    bool Search(int key, int &cnt, int &addr)
    {
        cnt = 0;
        addr = Hash(key);
        Node *p = &table[addr];
        if (p->data == 0)
            return false;
        else
        {
            while (p->next)
            {
                cnt++;
                if (key == p->next->data)
                    return true;
                p = p->next;
            }
            return false;
        }
    }
    void Search(int key)
    {
        int cnt, addr;
        if (Search(key, cnt, addr))
            cout << addr << ' ' << cnt;
        else
        {
            cout << "error";
            Insert(key);
        }
        cout << endl;
    }
    void Show()
    {
        for (int i = 0; i < length; i++)
        {
            cout << i << '-';
            Node *p = &table[i];
            do
            {
                cout << p->data << ' ';
                p = p->next;
            } while (p);
            cout << endl;
        }
    }
};

int main()
{
    HashTable ht;

    int t;
    cin >> t;
    while (t--)
    {
        int key;
        cin >> key;
        ht.Search(key);
    }

    return 0;
}

/*
样例输入:
6
11 23 39 48 75 62
6
39
52
52
63
63
52

使用头插法样例输出:
6 1
error
8 1
error
8 1
8 2

使用尾插法样例输出:
6 1
error
8 1
error
8 2
8 1
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值