如何制作一个"排序数组以平衡BST"递归算法到迭代算法?

时间:2018-05-01 18:48:04

标签: c++ loops recursion stack

我已经四处搜索但无法真正理解或寻求帮助,因为这种迭代算法需要两个堆栈(包含left_Index和right_Index)。

主要的递归方式是将它放在一边直到left_Index> = right_Index,然后递归地为双方和每个子部分(如果这是有意义的)这样做,我不明白如何准确地这样做因为我要维护两个堆栈,需要看看它们之间的确切关系。

这个问题主要是由于我不理解正常的递归方法词的方式,虽然在并排查看它们时如何处理它,我总是不知所措。

关于为什么我这样做的背景故事: 试图解决从A到B的单词梯形问题,并决定建立一个BST,其中连接通过奇异的字符差异和长度连接。我从包含大量字典的文本文件中获取单词,并且由于我使用BST作为包含所有顶点的主列表,因此这是一个字典意味着每个插入都将按顺序排列因此树是右倾的(所以插入O(n ^ 2)的速度很慢,这是一个阻碍)。我计划将数据存储在一个数组中,然后从中产生一个平衡的BST,因为我认为速度应该更快,因为插入将是O(n * logn),这看起来很棒。问题在于我不能使用递归方法,因为有很多数据导致堆栈溢出,所以我需要使用堆栈和循环迭代地进行迭代,但我发现它太难了。 / p>

我一开始的糟糕尝试:

  

while(lindx.the_front()< rindx.the_back())
    {
     mid =(lindx.the_front()+ rindx.the_back())/ 2;
     dictionary.addVertex(矢量[MID]);
     std :: cout<< "推动" << vector [mid]<< ' \ n&#39 ;;      rindx.push(mid - 1);
     }

这基本上是从我制作的链接堆栈中得到程序左半部分的1/2。 " the_front()"是第一个插入," the_back()"是列表中的最终/最新插入。我遇到的主要问题是理解如何让它重复一半以获得所有值。

我需要找到我过去的作业,我已经完成了这项工作,但代码是...... ...

void array2balanced(int array[], int lIndex, int rIndex) 
{  
  //base case
  if(lIndex > rIndex) 
  {
    return; 
  } 
  //recursive cals
  else 
  {  
    mid = (lIndex+rIndex)/2;  
    tree.insert(array[mid]);  
    array2balanced(array, lIndex, mid-1);  
    array2balanced(array, mid+1, rIndex); 
  } 
}

更新 到目前为止进展

void balancedTree(std::vector<std::string> vector, dictionaryGraph &dictionary) // divide and conquer into tree?
{
    linkedStack<int> lindx, rindx, midX;
    unsigned int l_Index{ 0 }, r_Index{ vector.size() - 1 }, mid{ (l_Index + r_Index) / 2 };;
    lindx.push(l_Index);
    rindx.push(r_Index);
    midX.push(mid);
    int testCount{ 0 };
    std::cout << "There are " << vector.size() << " words.\n";

    while (!midX.empty())
    {
        mid = midX.pop();
        l_Index = lindx.pop();
        r_Index = rindx.pop();
        std::cout << "inputted " << vector[mid] << '\n';
        dictionary.addVertex(vector[mid]);
        testCount++;

        if (r_Index > l_Index)
        {

            midX.push((l_Index + mid) / 2);
            lindx.push(l_Index);
            rindx.push(mid - 1);
        }
        if (l_Index < r_Index)
        {
            midX.push((mid + r_Index) / 2);
            lindx.push(mid + 1);
            rindx.push(r_Index);
        }
    }
    std::cout << testCount << " words were inputted...\n"; // To see how many were inserted
    system("pause");
}

我遇到的问题是一些输入被重复,有些输入错过了。

2 个答案:

答案 0 :(得分:0)

  

这个问题主要是由于我不理解正常的方式   递归方法的话,虽然并排看着它们   看看如何接近它,我总是不知所措。

这需要练习......并且可能会审查其他人的工作。

  

需要两个堆栈(包含left_Index和right_Index)。

