【问题标题】:What sorting method is this being applied and what is the algorithmic complexity of the method这是应用什么排序方法,该方法的算法复杂度是多少
【发布时间】:2021-06-29 14:12:36
【问题描述】:

我遇到了下面实现排序数组的代码。

我已经申请了一个很长的数组,它能够在一秒内完成,可能是 20 毫秒或更短。

我一直在阅读有关算法复杂性和大 O 表示法的文章,并想知道:

  1. 在此代码中实现的(现有的)排序方法是什么。
  2. 这里使用的算法的复杂度是多少。
  3. 如果你要改进下面的算法/代码,你会改变什么。
using System;
using System.Text;
//This program sorts an array
public class SortArray
{
    static void Main(String []args)
    {
        // declaring and initializing the array 
        //int[] arr = new int[] {3,1,4,5,7,2,6,1, 9,11, 7, 2,5,8,4}; 
        
 int[] arr = new int[] {489,491,493,495,497,529,531,533,535,369,507,509,511,513,515,203,205,207,209,211,213,107,109,111,113,115,117,11913,415,417,419,421,423,425,427,15,17,19,21,4,517,519,521,523,525,527,4,39,441,443,445,447,449,451,453,455,457,459,461,537,539,541,543,545,547,1,3,5,7,9,11,13,463,465,467,23,399,401,403,405,407,409,411,499,501,503,505,333,335,337,339,341,343,345,347,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,9,171,173,175,177,179,181,183,185,187,269,271,273,275,277,279,281,283,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,133,135,137,139,141,143,145,285,287,289,291,121,123,125,127,129,131,297,299,373,375,377,379,381,383,385,387,389,97,99,101,103,105,147,149,151,153,155,157,159,161,163,165,167,16,391,393,395,397,399,401,403,189,191,193,195,197,199,201,247,249,251,253,255,257,259,261,263,265,267,343,345,347,349,501,503,505,333,335,337,339,341,417,419,421,423,425,561,563,565,567,569,571,573,587,589,591,593,595,597,599,427,429,431,433,301,303,305,307,309,311,313,315,317,319,321,323,325,327,329,331,371,359,361,363,365,367,369,507,509,511,513,515,351,353,355,57,517,519,521,523,525,527,413,415,405,407,409,411,499,435,437,469,471,473,475,477,479,481,483,485,487,545,547,549,551,553,555,575,577,579,581,583,585,557,559,489,491,493,495,497,529,531,533,535,537,539,541,543,215,217,219,221,223,225,227,229,231,233,235,237,239,241,243,245,293,295};
        
  
        int temp; 
          // traverse 0 to array length 
        for (int i = 0; i < arr.Length ; i++) 
        {
            // traverse i+1 to array length 
            //for (int j = i + 1; j < arr.Length; j++) 
            for (int j = i+1; j < arr.Length; j++) 
            {
                // compare array element with  
                // all next element 
                if (arr[i] > arr[j]) { 
                    ///Console.WriteLine(i+"i before"+arr[i]); 
                    temp = arr[i]; 
                    arr[i] = arr[j]; 
                    arr[j] = temp; 
                    //Console.WriteLine("i  After"+arr[i]); 
                }
            }
        }           
  
        // print all element of array 
        foreach(int value in arr) 
        { 
            Console.Write(value + " "); 
        } 

    }
}

【问题讨论】:

  • 选择排序 - O(N^2) - 还有很多其他选项。我可以通过快速的谷歌搜索找到这个,请在​​作为问题发布之前尝试研究一些东西 - Big O Cheat Sheet
  • 在学习的时候,这种代码就可以了。当你完成任务时,你应该使用 Array.Sort(arr); 。微软聘请了真正了解复杂性的精英计算机科学家,并让他们花费大量时间为我们这些凡人尽快完成这类事情。
  • 如果您打算成为 Microsoft、Google 或 Amazon 团队的一员,他们要求您了解的不仅仅是基础知识和使用 array.sort (arrayx)....
  • 在讨论排序算法时,“非常长的数组”是一个包含超过一百万个元素的数组。问题中的数组很小。
  • 我能够创建一个很长的数组并增加了代码的时间。排序花了 40 秒。现在我可以使用其他方法创建代码并进行比较。

标签: c# algorithm sorting


【解决方案1】:

这是selection sort。它的时间复杂度是 O(?²)。它在ij 上有嵌套循环,您可以看到它们在{0,...,?-1} 范围内生成所有可能的两个索引集,其中? 是arr.Length。对数为triangular number,等于:

?(?-1)/2

...这是 O(?²)

如果我们坚持选择排序,我们仍然可以找到一些改进。

我们可以看到,外循环的作用是在arr[i] 中存储最终排序数组中属于那里的值,并且永远不会再接触该条目。它通过搜索从该索引 ? 开始的数组右侧部分的最小值来实现。

现在在内部循环中进行的搜索期间,它不断将较小的值交换到arr[i]。这可能会发生几次,因为当j 向右移动时,它可能会找到更小的值。这是对操作的浪费,因为我们宁愿只执行一次交换。这是可能的:不是立即交换,而是延迟此操作。而是跟踪最小值的位置位于(最初位于i,但这可能会变成某个j 索引)。只有当内部循环完成时,才执行交换。

没有那么重要的改进:i 不必等于arr.Length - 1,因为这样就没有内部循环的迭代。因此,外部循环的结束条件可以排除该迭代的发生。

看起来是这样的:

for (int i = 0, last = arr.Length - 1; i < last; i++) 
{
    int k = i; // index that has the least value in the range arr[i..n-1] so far
    for (int j = i+1; j < arr.Length; j++) 
    {
        if (arr[k] > arr[j]) { 
            k = j; // don't swap yet -- just track where the minimum is located
        }
    }
    if (k > i) { // now perform the swap
        int temp = arr[i];
        arr[i] = arr[k]; 
        arr[k] = temp; 
    }
}

进一步的改进可以是使用内部循环不仅可以定位最小值,还可以定位最大值,并将找到的最大值移动到数组的右端。这样,数组的两端逐渐排序,内部循环将缩短两倍。尽管如此,比较次数保持不变,平均掉期次数也保持不变。所以收益只在于迭代开销。

【讨论】:

  • 先生,我尝试了那里使用的代码,但效果不佳。它给出了不同的结果。它没有输出整个数组。
  • 您能否通过数组示例链接到您的实现?
  • 如果您运行此代码,它将很好地完成排序。如果您运行上面的内容,它不会以相同的方式运行。 dropbox.com/s/3bduh4rrleft7jl/sort.cs?dl=0
  • 我刚刚在我的代码块中看到了一个错字。 = arr[i]。我想这就是你得到不同结果的原因。现已更正。
【解决方案2】:

这是 O(n^2) 的“冒泡排序”。您可以使用“Mergesort”或“Quicksort”将您的算法改进到 O(n*log(n))。如果您总是知道数字的最小值和最大值,则可以使用 O(n) 的“数字排序”或“基数排序”

见:Sorting alrogithms in c#

【讨论】:

  • 这不是冒泡排序。查看已接受的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-12
  • 2023-03-07
  • 2017-03-27
  • 2012-07-10
  • 1970-01-01
相关资源
最近更新 更多