c# - 这是应用什么排序方法,该方法的算法复杂度是多少
问题描述
我遇到了下面用于实现排序数组的代码。
我已经申请了一个非常长的阵列,它能够在一秒内完成,可能是 20 毫秒或更短。
我一直在阅读有关算法复杂性和大 O 表示法的信息,并想知道:
- 这是在此代码中实现的(现有的)排序方法。
- 这里使用的算法的复杂度是多少。
- 如果你要改进下面的算法/代码,你会改变什么。
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(²)。i
它在和上有嵌套循环j
,您可以看到这些循环在 {0,...,-1} 范围内产生每个可能的两个索引集,其中 is arr.Length
。对的数量是一个三角形数,并且等于:
(-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;
}
}
进一步的改进可以是使用内部循环不仅可以定位最小值,还可以定位最大值,并将找到的最大值移动到数组的右端。这样,数组的两端逐渐排序,内部循环将缩短两倍。尽管如此,比较次数保持不变,平均掉期次数也保持不变。因此,收益仅在于迭代开销。
推荐阅读
- reactjs - 在 React JS 中将密钥从组件发送到另一个组件
- java - 防止用户在 Java 中输入空格
- c++ - Why there is no std::erase?
- c# - 比较日期大于 C#
- python - 如何使用重复索引进行数据透视表
- datetime - 在 Flutter / Dart 中获取上个月的日期
- json - 当您将标志“?debugmode = false”附加到Web url的末尾时,它会做什么
- javascript - Mobx 反应表单自定义 DVR 规则
- sql - Oracle 生成数据
- ansible - ansible:如何通过字母数字键/索引/哈希访问 yaml 定义的数组