代码之家  ›  专栏  ›  技术社区  ›  Imbue

一组数字中求最大差的算法

  •  18
  • Imbue  · 技术社区  · 17 年前

    我有一个由几百万个数字组成的数组。

    double* const data = new double (3600000);
    

    我需要遍历数组并找到范围(数组中的最大值减去最小值)。然而,有一个陷阱。我只想找到最小值和最大值在1000个样本之间的范围。

    所以我需要找到最大值:范围(数据+0,数据+1000),范围(数据+1,数据+1001),范围(数据+2,数据+1002),…,范围(数据+3599000,数据+3600000)。

    我希望这是有道理的。基本上我可以像上面那样做,但是我正在寻找一个更有效的算法,如果存在的话。我认为上面的算法是O(N),但我觉得有可能进行优化。我正在玩的一个想法是跟踪最近的最大值和最小值,以及它们向后的距离,然后在必要时才进行回溯。

    我将用C++来编码,但是在伪代码中的一个很好的算法将会很好。另外,如果我要找的这个号码有名字,我想知道它是什么。

    谢谢。

    7 回复  |  直到 14 年前
        1
  •  8
  •   Drakosha    17 年前

    你描述的算法确实是O(N),但我认为这个常数太高了。另一个看起来合理的解决方案是使用o(n*log(n))算法,方法如下:

    * create sorted container (std::multiset) of first 1000 numbers
    * in loop (j=1, j<(3600000-1000); ++j)
       - calculate range
       - remove from the set number which is now irrelevant (i.e. in index *j - 1* of the array)
       - add to set new relevant number  (i.e. in index *j+1000-1* of the array)
    

    我认为应该更快,因为常数要低得多。

        2
  •  10
  •   shoosh    17 年前

    这类问题属于流算法的一个分支。这是一个研究问题,不仅需要一个O(N)解决方案,而且还需要在一次数据传递中工作。数据以流的形式输入到算法中,算法无法保存所有的数据,因此将永远丢失。算法需要得到一些关于数据的答案,例如最小值或中值。

    具体来说,您需要在流上方的窗口中查找最大值(或者更常见的是在文献中是最小值)。

    Here's a presentation 关于一个 article 这就把这个问题作为他们试图解决的问题的一个子问题。它可能会给你一些想法。

    我认为解决方案的轮廓是这样的——在流上维护一个窗口,在每个步骤中,一个元素插入窗口,另一个元素从另一侧移除(滑动窗口)。您实际保存在内存中的项目并不都是窗口中的1000个项目,而是选定的代表,这些代表将是最起码(或最多)的最佳人选。

    阅读文章。它有点复杂,但2-3次阅读后,你就可以掌握它的窍门了。

        3
  •  6
  •   Tyler    17 年前

    这是一个很好的应用程序 最小队列 -一个队列(先进先出=先进先出),它可以同时跟踪它所包含的最小元素,并使用分摊的固定时间更新。当然,最大队列基本上是相同的。

    一旦您有了这个数据结构,就可以考虑将currentmax(过去1000个元素中的)减去currentmin,将其存储为bestsofar,然后推一个新值并弹出旧值,然后再次检查。这样,就可以一直更新bestsofar,直到最终的值是问题的解决方案。每一步都需要摊余常量时间,所以整个过程是线性的,我所知道的实现有一个很好的标量常量(很快)。

    我不知道关于MinQueue的任何文档-这是我与同事合作开发的一个数据结构。您可以通过在内部跟踪数据的每个连续子序列中最少元素的二叉树来实现它。它简化了只从结构一端弹出数据的问题。

    如果你对更多细节感兴趣,我可以试着提供。我正考虑把这个数据结构写成一篇ARXIV的论文。还需要注意的是,Tarjan和其他人之前已经建立了一个更强大的Min-Deque结构,可以在这里工作,但是实现要复杂得多。你可以 google for "mindeque" 阅读Tarjan等人的作品。

        4
  •  0
  •   Mark Ransom    17 年前
    std::multiset<double> range;
    double currentmax = 0.0;
    for (int i = 0;  i < 3600000;  ++i)
    {
        if (i >= 1000)
            range.erase(range.find(data[i-1000]));
        range.insert(data[i]);
        if (i >= 999)
            currentmax = max(currentmax, *range.rbegin());
    }
    

    注释 未经测试的代码。

    编辑: 一个错误就解决了。

        5
  •  0
  •   freespace    17 年前
    1. 读前1000个数字。
    2. 创建跟踪当前1000个数字的1000个元素链接列表。
    3. 创建指向链接列表节点的1000元素指针数组,1-1映射。
    4. 根据链接列表节点的值对指针数组进行排序。这将重新排列数组,但保持链接列表的完整性。
    5. 现在可以通过检查指针数组的第一个和最后一个元素来计算前1000个数字的范围。
    6. 删除第一个插入的元素,根据链接列表的创建方式,该元素可以是头元素,也可以是尾元素。使用节点的值对指针数组执行二进制搜索以查找要删除的节点的指针,并将数组移动一次以将其删除。
    7. 将第1001个元素添加到链接列表中,通过执行插入排序的一个步骤,在数组中的正确位置插入指向该元素的指针。这将保持数组的排序。
    8. 现在您有了介于1和1001之间的数字的最小值和最大值,并且可以使用指针数组的第一个和最后一个元素计算范围。
    9. 现在应该很明显您需要为数组的其余部分做什么。

    该算法应该是O(N),因为删除和插入由日志(1E3)限定,而其他一切都需要恒定的时间。

        6
  •  0
  •   Tim Cooper    14 年前

    我决定看看我能想到的解决这个问题的最有效的算法是使用实际的代码和实际的时间安排。我首先创建了一个简单的解决方案,它使用圆形缓冲区跟踪前n个条目的最小/最大值,并使用测试工具测量速度。在简单的解决方案中,将每个数据值与最小/最大值集进行比较,这样就可以进行窗口大小*计数测试(原始问题中的窗口大小为1000,计数为3600000)。

    然后我考虑如何使它更快。首先,我创建了一个使用FIFO队列存储窗口大小值的解决方案,以及一个按升序存储值的链接列表,其中链接列表中的每个节点也是队列中的一个节点。为了处理一个数据值,FIFO末尾的项目被从链接列表和队列中删除。新值被添加到队列的开头,并使用线性搜索来查找链接列表中的位置。然后可以从链接列表的开始和结束处读取最小值和最大值。这很快,但不能很好地随着窗口大小的增加而扩展(即线性)。

    所以我决定在系统中添加一个二叉树来加速算法的搜索部分。窗口大小=1000和计数=3600000的最终计时为:

    Simple: 106875
    Quite Complex: 1218
    Complex: 1219
    

    这是意料之中的。预期中使用排序链接列表有帮助,但意外的是拥有自平衡树的开销没有抵消快速搜索的优势。我尝试了后两种方法,增加了窗口大小,结果发现,在100000个窗口大小之前,它们几乎是相同的。

    这一切都表明,理论化的算法是一回事,实现它们是另一回事。

    不管怎样,对于那些感兴趣的人,这是我写的代码(有很多!):

    范围:H:

    #include <algorithm>
    #include <iostream>
    #include <ctime>
    
    using namespace std;
    
    //  Callback types.
    typedef void (*OutputCallback) (int min, int max);
    typedef int (*GeneratorCallback) ();
    
    //  Declarations of the test functions.
    clock_t Simple (int, int, GeneratorCallback, OutputCallback);
    clock_t QuiteComplex (int, int, GeneratorCallback, OutputCallback);
    clock_t Complex (int, int, GeneratorCallback, OutputCallback);
    

    MCP.CPP:

    #include "Range.h"
    
    int
      checksum;
    
    //  This callback is used to get data.
    int CreateData ()
    {
      return rand ();
    }
    
    //  This callback is used to output the results.
    void OutputResults (int min, int max)
    {
      //cout << min << " - " << max << endl;
      checksum += max - min;
    }
    
    //  The program entry point.
    void main ()
    {
      int
        count = 3600000,
        window = 1000;
    
      srand (0);
      checksum = 0;
      std::cout << "Simple: Ticks = " << Simple (count, window, CreateData, OutputResults) << ", checksum = " << checksum << std::endl;
      srand (0);
      checksum = 0;
      std::cout << "Quite Complex: Ticks = " << QuiteComplex (count, window, CreateData, OutputResults) << ", checksum = " << checksum << std::endl;
      srand (0);
      checksum = 0;
      std::cout << "Complex: Ticks = " << Complex (count, window, CreateData, OutputResults) << ", checksum = " << checksum << std::endl;
    }
    

    Simple.cpp:

    #include "Range.h"
    
    //  Function to actually process the data.
    //  A circular buffer of min/max values for the current window is filled
    //  and once full, the oldest min/max pair is sent to the output callback
    //  and replaced with the newest input value. Each value inputted is 
    //  compared against all min/max pairs.
    void ProcessData
    (
      int count,
      int window,
      GeneratorCallback input,
      OutputCallback output,
      int *min_buffer,
      int *max_buffer
    )
    {
      int
        i;
    
      for (i = 0 ; i < window ; ++i)
      {
        int
          value = input ();
    
        min_buffer [i] = max_buffer [i] = value;
    
        for (int j = 0 ; j < i ; ++j)
        {
          min_buffer [j] = min (min_buffer [j], value);
          max_buffer [j] = max (max_buffer [j], value);
        }
      }
    
      for ( ; i < count ; ++i)
      {
        int
          index = i % window;
    
        output (min_buffer [index], max_buffer [index]);
    
        int
          value = input ();
    
        min_buffer [index] = max_buffer [index] = value;
    
        for (int k = (i + 1) % window ; k != index ; k = (k + 1) % window)
        {
          min_buffer [k] = min (min_buffer [k], value);
          max_buffer [k] = max (max_buffer [k], value);
        }
      }
    
      output (min_buffer [count % window], max_buffer [count % window]);
    }
    
    //  A simple method of calculating the results.
    //  Memory management is done here outside of the timing portion.
    clock_t Simple
    (
      int count,
      int window,
      GeneratorCallback input,
      OutputCallback output
    )
    {
      int
        *min_buffer = new int [window],
        *max_buffer = new int [window];
    
      clock_t
        start = clock ();
    
      ProcessData (count, window, input, output, min_buffer, max_buffer);
    
      clock_t
        end = clock ();
    
      delete [] max_buffer;
      delete [] min_buffer;
    
      return end - start;
    }
    

    quitecomplex.cpp(基特复杂.cpp):

    #include "Range.h"
    
    template <class T>
    class Range
    {
    private:
      //  Class Types
    
      //  Node Data
      //  Stores a value and its position in various lists.
      struct Node
      {
        Node
          *m_queue_next,
          *m_list_greater,
          *m_list_lower;
    
        T
          m_value;
      };
    
    public:
      //  Constructor
      //  Allocates memory for the node data and adds all the allocated
      //  nodes to the unused/free list of nodes.
      Range
      (
        int window_size
      ) :
        m_nodes (new Node [window_size]),
        m_queue_tail (m_nodes),
        m_queue_head (0),
        m_list_min (0),
        m_list_max (0),
        m_free_list (m_nodes)
      {
        for (int i = 0 ; i < window_size - 1 ; ++i)
        {
          m_nodes [i].m_list_lower = &m_nodes [i + 1];
        }
    
        m_nodes [window_size - 1].m_list_lower = 0;
      }
    
      //  Destructor
      //  Tidy up allocated data.
      ~Range ()
      {
        delete [] m_nodes;
      }
    
      //  Function to add a new value into the data structure.
      void AddValue
      (
        T value
      )
      {
        Node
          *node = GetNode ();
    
        //  clear links
        node->m_queue_next = 0;
    
        //  set value of node
        node->m_value = value;
    
        //  find place to add node into linked list
        Node
          *search;
    
        for (search = m_list_max ; search ; search = search->m_list_lower)
        {
          if (search->m_value < value)
          {
            if (search->m_list_greater)
            {
              node->m_list_greater = search->m_list_greater;
              search->m_list_greater->m_list_lower = node;
            }
            else
            {
              m_list_max = node;
            }
    
            node->m_list_lower = search;
            search->m_list_greater = node;
          }
        }
    
        if (!search)
        {
          m_list_min->m_list_lower = node;
          node->m_list_greater = m_list_min;
          m_list_min = node;
        }
      }
    
      //  Accessor to determine if the first output value is ready for use.
      bool RangeAvailable ()
      {
        return !m_free_list;
      }
    
      //  Accessor to get the minimum value of all values in the current window.
      T Min ()
      {
        return m_list_min->m_value;
      }
    
      //  Accessor to get the maximum value of all values in the current window.
      T Max ()
      {
        return m_list_max->m_value;
      }
    
    private:
      //  Function to get a node to store a value into.
      //  This function gets nodes from one of two places:
      //    1. From the unused/free list
      //    2. From the end of the fifo queue, this requires removing the node from the list and tree
      Node *GetNode ()
      {
        Node
          *node;
    
        if (m_free_list)
        {
          //  get new node from unused/free list and place at head
          node = m_free_list;
    
          m_free_list = node->m_list_lower;
    
          if (m_queue_head)
          {
            m_queue_head->m_queue_next = node;
          }
    
          m_queue_head = node;
        }
        else
        {
          //  get node from tail of queue and place at head
          node = m_queue_tail;
    
          m_queue_tail = node->m_queue_next;
          m_queue_head->m_queue_next = node;
          m_queue_head = node;
    
          //  remove node from linked list
          if (node->m_list_lower)
          {
            node->m_list_lower->m_list_greater = node->m_list_greater;
          }
          else
          {
            m_list_min = node->m_list_greater;
          }
    
          if (node->m_list_greater)
          {
            node->m_list_greater->m_list_lower = node->m_list_lower;
          }
          else
          {
            m_list_max = node->m_list_lower;
          }
        }
    
        return node;
      }
    
      //  Member Data.
      Node
        *m_nodes,
        *m_queue_tail,
        *m_queue_head,
        *m_list_min,
        *m_list_max,
        *m_free_list;
    };
    
    //  A reasonable complex but more efficent method of calculating the results.
    //  Memory management is done here outside of the timing portion.
    clock_t QuiteComplex
    (
      int size,
      int window,
      GeneratorCallback input,
      OutputCallback output
    )
    {
      Range <int>
        range (window);
    
      clock_t
        start = clock ();
    
      for (int i = 0 ; i < size ; ++i)
      {   
        range.AddValue (input ());
    
        if (range.RangeAvailable ())
        {
          output (range.Min (), range.Max ());
        }
      }
    
      clock_t
        end = clock ();
    
      return end - start;
    }
    

    Complex.cpp:

    #include "Range.h"
    
    template <class T>
    class Range
    {
    private:
      //  Class Types
    
      //  Red/Black tree node colours.
      enum NodeColour
      {
        Red,
        Black
      };
    
      //  Node Data
      //  Stores a value and its position in various lists and trees.
      struct Node
      {
        //  Function to get the sibling of a node.
        //  Because leaves are stored as null pointers, it must be possible
        //  to get the sibling of a null pointer. If the object is a null pointer
        //  then the parent pointer is used to determine the sibling.
        Node *Sibling
        (
          Node *parent
        )
        {
          Node
            *sibling;
    
          if (this)
          {
            sibling = m_tree_parent->m_tree_less == this ? m_tree_parent->m_tree_more : m_tree_parent->m_tree_less;
          }
          else
          {
            sibling = parent->m_tree_less ? parent->m_tree_less : parent->m_tree_more;
          }
    
          return sibling;
        }
    
        //  Node Members
        Node
          *m_queue_next,
          *m_tree_less,
          *m_tree_more,
          *m_tree_parent,
          *m_list_greater,
          *m_list_lower;
    
        NodeColour
          m_colour;
    
        T
          m_value;
      };
    
    public:
      //  Constructor
      //  Allocates memory for the node data and adds all the allocated
      //  nodes to the unused/free list of nodes.
      Range
      (
        int window_size
      ) :
        m_nodes (new Node [window_size]),
        m_queue_tail (m_nodes),
        m_queue_head (0),
        m_tree_root (0),
        m_list_min (0),
        m_list_max (0),
        m_free_list (m_nodes)
      {
        for (int i = 0 ; i < window_size - 1 ; ++i)
        {
          m_nodes [i].m_list_lower = &m_nodes [i + 1];
        }
    
        m_nodes [window_size - 1].m_list_lower = 0;
      }
    
      //  Destructor
      //  Tidy up allocated data.
      ~Range ()
      {
        delete [] m_nodes;
      }
    
      //  Function to add a new value into the data structure.
      void AddValue
      (
        T value
      )
      {
        Node
          *node = GetNode ();
    
        //  clear links
        node->m_queue_next = node->m_tree_more = node->m_tree_less = node->m_tree_parent = 0;
    
        //  set value of node
        node->m_value = value;
    
        //  insert node into tree
        if (m_tree_root)
        {
          InsertNodeIntoTree (node);
          BalanceTreeAfterInsertion (node);
        }
        else
        {
          m_tree_root = m_list_max = m_list_min = node;
          node->m_tree_parent = node->m_list_greater = node->m_list_lower = 0;
        }
    
        m_tree_root->m_colour = Black;
      }
    
      //  Accessor to determine if the first output value is ready for use.
      bool RangeAvailable ()
      {
        return !m_free_list;
      }
    
      //  Accessor to get the minimum value of all values in the current window.
      T Min ()
      {
        return m_list_min->m_value;
      }
    
      //  Accessor to get the maximum value of all values in the current window.
      T Max ()
      {
        return m_list_max->m_value;
      }
    
    private:
      //  Function to get a node to store a value into.
      //  This function gets nodes from one of two places:
      //    1. From the unused/free list
      //    2. From the end of the fifo queue, this requires removing the node from the list and tree
      Node *GetNode ()
      {
        Node
          *node;
    
        if (m_free_list)
        {
          //  get new node from unused/free list and place at head
          node = m_free_list;
    
          m_free_list = node->m_list_lower;
    
          if (m_queue_head)
          {
            m_queue_head->m_queue_next = node;
          }
    
          m_queue_head = node;
        }
        else
        {
          //  get node from tail of queue and place at head
          node = m_queue_tail;
    
          m_queue_tail = node->m_queue_next;
          m_queue_head->m_queue_next = node;
          m_queue_head = node;
    
          //  remove node from tree
          node = RemoveNodeFromTree (node);
          RebalanceTreeAfterDeletion (node);
    
          //  remove node from linked list
          if (node->m_list_lower)
          {
            node->m_list_lower->m_list_greater = node->m_list_greater;
          }
          else
          {
            m_list_min = node->m_list_greater;
          }
    
          if (node->m_list_greater)
          {
            node->m_list_greater->m_list_lower = node->m_list_lower;
          }
          else
          {
            m_list_max = node->m_list_lower;
          }
        }
    
        return node;
      }
    
      //  Rebalances the tree after insertion
      void BalanceTreeAfterInsertion
      (
        Node *node
      )
      {
        node->m_colour = Red;
    
        while (node != m_tree_root && node->m_tree_parent->m_colour == Red)
        {
          if (node->m_tree_parent == node->m_tree_parent->m_tree_parent->m_tree_more)
          {
            Node
              *uncle = node->m_tree_parent->m_tree_parent->m_tree_less;
    
            if (uncle && uncle->m_colour == Red)
            {
              node->m_tree_parent->m_colour = Black;
              uncle->m_colour = Black;
              node->m_tree_parent->m_tree_parent->m_colour = Red;
              node = node->m_tree_parent->m_tree_parent;
            }
            else
            {
              if (node == node->m_tree_parent->m_tree_less)
              {
                node = node->m_tree_parent;
                LeftRotate (node);
              }
    
              node->m_tree_parent->m_colour = Black;
              node->m_tree_parent->m_tree_parent->m_colour = Red;
              RightRotate (node->m_tree_parent->m_tree_parent);
            }
          }
          else
          {
            Node
              *uncle = node->m_tree_parent->m_tree_parent->m_tree_more;
    
            if (uncle && uncle->m_colour == Red)
            {
              node->m_tree_parent->m_colour = Black;
              uncle->m_colour = Black;
              node->m_tree_parent->m_tree_parent->m_colour = Red;
              node = node->m_tree_parent->m_tree_parent;
            }
            else
            {
              if (node == node->m_tree_parent->m_tree_more)
              {
                node = node->m_tree_parent;
                RightRotate (node);
              }
    
              node->m_tree_parent->m_colour = Black;
              node->m_tree_parent->m_tree_parent->m_colour = Red;
              LeftRotate (node->m_tree_parent->m_tree_parent);
            }
          }
        }
      }
    
      //  Adds a node into the tree and sorted linked list
      void InsertNodeIntoTree
      (
        Node *node
      )
      {
        Node
          *parent = 0,
          *child = m_tree_root;
    
        bool
          greater;
    
        while (child)
        {
          parent = child;
          child = (greater = node->m_value > child->m_value) ? child->m_tree_more : child->m_tree_less;
        }
    
        node->m_tree_parent = parent;
    
        if (greater)
        {
          parent->m_tree_more = node;
    
          //  insert node into linked list
          if (parent->m_list_greater)
          {
            parent->m_list_greater->m_list_lower = node;
          }
          else
          {
            m_list_max = node;
          }
    
          node->m_list_greater = parent->m_list_greater;
          node->m_list_lower = parent;
          parent->m_list_greater = node;
        }
        else
        {
          parent->m_tree_less = node;
    
          //  insert node into linked list
          if (parent->m_list_lower)
          {
            parent->m_list_lower->m_list_greater = node;
          }
          else
          {
            m_list_min = node;
          }
    
          node->m_list_lower = parent->m_list_lower;
          node->m_list_greater = parent;
          parent->m_list_lower = node;
        }
      }
    
      //  Red/Black tree manipulation routine, used for removing a node
      Node *RemoveNodeFromTree
      (
        Node *node
      )
      {
        if (node->m_tree_less && node->m_tree_more)
        {
          //  the complex case, swap node with a child node
          Node
            *child;
    
          if (node->m_tree_less)
          {
            // find largest value in lesser half (node with no greater pointer)
            for (child = node->m_tree_less ; child->m_tree_more ; child = child->m_tree_more)
            {
            }
          }
          else
          {
            // find smallest value in greater half (node with no lesser pointer)
            for (child = node->m_tree_more ; child->m_tree_less ; child = child->m_tree_less)
            {
            }
          }
    
          swap (child->m_colour, node->m_colour);
    
          if (child->m_tree_parent != node)
          {
            swap (child->m_tree_less, node->m_tree_less);
            swap (child->m_tree_more, node->m_tree_more);
            swap (child->m_tree_parent, node->m_tree_parent);
    
            if (!child->m_tree_parent)
            {
              m_tree_root = child;
            }
            else
            {
              if (child->m_tree_parent->m_tree_less == node)
              {
                child->m_tree_parent->m_tree_less = child;
              }
              else
              {
                child->m_tree_parent->m_tree_more = child;
              }
            }
    
            if (node->m_tree_parent->m_tree_less == child)
            {
              node->m_tree_parent->m_tree_less = node;
            }
            else
            {
              node->m_tree_parent->m_tree_more = node;
            }
          }
          else
          {
            child->m_tree_parent = node->m_tree_parent;
            node->m_tree_parent = child;
    
            Node
              *child_less = child->m_tree_less,
              *child_more = child->m_tree_more;
    
            if (node->m_tree_less == child)
            {
              child->m_tree_less = node;
              child->m_tree_more = node->m_tree_more;
              node->m_tree_less = child_less;
              node->m_tree_more = child_more;
            }
            else
            {
              child->m_tree_less = node->m_tree_less;
              child->m_tree_more = node;
              node->m_tree_less = child_less;
              node->m_tree_more = child_more;
            }
    
            if (!child->m_tree_parent)
            {
              m_tree_root = child;
            }
            else
            {
              if (child->m_tree_parent->m_tree_less == node)
              {
                child->m_tree_parent->m_tree_less = child;
              }
              else
              {
                child->m_tree_parent->m_tree_more = child;
              }
            }
          }
    
          if (child->m_tree_less)
          {
            child->m_tree_less->m_tree_parent = child;
          }
    
          if (child->m_tree_more)
          {
            child->m_tree_more->m_tree_parent = child;
          }
    
          if (node->m_tree_less)
          {
            node->m_tree_less->m_tree_parent = node;
          }
    
          if (node->m_tree_more)
          {
            node->m_tree_more->m_tree_parent = node;
          }
        }
    
        Node
          *child = node->m_tree_less ? node->m_tree_less : node->m_tree_more;
    
        if (node->m_tree_parent->m_tree_less == node)
        {
          node->m_tree_parent->m_tree_less = child;
        }
        else
        {
          node->m_tree_parent->m_tree_more = child;
        }
    
        if (child)
        {
          child->m_tree_parent = node->m_tree_parent;
        }
    
        return node;
      }
    
      //  Red/Black tree manipulation routine, used for rebalancing a tree after a deletion
      void RebalanceTreeAfterDeletion
      (
        Node *node
      )
      {
        Node
          *child = node->m_tree_less ? node->m_tree_less : node->m_tree_more;
    
        if (node->m_colour == Black)
        {
          if (child && child->m_colour == Red)
          {
            child->m_colour = Black;
          }
          else
          {
            Node
              *parent = node->m_tree_parent,
              *n = child;
    
            while (parent)
            {
              Node
                *sibling = n->Sibling (parent);
    
              if (sibling && sibling->m_colour == Red)
              {
                parent->m_colour = Red;
                sibling->m_colour = Black;
    
                if (n == parent->m_tree_more)
                {
                  LeftRotate (parent);
                }
                else
                {
                  RightRotate (parent);
                }
              }
    
              sibling = n->Sibling (parent);
    
              if (parent->m_colour == Black &&
                sibling->m_colour == Black &&
                (!sibling->m_tree_more || sibling->m_tree_more->m_colour == Black) &&
                (!sibling->m_tree_less || sibling->m_tree_less->m_colour == Black))
              {
                sibling->m_colour = Red;
                n = parent;
                parent = n->m_tree_parent;
                continue;
              }
              else
              {
                if (parent->m_colour == Red &&
                  sibling->m_colour == Black &&
                  (!sibling->m_tree_more || sibling->m_tree_more->m_colour == Black) &&
                  (!sibling->m_tree_less || sibling->m_tree_less->m_colour == Black))
                {
                  sibling->m_colour = Red;
                  parent->m_colour = Black;
                  break;
                }
                else
                {
                  if (n == parent->m_tree_more &&
                    sibling->m_colour == Black &&
                    (sibling->m_tree_more && sibling->m_tree_more->m_colour == Red) &&
                    (!sibling->m_tree_less || sibling->m_tree_less->m_colour == Black))
                  {
                    sibling->m_colour = Red;
                    sibling->m_tree_more->m_colour = Black;
                    RightRotate (sibling);
                  }
                  else
                  {
                    if (n == parent->m_tree_less &&
                      sibling->m_colour == Black &&
                      (!sibling->m_tree_more || sibling->m_tree_more->m_colour == Black) &&
                      (sibling->m_tree_less && sibling->m_tree_less->m_colour == Red))
                    {
                      sibling->m_colour = Red;
                      sibling->m_tree_less->m_colour = Black;
                      LeftRotate (sibling);
                    }
                  }
    
                  sibling = n->Sibling (parent);
                  sibling->m_colour = parent->m_colour;
                  parent->m_colour = Black;
    
                  if (n == parent->m_tree_more)
                  {
                    sibling->m_tree_less->m_colour = Black;
                    LeftRotate (parent);
                  }
                  else
                  {
                    sibling->m_tree_more->m_colour = Black;
                    RightRotate (parent);
                  }
                  break;
                }
              }
            }
          }
        }
      }
    
      //  Red/Black tree manipulation routine, used for balancing the tree
      void LeftRotate
      (
        Node *node
      )
      {
        Node
          *less = node->m_tree_less;
    
        node->m_tree_less = less->m_tree_more;
    
        if (less->m_tree_more)
        {
          less->m_tree_more->m_tree_parent = node;
        }
    
        less->m_tree_parent = node->m_tree_parent;
    
        if (!node->m_tree_parent)
        {
          m_tree_root = less;
        }
        else
        {
          if (node == node->m_tree_parent->m_tree_more)
          {
            node->m_tree_parent->m_tree_more = less;
          }
          else
          {
            node->m_tree_parent->m_tree_less = less;
          }
        }
    
        less->m_tree_more = node;
        node->m_tree_parent = less;
      }
    
      //  Red/Black tree manipulation routine, used for balancing the tree
      void RightRotate
      (
        Node *node
      )
      {
        Node
          *more = node->m_tree_more;
    
        node->m_tree_more = more->m_tree_less;
    
        if (more->m_tree_less)
        {
          more->m_tree_less->m_tree_parent = node;
        }
    
        more->m_tree_parent = node->m_tree_parent;
    
        if (!node->m_tree_parent)
        {
          m_tree_root = more;
        }
        else
        {
          if (node == node->m_tree_parent->m_tree_less)
          {
            node->m_tree_parent->m_tree_less = more;
          }
          else
          {
            node->m_tree_parent->m_tree_more = more;
          }
        }
    
        more->m_tree_less = node;
        node->m_tree_parent = more;
      }
    
      //  Member Data.
      Node
        *m_nodes,
        *m_queue_tail,
        *m_queue_head,
        *m_tree_root,
        *m_list_min,
        *m_list_max,
        *m_free_list;
    };
    
    //  A complex but more efficent method of calculating the results.
    //  Memory management is done here outside of the timing portion.
    clock_t Complex
    (
      int count,
      int window,
      GeneratorCallback input,
      OutputCallback output
    )
    {
      Range <int>
        range (window);
    
      clock_t
        start = clock ();
    
      for (int i = 0 ; i < count ; ++i)
      {   
        range.AddValue (input ());
    
        if (range.RangeAvailable ())
        {
          output (range.Min (), range.Max ());
        }
      }
    
      clock_t
        end = clock ();
    
      return end - start;
    }
    
        7
  •  0
  •   Tim Cooper    14 年前

    算法思想:

    获取前1000个数据值并对其进行排序
    排序中的最后一个-第一个是范围(data+0,data+999)。
    然后从排序堆中删除第一个具有值数据的元素[0]
    并添加元素数据[1000]
    现在,排序中的最后一个-第一个是范围(data+1,data+1000)。
    重复直到完成

    // This should run in (DATA_LEN - RANGE_WIDTH)log(RANGE_WIDTH)
    #include <set>
    #include <algorithm>
    using namespace std;
    
    const int DATA_LEN = 3600000;
    double* const data = new double (DATA_LEN);
    
    ....
    ....
    
    const int RANGE_WIDTH = 1000;
    double range = new double(DATA_LEN - RANGE_WIDTH);
    multiset<double> data_set;
    data_set.insert(data[i], data[RANGE_WIDTH]);
    
    for (int i = 0 ; i < DATA_LEN - RANGE_WIDTH - 1 ; i++)
    {
       range[i] = *data_set.end() - *data_set.begin();
       multiset<double>::iterator iter = data_set.find(data[i]);
       data_set.erase(iter);
       data_set.insert(data[i+1]);
    }
    range[i] = *data_set.end() - *data_set.begin();
    
    // range now holds the values you seek
    

    您可能应该通过1个错误来检查这一点,但是这个想法是存在的。