【问题标题】:How to continuous check if array is sorted after removes/adds/updates of elements如何在删除/添加/更新元素后连续检查数组是否排序
【发布时间】:2015-12-29 08:18:00
【问题描述】:

假设给定一个包含 n 个整数的列表(该列表不需要已经排序)。删除、更新或插入值后如何检查列表是否已排序(非递增或非递减)?

我能想到的唯一解决这个问题的方法是使用 remove[O(n)],insert[O(n)] 和 update [O(n)] 和 a线性检查以查看其排序是非递减还是非递增。有没有可能更快地解决这个问题?

删除、插入和更新意味着用户将给出一个位置来删除/插入/更新,并且值将被插入、删除或添加到给定的位置。

在输入的任何时候都会有一个查询询问列表处于哪个状态(非增加或非减少)

【问题讨论】:

  • 删除不会扭曲排序顺序。添加可以通过二进制搜索来实现,以插入正确的位置以保持排序。更新可以实现为删除/添加。
  • 您打算保持容器排序(即在插入/修改后容器应该保持排序),还是只想能够有效地检查容器是否保持排序?
  • “我只是想继续检查列表是否保持排序状态” - 嗯??只需检查上一个和下一个元素...
  • 可以进行连续的删除/添加/更新。程序有一个查询输入,如果列表在每个时刻都按非递增或非递减排序,则必须回答。
  • 我想你问的是“在任何时候列表都可以处于已排序或未排序状态。此列表上的任何操作都需要根据它现在是否已排序来快速更新状态。”所以所有“保持分类”的建议都不是你想要的。对吗?

标签: algorithm


【解决方案1】:

这里是不减的逻辑(复制它的扭曲为不增加)。

跟踪相邻对的数量x, y 使得x > y,即减少对。该列表是非递减的当且仅当此数字为零。

ac (a, c => a, b, c) 之间插入b

num_decreasing_pairs -= a > c
num_decreasing_pairs += a > b
num_decreasing_pairs += b > c

删除ac 之间的b (a, b, c => a, c):

num_decreasing_pairs -= a > b
num_decreasing_pairs -= b > c
num_decreasing_pairs += a > c

ac (a, b1, c => a, b2, c) 之间将b1 更新为b2

num_decreasing_pairs -= a > b1
num_decreasing_pairs -= b1 > c
num_decreasing_pairs += a > b2
num_decreasing_pairs += b2 > c

所有这些语句都应该由检查检查的元素是否存在(边缘情况)的 if 保护。

