【问题标题】:C++ Hashing search function stuck in endless "else" and "while" loopC++ 散列搜索函数陷入无休止的“else”和“while”循环
【发布时间】:2019-10-06 18:14:37
【问题描述】:

如果生成的要查找的随机数在哈希表数组中不存在,则程序会陷入函数void hashSearch()中的无限循环, 而它应该只是退出循环并输出未找到搜索项。代码中的确切位置是这些输出的位置: cout << "stuck in else loop \n";cout << "stuck in while loop end \n";

我用谷歌搜索过,但找不到类似的例子。

#include <iostream>
#include <stdlib.h>     /* srand, rand */
#include <time.h>       /* time */
#include <chrono>
using namespace std;
int arr [1000];
int arr2 [1000];
int randArrayInt, n, randSearchItem, searchInt, address, size2;
void printZeroArr();
void linearSentinelSearch();
void printHashArray();
void hashSearch();
int main ()
{
    srand (time(nullptr));  //initialize random seed:
    n = rand() % 900 + 100; //random integer number from 100 - 1000, length of the array
    //n = rand() % 10; // random number in the range 1-10 for sanity tests, length of the array
    //randSearchItem = rand() % 10 + 1;
    randSearchItem = rand() % 900 + 100; //this is the number to search for
    cout << "Array length is " << n << endl;
    cout << "[";
    for (int i = 0; i <= n; i++)
    {
        randArrayInt = rand() % 900 + 100;
        //randArrayInt = rand() % 10 + 1; // generate random 1-10 number for for sanity tests
        arr[i] = randArrayInt;   // insert into array position the generated random number
        cout<< " " << arr[i];  // print out array element at current loop position
    }
    cout << " ]\n" << endl;
    printZeroArr();
}

void printZeroArr()
{
    size2 = n + 1; //length of hashed array
    cout << "This is the random key to search for in array: " << randSearchItem << endl;
    cout << "This is the size2 length " << size2 << endl;
    cout << "This is the hasharray with zeros" << endl;
    cout << "[";
    for (int i = 0; i <= size2; i++)
    {
        arr2[i] = 0;   // insert into hasharray number 0
        cout<< " " << arr2[i];  // print out hasharray element at current loop position
    }
    cout << " ]\n" << endl;
    linearSentinelSearch();
}

void linearSentinelSearch()
{
    auto start = std::chrono::high_resolution_clock::now();
    arr[n + 1] = randSearchItem;
    //cout << "testing arr[n + 1] is " << arr[n + 1] << endl;
    int i = 0;
    while (arr[i] != randSearchItem) i++;
    if (i == n + 1)
        cout << "Sentinel search did not found the searchitem in random array" << "\n" << endl;
    else
        cout << "Searchitem found in array with linearsearch at position " << i << "\n" << endl;
    auto finish = std::chrono::high_resolution_clock::now();
    chrono::duration<double> elapsed = finish - start;
    cout << "Elapsed time: " << elapsed.count() << " s\n";
    printHashArray();
}

void printHashArray()
{
    //cout << "printing out 'address' value, or the modulo result: " << endl;
    //cout << "[";
    for (int i = 0; i <= n; i++)
    {
        address = arr[i] % size2;
        //cout << " " << address;
        while (arr2[address] != 0)
        {
            if (address == size2 - 1)
            {
                address = 0;
            } else
            {
                address++;
            }
        }
        arr2[address] = arr[i];
    }
    //cout << " ]\n" << endl;
    cout << "This is the hasharray with hashitems" << endl;
    cout << "[";
    for (int i = 0; i <= size2; i++)
    {
        cout << " " << arr2[i];
    }
    cout << " ]\n" << endl; hashSearch();
}

