【问题标题】:How to re-sort already sorted array where one element updates如何重新排序一个元素更新的已排序数组
【发布时间】:2012-12-08 10:15:54
【问题描述】:

我有一个固定大小的数组(在现实生活中大小 = 20),允许重复例如:

1 2 2 3 3 4 5 6 7 8 9

现在正好更新了一个元素:

1 5 2 3 3 4 5 6 7 8 9

我需要使用这个数组。我应该只使用冒泡排序吗?

更新我不知道怎么称呼我写的。但我想不可能更快地排序。欢迎 cmets!

    // array is already almost sorted and INCREASING, element at pos need to be inserted to the right place
    private void SortQuotes(List<Quote> quoteList, int pos)
    {
        var quoteToMove = quoteList[pos];
        if (pos == 0 || quoteList[pos - 1].Price < quoteToMove.Price)
        {
            MoveElementsDown(quoteList, pos);
        } else if (pos == quoteList.Count - 1 || quoteList[pos + 1].Price > quoteToMove.Price)
        {
            MoveElementsUp(quoteList, pos);
        }
    }

    private void MoveElementsDown(List<Quote> quoteList, int pos)
    {
        var quoteToInsert = quoteList[pos];
        var price = quoteToInsert.Price;
        for (int i = pos - 1; i >= 0; i--)
        {
            var nextQuote = quoteList[i];
            if (nextQuote.Price > price)
            {
                quoteList[i + 1] = quoteList[i];
                if (i == 0)   // last element
                {
                    quoteList[i] = quoteToInsert;
                }
            }
            else
            {
                quoteList[i + 1] = quoteToInsert;
                break;
            }
        }
    }

    private void MoveElementsUp(List<Quote> quoteList, int pos)
    {
        var quoteToInsert = quoteList[pos];
        var price = quoteToInsert.Price;
        for (int i = pos + 1; i < quoteList.Count; i++)
        {
            var nextQuote = quoteList[i];
            if (nextQuote.Price < price)
            {
                quoteList[i - 1] = quoteList[i];
                if (i == quoteList.Count - 1)   // last element
                {
                    quoteList[i] = quoteToInsert;
                }
            }
            else
            {
                quoteList[i - 1] = quoteToInsert;
                break;
            }
        }
    }

更新我知道哪个元素是奇怪的,即它的位置是已知的!

【问题讨论】:

  • 在您的情况下,冒泡排序并不是那么糟糕,而是自定义的冒泡排序,它只迭代列表一次。 (而不是 N 次),这将花费 O(n)。

标签: java algorithm sorting


【解决方案1】:

此解决方案将每个元素移动一个,直到找到奇数元素的正确位置。由于它已在第一步中被覆盖,因此将其保存在临时变量“h”中,然后写入最终位置。它需要最少的比较和移位操作:

 static void MoveOddElementToRightPosition(int[] a, int oddPosition)
 {
   int h = a[oddPosition];
   int i;
   if (h > a[oddPosition + 1])
     for (i = oddPosition; i < a.Count()-1 && a[i+1] <= h; i++)
        a[i] = a[i+1];
   else
     for (i = oddPosition; i > 0 && a[i-1] >= h; i--)
        a[i] = a[i - 1];
   a[i] = h;
 }

【讨论】:

  • 和我在描述中写的完全一样。但是我认为这是正确的答案
  • 好吧,这只会向上移动。如果 A[OldPos] 恰好低于 a[OldPos-1] 怎么办?
  • 哎呀,我想我写这篇文章的时候已经太晚了。我会添加一个条件
【解决方案2】:

如果最后一个元素需要到达前面,冒泡排序将使用 n^2 次。使用插入排序。

【讨论】:

  • 没有 1 次迭代冒泡排序将花费 O(n)
  • 而且,如果放错位置的元素需要移到列表的前面,则只会将该元素移动一个位置。
  • 我忘了说我知道哪个元素是奇数!
【解决方案3】:

由于数组很小,对于小型数组,插入排序大约需要 ~O(n) 时间,如果您只是更新 1 个值,则插入排序应该以最佳方式实现您的目的。

【讨论】:

  • 插入排序不需要 O(n)
  • 它谈论已经排序的列表。但这没有排序,有一个奇怪的元素。
  • 此列表几乎已排序。您也可以在下面提到的链接中使用动画自行检查。选择您的数据集,然后单击左侧的刷新按钮。小数组和近似排序数组的线性性能sorting-algorithms.com/insertion-sort
  • 另外,如果您签入 Arrays.sort() 的 jdk 实现。您可以检查 INSERTION_SORT_THRESHOLD,如果大小
【解决方案4】:

It can be done in O(n)。如果您不知道该元素,则在 O(n) 中搜索该元素,然后您只需要比较和交换每个元素,这将花费 O(n)。所以总共 2n 这意味着 O(n)。如果您知道已修改的元素,然后比较并交换每个元素。

