C ++ - Как посчитать, сколько сравнений потребовалось программе, чтобы найти значение в двоичном дереве - PullRequest
1 голос
/ 11 апреля 2020

Ниже приведен код, который я использую для 1) извлечения чисел из текстового файла и сохранения их в массив; 2) использовать массив как «вход» и импортировать числа из массива в двоичное дерево; 3) выполнить поиск в двоичном дереве, чтобы найти введенные пользователем значения, если найдено, вывести «Значение найдено», если не найдено, вывести «Значение не найдено».

Код работает отлично. Но я борюсь за последнюю часть. Я должен сделать вывод программы, сколько сравнений потребовалось, чтобы найти (или не найти) каждое значение в двоичном дереве.

#include<iostream>
#include  <fstream>
#include <string>

using namespace std;

//define the struct of a binary tree

typedef struct node
{
    int value;
    node * pLeft;
    node * pRight;
    node(int val = 0)
    {
        value = val;
        pRight = NULL;
        pLeft = NULL;
    }
}node;


//decide insertion location for each value imported from the array
void insert(node*& pRoot, int val)
{
    if (pRoot == NULL)
    {
        //insertion place found
        pRoot = new node;
        pRoot->pRight = NULL;
        pRoot->pLeft = NULL;
        pRoot->value = val;
    }
    else if (val < pRoot->value)
        insert(pRoot->pLeft, val);
    else
        insert(pRoot->pRight, val);
}

//pass in value from arrary to the binary tree
node * getBST(int * arr, int size)
{
    node * pRoot = NULL;
    for (int i = 0; i < size; i++)
        insert(pRoot, arr[i]);
    return pRoot;
}

//look through the binary tree to find the user-input value 
void Retrieve(node* pRoot, int value)
{
        if (pRoot == NULL)
        {
            bool found = false;
            cout << "Value not found" << endl;
        }
        else if (value < pRoot->value)
        {
            Retrieve(pRoot->pLeft, value);
        }
        else if (value > pRoot->value)
        {
            Retrieve(pRoot->pRight, value);
        }
        else
        {
            value = pRoot->value;
            bool found = true;
            cout << "Value found" << endl;
        }

}

int main()
{
    ifstream file("5 Random Numbers.txt");
    if (file.is_open())                    //open the file
    {
        int arr[5];

        for (int i = 0; i < 5; ++i)     //put numbers in the file into the array
        {
            file >> arr[i];
        }

        node * pRoot = getBST(arr, 5);   //convert array to binary tree; 5 is the size   

        for (int i = 0;i < 3; ++i)     //ask user to enter 3 numbers, then search these numbers in the binary tree
        {
            int userValue;
            cout << "Enter an integer to search: ";
            cin >> userValue;
            Retrieve(pRoot, userValue);
        }


        cout << endl;

        return 0;
    }
}

В данный момент функция Retrieve может показывать только найденное значение или нет. Но мне также нужно, чтобы распечатать, сколько сравнений потребовалось, чтобы найти значение.

Например, если текстовый файл содержит пять чисел «123 15 392 88 731», и я ввожу число «88» для поиска, программа 3 сравнивает, чтобы найти число в двоичном дереве , Я хочу, чтобы программа распечатала что-то вроде «потребовалось 3 сравнения».

Если я введу число «999». «999» не существует в двоичном дереве, но программа 3 сравнения все же потребовалась, чтобы прийти к такому выводу, поэтому программа должна распечатать «Требуется 3 сравнения». Я пытался добавить for-l oop в функцию Retrieve, но почему-то это не сработало ... Любые подсказки приветствуются!

Ответы [ 3 ]

1 голос
/ 11 апреля 2020

Для начала функцию insert можно упростить с учетом определения конструктора узла struct.

void insert(node*& pRoot, int val)
{
    if (pRoot == NULL)
    {
        //insertion place found
        pRoot = new node( val );
    }
    else if ( value < pRoot->value)
        insert(pRoot->pLeft, val);
    else
        insert(pRoot->pRight, val);
}

Функция Retrieve не должна ничего выводить. Он должен возвращать логическое значение true или false. Вызывающая функция решает, какое сообщение вывести на основе возвращаемого значения функции. Функция может быть реализована следующим образом:

//look through the binary tree to find the user-input value 
bool Retrieve( const node* pRoot, int value, size_t &n )
{
        if ( pRoot == NULL)
        {
            return false;
        }
        else if ( ++n, value < pRoot->value )
        {
            return Retrieve( pRoot->pLeft, value, n );
        }
        else if ( ++n, value > pRoot->value )
        {
            return Retrieve(pRoot->pRight, value, n );
        }
        else
        {
            return true;
        }
}

Перед вызовом функции аргумент, соответствующий третьему параметру, должен быть установлен в ноль, если вы хотите подсчитать количество сравнений в одном вызове функции. ..