道歉,我不明白为什么OP会这么想。我下面的演示只有一个名为'todo'的堆栈,也许你会发现这个想法很有用。

#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
#include <cassert>

#include "./BTree.hh"  // code not provided, used in this MCVE to 
                       // conveniently provide "showTallTreeView()" 

typedef std::vector<int>  IVec_t;  

class T607_t
{
   IVec_t m_sortedIVec;    // sorted - created with for loop
   IVec_t m_recursiveIVec; // extract from sorted by recursion
   IVec_t m_iterativeIVec; // extract from sorted by iteration

public:

   T607_t() = default;
   ~T607_t() = default;

   int exec(int , char**  )
      {
         fillShowSortedIVec();

         fillShowRecursiveIVec();

         fillShowIterativeIVec();

         showResults();

         return 0;
      }

private: // methods

向量在T607_t类中,因此每个向量都可用于任何成员函数。

对于这个MCVE,我只创建“IVec_t m_sortedIVec;”并填写一个简单的for循环:

   void fillShowSortedIVec()
      {
         for (int i=0; i<15; ++i)
            m_sortedIVec.push_back (i*100);  // create in sorted order

         showIVec(m_sortedIVec, "\n  m_sortedIVec   :");   
      }

接下来(在这个MCVE中)是递归填充和显示,以及我对OP的递归方法的改编以产生递归插入序列:

   // ///////////////////////////////////////////////////////////////
   void fillShowRecursiveIVec()
      {
         assert(m_sortedIVec.size() > 0);
         int max = static_cast<int>(m_sortedIVec.size()) - 1;

         // use OP's recursive insert
         array2balancedR (m_sortedIVec, 0, max);  
         // NOTE - 'sequence' is inserted to 'm_recursiveIVec'
         //        instead of into tree the op did not share

         showIVec(m_recursiveIVec, "\n  m_recursiveIVec:");
      }

   // recursive extract from: m_sortedIVec  to: m_recursiveIVec
   // my adaptation of OP's recursive method
   void array2balancedR(IVec_t& array, int lIndex, int rIndex)
      {
         //base case
         if(lIndex > rIndex)
         {
            return;
         }
         else    //recursive calls
         {
            int mid = (lIndex+rIndex)/2;
            m_recursiveIVec.push_back(array[mid]);  // does this
            // tree.insert(array[mid]);             // instead of this

            array2balancedR(array, lIndex, mid-1);  // recurse left
            array2balancedR(array, mid+1, rIndex);  // recurse right
         }
      }

注意:我将“IVec_t&amp; array”作为参数留给了这个函数,因为OP的代码有它。在这个'class'包装器中,函数不需要通过递归传递数组,因为每个方法都可以访问实例数据。

下一步(在此MCVE中)是使用一种可能的迭代方法的填充和显示操作。我仔细地设计了这种迭代方法,以匹配OP的递归工作。

首先,我添加了一个'工具'(IndxRng_t)来简化迭代的'堆栈'捕获,以便以后处理。 (即“todo”)。

   // //////////////////////////////////////////////////////////////
   // iterative extract from  m_sortedIVec  to: m_iterativeIVec
   class IndxRng_t  // tool to simplify iteration
   {
   public:
      IndxRng_t() = delete; // no default
      IndxRng_t(int li, int ri)
         : lIndx (li)
         , rIndx (ri)
         {}
      ~IndxRng_t() = default;

      // get'er and set'er free.  also glutton free.  gmo free.
      bool            done() { return (lIndx > rIndx); } // range used up
      int              mid() { return ((lIndx + rIndx) / 2); } // compute
      IndxRng_t   left(int m) { return {lIndx, m-1}; }  // ctor
      IndxRng_t  right(int m) { return {m+1, rIndx}; }  // ctor
   private:
      int lIndx;
      int rIndx;
   };


   void fillShowIterativeIVec()
      {
         assert(m_sortedIVec.size() > 0);
         int max = static_cast<int>(m_sortedIVec.size()) - 1;

         array2balancedI(m_sortedIVec, 0, max); 
         // 'sequence' inserted to 'm_iterativeIVec'

         showIVec(m_iterativeIVec, "\n  m_iterativeIVec:");
      }