void hashSearch()
{
    auto start = std::chrono::high_resolution_clock::now();
    int searchInt = randSearchItem % size2;
    while ((arr2[searchInt] != 0)  && (arr2[searchInt] != randSearchItem))
    {
        if (searchInt == size2 - 1)
        {
            searchInt = 0;
            cout << "if loop \n";
        }
        else
        {
            searchInt++;
            cout << " stuck in else loop \n";
        }
        cout << " stuck in while loop end \n";
    }
    if (searchInt == 0) {
        cout << "Search item not found using hashSearch" << endl;
    } else {
        cout << "Search item " << randSearchItem << " found using hashSearch at position " << searchInt << " in arr2." << endl;
    }
    auto finish = std::chrono::high_resolution_clock::now();
    chrono::duration<double> elapsed = finish - start;
    cout << "Elapsed time: " << elapsed.count() << " s\n";
}

而它应该只是退出循环并输出未找到搜索项。 搜索cout &lt;&lt; " stuck in else loop \n";cout &lt;&lt; " stuck in while loop end \n";

【问题讨论】:

  • 不确定您要编写的算法。如果您使用局部变量而不是所有全局变量,并且可能使用更具描述性的变量名称,那么阅读起来会更容易。
  • C 使用从零开始的索引,因此arr[n] 已经超出了具有“n”个元素的数组的上限。 arr[n + 1],你放哨兵的地方,是超出上限的两个项目。你的初始化循环应该是i = 0; i &lt; n, i++): lett 而不是小于或等于。 (这不是你的问题的原因,因为你的数组有多余的未使用的元素,但值得注意。)

标签: c++ algorithm hashtable


【解决方案1】:

您想在到达数组末尾时停止循环:为此,您将要搜索的项目设置为零:

    if (searchInt == size2 - 1)
    {
        searchInt = 0;
        cout << "if loop \n";
    }

但在循环控制中,您不会对此进行测试。您只测试当前索引处的数组元素是否为零(未找到)或要搜索的项目(找到):

while ((arr2[searchInt] != 0)  && (arr2[searchInt] != randSearchItem)) ...

您需要额外的测试:

while ((searchInt != 0)  && ...) ...

我花了一段时间才看到您想要编写一个开放地址 hastable,其中零标记未使用的插槽。哈希值只是数字本身。使用零作为空槽的指示符并不理想:您不能存储哈希码以表大小为模后为零的数字。

我还会使用非 void 函数对此进行编码,其中返回值是索引或一些明确的值,意思是“未找到”,可能是 -1。 (或者,如果未找到该项目,您可以返回指向找到的项目的指针或NULL - 毕竟,哈希数组中的索引是哈希表内部的一部分,与调用者无关。)

那么你可以使用提前退货:

int hashSearch(const int *arr2, int size2, int item)
{
    int i = item % size2;

    for (; i < size2; i++) {
        if (arr2[i] == -1) break;            // -1 indicated unused space
        if (arr2[i] == item) return i;       // return index of item
    }

    return -1;     // not found!
}

但是当你的哈希码接近数组大小时,如果没有空间容纳更多元素,你会怎么做?您将需要在最后添加额外的空间,否则您需要环绕。也许这就是您想要通过将索引设置回零来实现的目标。在您的情况下,数组已满,因此没有可以用作循环中断标准的零。您将不得不找到另一个标准。您可以通过使哈希表比条目数大 30% 左右来确保有零。或者您可以尝试检测索引是否已与原始索引转了一圈。

正如在 cmets 中已经向您指出的那样:尝试使用函数参数和局部变量,而不是将所有内容都放入全局空间。此外,函数调用的链接,函数中的最后一件事是调用下一个函数,这很奇怪。将所有顺序调用放到 main 中可能会更好。

【讨论】:

  • M Oehm,经过快速测试,我发现您的建议有效并且循环退出,非常感谢!关于代码上的其他 cmets - 是的,我需要做得更好:)
猜你喜欢
  • 1970-01-01
  • 2012-03-12
  • 2020-11-19
  • 1970-01-01
  • 2017-06-19
  • 2018-05-20
  • 2021-12-30
  • 1970-01-01
相关资源
最近更新 更多