【讨论】:

    【解决方案5】:
    • 如果您对快速替换元素感兴趣,那么您还可以使用快速删除和插入的结构,例如 Java 中的 TreeSet。这在理论上意味着 O(log(n)),但如果你只是操作 20 个元素的数组,它可能不值得
    • 如果所有不同元素的集合都是有限的,例如在您的示例中您只使用数字表示 1 到 9,那么在 O(1) 中就有一个解决方案。您只需保留一个包含元素出现次数的数组,而不是排序列表。
    • 如果您仍想将所有内容保存在数组中,那么最快的方法是
      1. 在 O(log(n)) 中通过二等分找到要删除的元素的位置 A。
      2. 以同样的方式找到新元素的最终位置 B。更准确地说,B 是每个 k > B
      3. 的 new_element 如果 A A,则执行相同的操作,但向右移动。现在这一步在 O(n) 中,但没有逻辑,它只是移动内存。在 C 语言中,您可以使用 memmove,它已经过高度优化,但我不知道任何 Java 等价物。

    【讨论】:

    • 我假设我在这里不需要二进制搜索。无论如何,我确实需要移动一堆过时的元素。所以可以使用纯bublesort,它会比二分查找更快。
    • 我们谈论的是算法,然后才是复杂性。通常遍历数组,比较和移动每个元素比寻找正确的位置然后进行内存移动更快。
    【解决方案6】:

    您无需再次对其进行排序。

    只有一个元素发生变化。因此,您只需要浏览列表并将更改的号码放在适当的位置即可。 这将是 O(n) 复杂度

    int a[] = {1, 5, 2, 3, 3, 4, 5, 6, 7, 8, 9};
    int count = 0;
    
    //find the odd element
    for(int jj=1; jj< a.length; jj++){
        if(a[jj] < a[count])
            break;
        else count++;
    }
    System.out.println(" Odd position "  + count);
    
    //put odd element to proper position
    for(int k= count+1; k<a.length; k++){
        if(a[count] > a[k]){
            int t = a[count];
            a[count] = a[k];
            a[k] = t;
            count++;
        }
    }
    

    以上是针对给定输入测试的工作代码。 享受吧。

    【讨论】:

    • 谢谢,在每次迭代的代码中,您编写的元素将在下一次迭代中重写。最好只在最后一步编写“奇数”元素(如我上面描述的代码)。
    • 您在第二个循环中使用了太多的分配/交换。请在下面查看我的改进
    • 同意,它不是很优化。只是想有一个工作代码:)
    【解决方案7】:

    在这种情况下,冒泡排序非常好,最多可进行 20 次比较。

    但是用二分查找找到新位置是 O(log(n)),在这种情况下是 5 次比较。
    稍微快一点,如果你需要最后一点奇数的速度,请使用二进制搜索,否则你可以坚持使用冒泡排序。

    【讨论】:

    • 重点是在冒泡排序时我会更新数组。但是在找到位置后,我必须花费 O(n) 操作来移动元素,所以冒泡排序更好
    【解决方案8】:

    这是一个简单的 C 语言实现。测试后删除fprintf(stderr, ...。只要有比较功能,ITEM 可以是任何东西。否则:使用指向 ITEM 的指针,(并且可能添加一个额外的 sizeofelem 参数,ala qsort)

    #include <stdio.h>
    #include <string.h>
    
    typedef int ITEM;
    
    int item_cmp(ITEM one, ITEM two);
    unsigned one_bubble( ITEM *arr, unsigned cnt, unsigned hot , int (*cmp)(ITEM,ITEM) );
    
    int item_cmp(ITEM one, ITEM two)
    {
    fprintf(stderr,"Cmp= %u to %u: %d\n", one, two, one-two);
    if (one > two) return 1;
    else if (one < two) return -1;
    else return 0;
    }
    
    unsigned one_bubble( ITEM *arr, unsigned cnt, unsigned hot , int (*cmp)(ITEM,ITEM) )
    {
    unsigned goal = cnt;
    int diff;
    ITEM temp;
    
            /* hot element should move to the left */
    if (hot > 0 && (diff=cmp( arr[hot-1], arr[hot])) > 0) {
            /* Find place to insert (this could be a binary search) */
            for (goal= hot; goal-- > 0; ) {
                    diff=cmp( arr[goal], arr[hot]);
                    if (diff <= 0) break;
                    }
            goal++;
            fprintf(stderr,"Move %u LEFT to %u\n", hot, goal);
            if (goal==hot) return hot;
            temp = arr[hot];
                    /* shift right */
            fprintf(stderr,"memmove(%u,%u,%u)\n", goal+1, goal, (hot-goal) );
            memmove(arr+goal+1, arr+goal, (hot-goal) *sizeof temp);
            arr[goal] = temp;
            return goal; /* new position */
            }
            /* hot element should move to the right */
    else if (hot < cnt-1 && (diff=cmp( arr[hot], arr[hot+1])) > 0) {
            /* Find place to insert (this could be a binary search) */
            for (goal= hot+1; goal < cnt; goal++ ) {
                    diff=cmp( arr[hot], arr[goal]);
                    if (diff <= 0) break;
                    }
            goal--;
            fprintf(stderr,"Move %u RIGHT to %u\n", hot, goal);
            if (goal==hot) return hot;
            temp = arr[hot];
                    /* shift left */
            fprintf(stderr,"memmove(%u,%u,%u)\n", hot, hot+1, (goal-hot) );
            memmove(arr+hot, arr+hot+1, (goal-hot) *sizeof temp);
            arr[goal] = temp;
            return goal; /* new position */
            }
    fprintf(stderr,"Diff=%d Move %u Not to %u\n", diff, hot, goal);
    return hot;
    }
    
    ITEM array[10] = { 1,10,2,3,4,5,6,7,8,9,};
    #define HOT_POS 1
    int main(void)
    {
    unsigned idx;
    
    idx = one_bubble(array, 10, HOT_POS, item_cmp);
    
    printf("%u-> %u\n", HOT_POS, idx );
    
    for (idx = 0; idx < 10; idx++) {
            printf("%u: %u\n", idx, array[idx] );
            }
    
    return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2019-10-23
      • 2020-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-14
      • 2016-01-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多