   void array2balancedI(IVec_t& array, int lIndex, int rIndex)
      {
         std::vector<IndxRng_t>  todo;
         todo.push_back({lIndex, rIndex}); // load the first range

         // iterative loop (No recursion)
         do
         {
            if (0 == todo.size()) break; // exit constraint
            // no more ranges to extract mid from

            // fetch something to do
            IndxRng_t  todoRng = todo.back();
            todo.pop_back(); // and remove from the todo list

            if(todoRng.done()) continue; // lIndex > rIndex 

            int mid = todoRng.mid();
            m_iterativeIVec.push_back(array[mid]);  // do this
            // tree.insert(array[mid]);             // instead of this

            todo.push_back(todoRng.right(mid) ); // iterate on right
            todo.push_back(todoRng.left(mid)  ); // iterate on left

         }while(1);
      }

这个mcve会生成一个结果显示:

   void showResults()
      {
         assert(m_recursiveIVec.size() == m_sortedIVec.size());
         assert(m_iterativeIVec.size() == m_sortedIVec.size());

         std::cout << std::endl;

         std::stringstream ss; // for btree use only

         std::cout << "\n  demo:\n     create a BTree, "
                   << std::flush;
         std::cout << "\n     Insert IVec_t " << std::endl;

         BBT::BTree_t btree(ss);
         std::cout << std::flush;

         for (size_t i=0; i<m_iterativeIVec.size(); ++i)
            btree.insertPL(m_iterativeIVec[i]);

         std::cout << "\n iterative result:\n\n" 
                   << btree.showTallTreeView();
      }


   void showIVec(IVec_t& ivec, std::string lbl)
   {
      std::cout << lbl << std::endl;
      for (auto it : ivec)
         std::cout << std::setw(5) << it << std::flush;
      std::cout << std::endl;
   }

}; // class T607_t


int main(int argc, char* argv[])
{
   T607_t  t607;
   return  t607.exec(argc, argv);
}

我的输出(在Ubuntu 17.10,g ++ 7.2.0上),

  m_sortedIVec   :
    0  100  200  300  400  500  600  700  800  900 1000 1100 1200 1300 1400

  m_recursiveIVec:
  700  300  100    0  200  500  400  600 1100  900  800 1000 1300 1200 1400

  m_iterativeIVec:
  700  300  100    0  200  500  400  600 1100  900  800 1000 1300 1200 1400


  demo:
     create a BTree, 
     Insert IVec_t 

 iterative result:

  BTree_t::showTallTreeView():  (balance: 0  sz: 15)

                     0 
               100 
                    200 
          300 
                    400 
               500 
                    600 
     700 
                    800 
               900 
                    1000 
          1100 
                    1200 
               1300 
                    1400 

-----------------

答案 1 :(得分:0)

将排序后的数组转换为二进制搜索树(BST)的迭代JavaScript实现:

function sortedArrayToBstIteratively(nums) {
    // use stack to iteratively split nums into node tuples and reuse values
    const stack = []

    // add root node to tree
    const tree = { first: 0, last: nums.length - 1 }
    stack.push(tree)

    // split array in the middle and continue with the two halfs
    while (stack.length > 0) {
        const node = stack.pop()

        if (node.last >= node.first) {
            if (node.last === node.first) {
                // node reaches a single leaf value (last == first)
                node.value = nums[node.first]
            } else {
                // node has still valid indices to further split the array (last > first)
                const middle = Math.ceil((node.first + node.last) / 2)
                node.value = nums[middle]
                node.left = { first: node.first, last: middle - 1 }
                node.right = { first: middle + 1, last: node.last }
                stack.push(node.left)
                stack.push(node.right)
            }
        } else {
            // node has no more valid indices (last < first), create empty leaf
            node.value = null
        }

        delete node.first
        delete node.last
    }

    // console.log(JSON.stringify(tree))

    return tree
}