【讨论】:

    【解决方案2】:

    如果您维护一个值的链表列表,其中每个子链表按升序排列,那么当只有一个子链表时,您就知道您有一个排序列表。

    现在的操作是:-

    • 删除 - 如果从子列表的开头或结尾删除,请检查您现在是否可以将两个子列表合并为一个。
    • 添加 - 如果这破坏了子列表顺序,则将子列表拆分为两个新的
    • 更新 - 与删除和添加相同。

    [省略了很多关于链表的细节,访问头/尾,计数值以快速到达正确的子链表,...]

    【讨论】:

      【解决方案3】:

      列表仍应在Remove 之后排序(假设代码没有做任何愚蠢的事情)以便解决。对于Insert,编写函数以将新元素添加到正确的位置。将Update 视为Remove,后跟Insert。如果您真的希望追求“是否有序”标准,请使用闭包来确定两个列表元素是否有序,然后只需将列表划分为两个重叠的对并映射闭包在结果对的集合上。如果地图不包含错误结果,表明所有重叠对都是有序的,那么您就是黄金。

      在 Clojure(Lisp 变体)中实现时,如下所示:

      (defn is-ordered? [c f]
        "Determines if a collection is in sorted order as defined by the function f.
         c is a collection
         f is a function which accepts a collection for an argument, returning
         true if the collection is 'ordered' by  f's definition of 'ordered', and false
         if not."
        (not (contains? (set (map f (partition 2 1 c))) false)))
      

      祝你好运。

      【讨论】:

      • 正如作者所说 - 列表最初可能没有排序。
      【解决方案4】:

      您可以使用自动二进制搜索来获得最佳性能。

      例子:

      class InternalList<T> : IEnumerable<T>
      {
          private static readonly T[] Empty = new T[0];
      
          private int version;
          private int size;
          private T[] items;
          private IComparer<T> comparer;
      
          public InternalList() : this(0, null) { }
          public InternalList(int capacity) : this(capacity, null) { }
      
          public InternalList(int capacity, IComparer<T> comparer)
          {
              if (capacity < 0)
              {
                  throw new ArgumentOutOfRangeException("capacity");
              }
      
              this.items = (capacity == 0) ? Empty : new T[capacity];
              this.comparer = comparer ?? Comparer<T>.Default;
          }
      
          public void Add(T item)
          {
              if (size == items.Length)
              {
                  Array.Resize(ref items, (size == 0 ? 4 : size * 2));
              }
      
              int index = Search(item);
      
              if (index != size)
              {
                  Array.Copy(items, index, items, index + 1, size - index);
              }
      
              items[index] = item;
              size++;
              version++;
          }
      
          public void RemoveAt(int index)
          {
              if (index < 0 || index >= size)
              {
                  throw new IndexOutOfRangeException();
              }
      
              if (index != size - 1)
              {
                  Array.Copy(items, index + 1, items, index, (size - index) - 1);
              }
      
              items[--size] = default(T);
              version++;
          }
      
          public void Clear()
          {
              if (size != 0)
              {
                  Array.Clear(items, 0, size);
                  size = 0;
                  version++;
              }
          }
      
          public IEnumerator<T> GetEnumerator()
          {
              return new Enumerator(this);
          }
      
          private int Search(T item)
          {
              if (size == 0)
              {
                  return 0;
              }
      
              int x = 0;
              int y = size;
      
              while (true)
              {
                  int d = (y - x) / 2;
                  int n = comparer.Compare(items[x + d], item);
      
                  if (n < 0)
                  {
                      if (d == 0)
                      {
                          return x + 1;
                      }
      
                      x += d;
      
                      continue;
                  }
                  else if (n > 0)
                  {
                      if (d == 0)
                      {
                          return x;
                      }
      
                      y -= d;
      
                      continue;
                  }
      
                  return x + d;
              }
          }
      
          IEnumerator IEnumerable.GetEnumerator()
          {
              return new Enumerator(this);
          }
      
          public struct Enumerator : IEnumerator<T>
          {
              private InternalList<T> list;
              private int version;
              private int index;
              private T current;
      
              internal Enumerator(InternalList<T> list)
              {
                  this.list = list;
                  this.version = list.version;
                  this.index = -1;
                  this.current = default(T);
              }
      
              public T Current
              {
                  get
                  {
                      if (index == -1)
                      {
                          throw new InvalidOperationException();
                      }
      
                      return current;
                  }
              }
      
              object IEnumerator.Current
              {
                  get { return Current; }
              }
      
              public bool MoveNext()
              {
                  if (version != list.version)
                  {
                      throw new InvalidOperationException();
                  }
      
                  if (index < list.size - 1)
                  {
                      current = list.items[++index];
      
                      return true;
                  }
      
                  return false;
              }
      
              public void Reset()
              {
                  if (version != list.version)
                  {
                      throw new InvalidOperationException();
                  }
      
                  index = -1;
                  current = default(T);
              }
      
              public void Dispose() { }
          }
      }
      

      但是,如果预计列表会很长,并且如果预计添加不合逻辑,那么使用 System.Generic.SortedList 可能更明智,假设您使用的是 DotNET。

      关于您自动跟踪列表顺序的请求;这当然是一个糟糕的设计。所有中断检查所消耗的时间可用于从头开始对列表进行排序。

      【讨论】:

        猜你喜欢
        • 2022-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-02
        • 2018-06-15
        • 1970-01-01
        相关资源
        最近更新 更多