Вот демонстрационная программа.

#include <iostream>

struct node
{
    int value;
    node * pLeft;
    node * pRight;
};

void insert( node* &pRoot, int value )
{
    if ( pRoot == nullptr )
    {
        pRoot = new node { value, nullptr, nullptr };
    }
    else if ( value < pRoot->value )
    {
        insert( pRoot->pLeft, value );
    }
    else
    {
        insert( pRoot->pRight, value );
    }
}

bool Retrieve( const node* pRoot, int value, size_t &n )
{
    if ( pRoot == NULL)
    {
        return false;
    }
    else if ( ++n, value < pRoot->value )
    {
        return Retrieve( pRoot->pLeft, value, n );
    }
    else if ( ++n, value > pRoot->value )
    {
        return Retrieve(pRoot->pRight, value, n );
    }
     else
    {
        return true;
    }
}

int main() 
{
    node *pRoot = nullptr;
    int a[] = { 123, 15, 392, 88, 731 };

    for ( const auto item : a ) insert( pRoot, item );

    size_t n = 0;
    int value = 88;

    if ( Retrieve( pRoot, value, n ) )
    {
        std::cout << value << " is found after " << n << " comparisons\n";
    }
    else
    {
        std::cout << value << " is not found after " << n << " comparisons\n";
    }


    return 0;
}

Ее вывод

88 is found after 5 comparisons

Обратите внимание, что есть 5 сравнений, а не 3 как вы написали в вопросе.

Действительно. Первое сравнение со значением узла root, равным 123. Затем второе сравнение со значением левого узла со значением 15. В этом случае есть два сравнения, соответствующих количеству выполненных операторов if

    else if ( ++n, value < pRoot->value )
    {
        return Retrieve( pRoot->pLeft, value, n );
    }
    else if ( ++n, value > pRoot->value )
    {
        return Retrieve(pRoot->pRight, value, n );
    }

И затем, чтобы определить, что текущий узел содержит точно значение 88, снова выполняются два сравнения со значением текущего узла

    else if ( ++n, value < pRoot->value )
    {
        return Retrieve( pRoot->pLeft, value, n );
    }
    else if ( ++n, value > pRoot->value )
    {
        return Retrieve(pRoot->pRight, value, n );
    }
     else
    {
        return true;
    }

Таким образом, правильный ответ - 5 сравнения. Что касается числа 3, то это не количество сравнений. Это количество рекурсивных вызовов.

Если вы хотите посчитать количество рекурсивных вызовов функции вместо количества сравнений, то измените функцию следующим образом

bool Retrieve( const node* pRoot, int value, size_t &n )
{
    ++n;

    if ( pRoot == NULL)
    {
        return false;
    }
    else if ( value < pRoot->value )
    {
        return Retrieve( pRoot->pLeft, value, n );
    }
    else if ( value > pRoot->value )
    {
        return Retrieve(pRoot->pRight, value, n );
    }
     else
    {
        return true;
    }
}

In в этом случае действительно число рекурсивных вызовов функции (не количество сравнений) будет равно 3.

. Используя этот подход, вы можете, например, подсчитать общее количество сравнений для нескольких вызовов функция.

1 голос
/ 11 апреля 2020

Добавьте параметр depth к вашей функции и увеличивайте его для каждого уровня дерева.

void Retrieve(node* pRoot, int value, int depth)
{
        if (pRoot == NULL)
        {
            bool found = false;
            cout << "Value not found" << endl;
        }
        else if (value < pRoot->value)
        {
            Retrieve(pRoot->pLeft, value, ++depth);
        }
        else if (value > pRoot->value)
        {
            Retrieve(pRoot->pRight, value, ++depth);
        }
        else
        {
            value = pRoot->value;
            bool found = true;
            cout << "Value found" << depth << endl;
        }

}
0 голосов
/ 11 апреля 2020

Если вы хотите напечатать глубину дерева, на котором найден ответ, внутри функции Retrieve, то ответ @ maxpaj показывает, как это сделать; добавить дополнительный параметр в функцию Retrieve. (Вы также можете распечатать ответ на сайте вызова, используя этот подход).

Однако, если вы хорошо печатаете ответ на сайте вызова, вы можете использовать возвращаемое значение Retrieve , который в настоящее время не используется.

int Retrieve(node* pRoot, int value)
{
  if (pRoot == NULL)
  {
    cout << "Value not found" << endl;
    return 0;
  }

  if (value < pRoot->value)
    return Retrieve(pRoot->pLeft, value) + 1;

  if (value > pRoot->value)
    return Retrieve(pRoot->pRight, value) + 1;

  cout << "Value found" << depth << endl;
  return 0;
}

Тогда на сайте звонка можно сделать

int depth = Retrieve(pRoot, userValue);
cout << "Took " << depth << " steps\n";
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...