各种排序算法汇总
排序是计算机内经常进行的一种操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列。分内部排序和外部排序。若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序。反之,若参加排序的记录数量很大,整个序列的排序过程不可能在内存中完成,则称此类排序问题为外部排序。内部排序的过程是一个逐步扩大记录的有序序列长度的过程。
将杂乱无章的数据元素,通过一定的方法按关键字顺序排列的过程叫做排序。假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的。
分类
稳定排序:假设在待排序的文件中,存在两个或两个以上的记录具有相同的关键字,在
用某种排序法排序后,若这些相同关键字的元素的相对次序仍然不变,则这种排序方法
是稳定的。其中冒泡,插入,基数,归并属于稳定排序,选择,快速,希尔,堆属于不稳定排序。
就地排序:若排序算法所需的辅助空间并不依赖于问题的规模n,即辅助空间为O(1),
则称为就地排序。(百度百科)
已知一组无序数据a[1]、a[2]、……a[n],需将其按升序排列。首先比较a[1]与a[2]的值,若a[1]大于a[2]则交换两者的值,否则不变。再比较a[2]与a[3]的值,若a[2]大于a[3]则交换两者的值,否则不变。再比较a[3]与a[4],以此类推,最后比较a[n-1]与a[n]的值。这样处理一轮后,a[n]的值一定是这组数据中最大的。再对a[1]~a[n-1]以相同方法处理一轮,则a[n-1]的值一定是a[1]~a[n-1]中最大的。再对a[1]~a[n-2]以相同方法处理一轮,以此类推。共处理n-1轮后a[1]、a[2]、……a[n]就以升序排列了。降序排列与升序排列相类似,若a[1]小于a[2]则交换两者的值,否则不变,后面以此类推。 总的来讲,每一轮排序后最大(或最小)的数将移动到数据序列的最后,理论上总共要进行n(n-1)/2次交换。
代码实现
![复制代码](http://common.cnblogs.com/images/copycode.gif)
1 /// summary 2 /// 冒泡排序 3 /// /summary 4 /// param name="arry" 要排序的整数数组 /param 5 public static void BubbleSort(this int[] arry) 7 for (int i = 0; i arry.Length-1; i++) 9 for (int j = 0; j arry.Length - 1 - i; j++) 11 //比较相邻的两个元素,如果前面的比后面的大,则交换位置 12 if (arry[j] arry[j + 1]) 14 int temp = arry[j + 1]; 15 arry[j + 1] = arry[j]; 16 arry[j] = temp; 20 }
![复制代码](http://common.cnblogs.com/images/copycode.gif)
简单测试
![复制代码](http://common.cnblogs.com/images/copycode.gif)
1 class Program 3 static void Main(string[] args) 5 int[] arry = new int[] { 1, 2, 3, 4, 1, -1 }; 6 arry.BubbleSort(); 7 for (int i = 0; i arry.Length; i++) 9 Console.Write("\t" + arry[i]); 11 Console.Read(); 13 }
![复制代码](http://common.cnblogs.com/images/copycode.gif)
结果
这里采用的是为整型数组添加扩展方法实现的冒泡排序。
优点:稳定
缺点:慢,每次只移动相邻的两个元素。
时间复杂度:理想情况下(数组本来就是有序的),此时最好的时间复杂度为o(n),最坏的时间复杂度(数据反序的),此时的时间复杂度为o(n*n) 。冒泡排序的平均时间负责度为o(n*n).
设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。
一趟快速排序的算法是:
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]互换;
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
代码实现
![复制代码](http://common.cnblogs.com/images/copycode.gif)
1 /// summary 2 /// 快速排序 3 /// /summary 4 /// param name="arry" 要排序的数组 /param 5 /// param name="left" 低位 /param 6 /// param name="right" 高位 /param 7 public static void QuickSort(this int[] arry, int left, int right) 9 //左边索引小于右边,则还未排序完成 10 if (left right) 12 //取中间的元素作为比较基准,小于他的往左边移,大于他的往右边移 13 int middle = arry[(left + right) / 2]; 14 int i = left - 1; 15 int j = right + 1; 16 while (true) 18 //移动下标,左边的往右移动,右边的向左移动 19 while (arry[++i] middle i right); 20 while (arry[--j] middle j 0); 21 if (i = j) 22 break; 23 //交换位置 24 int number = arry[i]; 25 arry[i] = arry[j]; 26 arry[j] = number; 29 QuickSort(arry, left, i - 1); 30 QuickSort(arry, j + 1, right); 32 }
![复制代码](http://common.cnblogs.com/images/copycode.gif)
简单测试
![复制代码](http://common.cnblogs.com/images/copycode.gif)
1 static void Main(string[] args) 3 int[] arry = new int[] { 34,1,221,50,44,58,12,1,1}; 4 //arry.BubbleSort(); 5 arry.QuickSort(0, arry.Length-1 ); 6 for (int i = 0; i arry.Length; i++) 8 Console.Write("\t" + arry[i]); 10 Console.Read(); 11 }
![复制代码](http://common.cnblogs.com/images/copycode.gif)
结果
每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序。
第一趟比较前两个数,然后把第二个数按大小插入到有序表中; 第二趟把第三个数据与前两个数从前向后扫描,把第三个数按大小插入到有序表中;依次进行下去,进行了(n-1)趟扫描以后就完成了整个排序过程。
直接插入排序属于稳定的排序,最坏时间复杂性为O(n^2),空间复杂度为O(1)。
直接插入排序是由两层嵌套循环组成的。外层循环标识并决定待比较的数值。内层循环为待比较数值确定其最终位置。直接插入排序是将待比较的数值与它的前一个数值进行比较,所以外层循环是从第二个数值开始的。当前一数值比待比较数值大的情况下继续循环比较,直到找到比待比较数值小的并将待比较数值置入其后一位置,结束该次循环。
值得注意的是,我们必需用一个存储空间来保存当前待比较的数值,因为当一趟比较完成时,我们要将待比较数值置入比它小的数值的后一位 插入排序类似玩牌时整理手中纸牌的过程。插入排序的基本方法是:每步将一个待排序的记录按其关键字的大小插到前面已经排序的序列中的适当位置,直到全部记录插入完毕为止。
代码实现
![复制代码](http://common.cnblogs.com/images/copycode.gif)
1 /// summary 2 /// 直接插入排序 3 /// /summary 4 /// param name="arry" 要排序的数组 /param 5 public static void InsertSort(this int[] arry) 7 //直接插入排序是将待比较的数值与它的前一个数值进行比较,所以外层循环是从第二个数值开始的 8 for (int i = 1; i arry.Length; i++) 10 //如果当前元素小于其前面的元素 11 if (arry[i] arry[i - 1]) 13 //用一个变量来保存当前待比较的数值,因为当一趟比较完成时,我们要将待比较数值置入比它小的数值的后一位 14 int temp = arry[i]; 15 int j = 0; 16 for (j = i - 1; j = 0 temp arry[j]; j--) 18 arry[j + 1] = arry[j]; 20 arry[j + 1] = temp; 23 }
![复制代码](http://common.cnblogs.com/images/copycode.gif)
测试
![复制代码](http://common.cnblogs.com/images/copycode.gif)
1 static void Main(string[] args) 3 int[] arry = new int[] { 34,1,221,50,44,58,12}; 4 //arry.BubbleSort(); 5 //arry.QuickSort(0, arry.Length-1 ); 6 arry.InsertSort(); 7 for (int i = 0; i arry.Length; i++) 9 Console.Write("\t" + arry[i]); 11 Console.Read(); 12 }
![复制代码](http://common.cnblogs.com/images/copycode.gif)
结果
希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因DL.Shell于1959年提出而得名。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。
但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。
基本思想
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2 d1重复上述的分组和排序,直至所取的增量 =1( … d2 d1),即所有记录放在同一组中进行直接插入排序为止。
该方法实质上是一种分组插入方法
比较相隔较远距离(称为增量)的数,使得数移动时能跨过多个元素,则进行一次比[2] 较就可能消除多个元素交换。D.L.shell于1959年在以他名字命名的排序算法中实现了这一思想。算法先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。
一般的初次取序列的一半为增量,以后每次减半,直到增量为1。
代码实现
![复制代码](http://common.cnblogs.com/images/copycode.gif)
1 /// summary 2 /// 希尔排序 3 /// /summary 4 /// param name="arry" 待排序的数组 /param 5 public static void ShellSort(this int[] arry) 7 int length = arry.Length; 8 for (int h = length / 2; h 0; h = h / 2) 10 //here is insert sort 11 for (int i = h; i length; i++) 13 int temp = arry[i]; 14 if (temp arry[i - h]) 16 for (int j = 0; j j += h) 18 if (temp arry[j]) 20 temp = arry[j]; 21 arry[j] = arry[i]; 22 arry[i] = temp; 28 }
![复制代码](http://common.cnblogs.com/images/copycode.gif)
测试
![复制代码](http://common.cnblogs.com/images/copycode.gif)
1 static void Main(string[] args) 3 int[] arry = new int[] { 34,1,221,50,44,58,12}; 4 //arry.BubbleSort(); 5 //arry.QuickSort(0, arry.Length-1 ); 6 //arry.InsertSort(); 7 arry.ShellSort(); 8 for (int i = 0; i arry.Length; i++) 10 Console.Write("\t" + arry[i]); 12 Console.Read(); 13 }
![复制代码](http://common.cnblogs.com/images/copycode.gif)
结果
设所排序序列的记录个数为n。i取1,2,…,n-1,从所有n-i+1个记录(Ri,Ri+1,…,Rn)中找出排序码最小的记录,与第i个记录交换。执行n-1趟 后就完成了记录序列的排序。
在简单选择排序过程中,所需移动记录的次数比较少。最好情况下,即待排序记录初始状态就已经是正序排列了,则不需要移动记录。
最坏情况下,即待排序记录初始状态是按逆序排列的,则需要移动记录的次数最多为3(n-1)。简单选择排序过程中需要进行的比较次数与初始状态下待排序的记录序列的排列情况无关。当i=1时,需进行n-1次比较;当i=2时,需进行n-2次比较;依次类推,共需要进行的比较次数是(n-1)+(n-2)+…+2+1=n(n-1)/2,即进行比较操作的时间复杂度为O(n^2),进行移动操作的时间复杂度为O(n)。
代码实现
![复制代码](http://common.cnblogs.com/images/copycode.gif)
1 /// summary 2 /// 简单选择排序 3 /// /summary 4 /// param name="arry" 待排序的数组 /param 5 public static void SimpleSelectSort(this int[] arry) 7 int tmp = 0; 8 int t = 0;//最小数标记 9 for (int i = 0; i arry.Length; i++) 11 t = i; 12 for (int j = i + 1; j arry.Length; j++) 14 if (arry[t] arry[j]) 16 t = j; 19 tmp = arry[i]; 20 arry[i] = arry[t]; 21 arry[t] = tmp; 23 }
![复制代码](http://common.cnblogs.com/images/copycode.gif)
测试
![复制代码](http://common.cnblogs.com/images/copycode.gif)
1 static void Main(string[] args) 3 int[] arry = new int[] { 34,1,221,50,44,58,12}; 4 //arry.BubbleSort(); 5 //arry.QuickSort(0, arry.Length-1 ); 6 //arry.InsertSort(); 7 //arry.ShellSort(); 8 arry.SimpleSelectSort(); 9 for (int i = 0; i arry.Length; i++) 11 Console.Write("\t" + arry[i]); 13 Console.Read(); 14 }
![复制代码](http://common.cnblogs.com/images/copycode.gif)
结果
堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] = A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。
代码实现
![复制代码](http://common.cnblogs.com/images/copycode.gif)
1 /// summary 2 /// 堆排序 3 /// /summary 4 /// param name="arry" /param 5 public static void HeapSort(this int[] arry, int top) 7 List int topNode = new List int (); 9 for (int i = arry.Length / 2 - 1; i = 0; i--) 11 HeapAdjust(arry, i, arry.Length); 14 for (int i = arry.Length - 1; i = arry.Length - top; i--) 16 int temp = arry[0]; 17 arry[0] = arry[i]; 18 arry[i] = temp; 19 HeapAdjust(arry, 0, i); 22 /// summary 23 /// 构建堆 24 /// /summary 25 /// param name="arry" /param 26 /// param name="parent" /param 27 /// param name="length" /param 28 private static void HeapAdjust(int[] arry, int parent, int length) 30 int temp = arry[parent]; 32 int child = 2 * parent + 1; 34 while (child length) 36 if (child + 1 length arry[child] arry[child + 1]) child++; 38 if (temp = arry[child]) 39 break; 41 arry[parent] = arry[child]; 43 parent = child; 45 child = 2 * parent + 1; 48 arry[parent] = temp; 49 }
![复制代码](http://common.cnblogs.com/images/copycode.gif)
测试
![复制代码](http://common.cnblogs.com/images/copycode.gif)
1 static void Main(string[] args) 3 int[] arry = new int[] { 34,1,221,50,44,58,12}; 4 //arry.BubbleSort(); 5 //arry.QuickSort(0, arry.Length-1 ); 6 //arry.InsertSort(); 7 //arry.ShellSort(); 8 //arry.SimpleSelectSort(); 9 arry.HeapSort(arry.Length); 10 for (int i = 0; i arry.Length; i++) 12 Console.Write("\t" + arry[i]); 14 Console.Read(); 15 }
![复制代码](http://common.cnblogs.com/images/copycode.gif)
结果
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归并过程为:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。
归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。
如 设有数列{6,202,100,301,38,8,1}
初始状态:6,202,100,301,38,8,1
第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;
第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;
第三次归并后:{1,6,8,38,100,202,301},比较次数:4;
总的比较次数为:3+4+4=11,;
逆序数为14;
归并操作的工作原理如下:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
代码实现
![复制代码](http://common.cnblogs.com/images/copycode.gif)
1 /// summary 2 /// 归并排序 3 /// /summary 4 /// param name="arry" /param 5 /// param name="first" /param 6 /// param name="last" /param 7 public static void MergeSort(this int[] arry, int first, int last) 9 if (first + 1 last) 11 int mid = (first + last) / 2; 12 MergeSort(arry, first, mid); 13 MergeSort(arry, mid, last); 14 Merger(arry, first, mid, last); 17 /// summary 18 /// 归并 19 /// /summary 20 /// param name="arry" /param 21 /// param name="first" /param 22 /// param name="mid" /param 23 /// param name="last" /param 24 private static void Merger(int[] arry, int first, int mid, int last) 26 Queue int tempV = new Queue int (); 27 int indexA, indexB; 28 //设置indexA,并扫描subArray1 [first,mid] 29 //设置indexB,并扫描subArray2 [mid,last] 30 indexA = first; 31 indexB = mid; 32 //在没有比较完两个子标的情况下,比较 v[indexA]和v[indexB] 33 //将其中小的放到临时变量tempV中 34 while (indexA mid indexB last) 36 if (arry[indexA] arry[indexB]) 38 tempV.Enqueue(arry[indexA]); 39 indexA++; 41 else 43 tempV.Enqueue(arry[indexB]); 44 indexB++; 47 //复制没有比较完子表中的元素 48 while (indexA mid) 50 tempV.Enqueue(arry[indexA]); 51 indexA++; 53 while (indexB last) 55 tempV.Enqueue(arry[indexB]); 56 indexB++; 58 int index = 0; 59 while (tempV.Count 0) 61 arry[first + index] = tempV.Dequeue(); 62 index++; 64 }
![复制代码](http://common.cnblogs.com/images/copycode.gif)
测试
![复制代码](http://common.cnblogs.com/images/copycode.gif)
1 static void Main(string[] args) 3 int[] arry = new int[] { 34,1,221,50,44,58,12}; 4 //arry.BubbleSort(); 5 //arry.QuickSort(0, arry.Length-1 ); 6 //arry.InsertSort(); 7 //arry.ShellSort(); 8 //arry.SimpleSelectSort(); 9 //arry.HeapSort(arry.Length); 10 arry.MergeSort(0, arry.Length); 11 for (int i = 0; i arry.Length; i++) 13 Console.Write("\t" + arry[i]); 15 Console.Read(); 16 }
![复制代码](http://common.cnblogs.com/images/copycode.gif)
结果
基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。
代码实现
![复制代码](http://common.cnblogs.com/images/copycode.gif)
1 /// summary 2 /// 基数排序 3 /// 约定:待排数字中没有0,如果某桶内数字为0则表示该桶未被使用,输出时跳过即可 4 /// /summary 5 /// param name="arry" 待排数组 /param 6 /// param name="array_x" 桶数组第一维长度 /param 7 /// param name="array_y" 桶数组第二维长度 /param 8 public static void RadixSort(this int[] arry, int array_x = 10, int array_y = 100) 10 /* 最大数字不超过999999999...(array_x个9) */ 11 for (int i = 0; i array_x; i++) 13 int[,] bucket = new int[array_x, array_y]; 14 foreach (var item in arry) 16 int temp = (item / (int)Math.Pow(10, i)) % 10; 17 for (int l = 0; l array_y; l++) 19 if (bucket[temp, l] == 0) 21 bucket[temp, l] = item; 22 break; 26 for (int o = 0, x = 0; x array_x; x++) 28 for (int y = 0; y array_y; y++) 30 if (bucket[x, y] == 0) continue; 31 arry[o++] = bucket[x, y]; 36 }
![复制代码](http://common.cnblogs.com/images/copycode.gif)
测试
![复制代码](http://common.cnblogs.com/images/copycode.gif)
1 static void Main(string[] args) 3 int[] arry = new int[] { 34,1,221,50,44,58,12}; 4 //arry.BubbleSort(); 5 //arry.QuickSort(0, arry.Length-1 ); 6 //arry.InsertSort(); 7 //arry.ShellSort(); 8 //arry.SimpleSelectSort(); 9 //arry.HeapSort(arry.Length); 10 //arry.MergeSort(0, arry.Length); 11 arry.RadixSort(); 12 for (int i = 0; i arry.Length; i++) 14 Console.Write("\t" + arry[i]); 16 Console.Read(); 17 }
![复制代码](http://common.cnblogs.com/images/copycode.gif)
结果
整数数组各种排序算法扩展类
![](http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
![复制代码](http://common.cnblogs.com/images/copycode.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 7 namespace Wolfy.Sort 9 /// summary 10 /// 排序辅助类 11 /// /summary 12 public static class SortExtention 13 { 14 /// summary 15 /// 冒泡排序 16 /// /summary 17 /// param name="arry" 要排序的整数数组 /param 18 public static void BubbleSort(this int[] arry) 19 { 20 for (int i = 0; i arry.Length-1; i++) 21 { 22 for (int j = 0; j arry.Length - 1 - i; j++) 23 { 24 //比较相邻的两个元素,如果前面的比后面的大,则交换位置 25 if (arry[j] arry[j + 1]) 26 { 27 int temp = arry[j + 1]; 28 arry[j + 1] = arry[j]; 29 arry[j] = temp; 30 } 31 } 32 } 33 } 34 /// summary 35 /// 快速排序 36 /// /summary 37 /// param name="arry" 要排序的数组 /param 38 /// param name="left" 低位 /param 39 /// param name="right" 高位 /param 40 public static void QuickSort(this int[] arry, int left, int right) 41 { 42 //左边索引小于右边,则还未排序完成 43 if (left right) 44 { 45 //取中间的元素作为比较基准,小于他的往左边移,大于他的往右边移 46 int middle = arry[(left + right) / 2]; 47 int i = left - 1; 48 int j = right + 1; 49 while (true) 50 { 51 //移动下标,左边的往右移动,右边的向左移动 52 while (arry[++i] middle i right) ; 53 while (arry[--j] middle j 0) ; 54 if (i = j) 55 break; 56 //交换位置 57 int number = arry[i]; 58 arry[i] = arry[j]; 59 arry[j] = number; 61 } 62 QuickSort(arry, left, i - 1); 63 QuickSort(arry, j + 1, right); 64 } 65 } 66 /// summary 67 /// 直接插入排序 68 /// /summary 69 /// param name="arry" 要排序的数组 /param 70 public static void InsertSort(this int[] arry) 71 { 72 //直接插入排序是将待比较的数值与它的前一个数值进行比较,所以外层循环是从第二个数值开始的 73 for (int i = 1; i arry.Length; i++) 74 { 75 //如果当前元素小于其前面的元素 76 if (arry[i] arry[i - 1]) 77 { 78 //用一个变量来保存当前待比较的数值,因为当一趟比较完成时,我们要将待比较数值置入比它小的数值的后一位 79 int temp = arry[i]; 80 int j = 0; 81 for (j = i - 1; j = 0 temp arry[j]; j--) 82 { 83 arry[j + 1] = arry[j]; 84 } 85 arry[j + 1] = temp; 86 } 87 } 88 } 89 /// summary 90 /// 希尔排序 91 /// /summary 92 /// param name="arry" 待排序的数组 /param 93 public static void ShellSort(this int[] arry) 94 { 95 int length = arry.Length; 96 for (int h = length / 2; h 0; h = h / 2) 97 { 98 //here is insert sort 99 for (int i = h; i length; i++) 100 { 101 int temp = arry[i]; 102 if (temp arry[i - h]) 103 { 104 for (int j = 0; j j += h) 105 { 106 if (temp arry[j]) 107 { 108 temp = arry[j]; 109 arry[j] = arry[i]; 110 arry[i] = temp; 111 } 112 } 113 } 114 } 115 } 116 } 117 /// summary 118 /// 简单选择排序 119 /// /summary 120 /// param name="arry" 待排序的数组 /param 121 public static void SimpleSelectSort(this int[] arry) 122 { 123 int tmp = 0; 124 int t = 0;//最小数标记 125 for (int i = 0; i arry.Length; i++) 126 { 127 t = i; 128 for (int j = i + 1; j arry.Length; j++) 129 { 130 if (arry[t] arry[j]) 131 { 132 t = j; 133 } 134 } 135 tmp = arry[i]; 136 arry[i] = arry[t]; 137 arry[t] = tmp; 138 } 139 } 140 /// summary 141 /// 堆排序 142 /// /summary 143 /// param name="arry" /param 144 public static void HeapSort(this int[] arry, int top) 145 { 146 List int topNode = new List int (); 148 for (int i = arry.Length / 2 - 1; i = 0; i--) 149 { 150 HeapAdjust(arry, i, arry.Length); 151 } 153 for (int i = arry.Length - 1; i = arry.Length - top; i--) 154 { 155 int temp = arry[0]; 156 arry[0] = arry[i]; 157 arry[i] = temp; 158 HeapAdjust(arry, 0, i); 159 } 160 } 161 /// summary 162 /// 构建堆 163 /// /summary 164 /// param name="arry" /param 165 /// param name="parent" /param 166 /// param name="length" /param 167 private static void HeapAdjust(int[] arry, int parent, int length) 168 { 169 int temp = arry[parent]; 171 int child = 2 * parent + 1; 173 while (child length) 174 { 175 if (child + 1 length arry[child] arry[child + 1]) child++; 177 if (temp = arry[child]) 178 break; 180 arry[parent] = arry[child]; 182 parent = child; 184 child = 2 * parent + 1; 185 } 187 arry[parent] = temp; 188 } 189 /// summary 190 /// 归并排序 191 /// /summary 192 /// param name="arry" /param 193 /// param name="first" /param 194 /// param name="last" /param 195 public static void MergeSort(this int[] arry, int first, int last) 196 { 197 if (first + 1 last) 198 { 199 int mid = (first + last) / 2; 200 MergeSort(arry, first, mid); 201 MergeSort(arry, mid, last); 202 Merger(arry, first, mid, last); 203 } 204 } 205 /// summary 206 /// 归并 207 /// /summary 208 /// param name="arry" /param 209 /// param name="first" /param 210 /// param name="mid" /param 211 /// param name="last" /param 212 private static void Merger(int[] arry, int first, int mid, int last) 213 { 214 Queue int tempV = new Queue int (); 215 int indexA, indexB; 216 //设置indexA,并扫描subArray1 [first,mid] 217 //设置indexB,并扫描subArray2 [mid,last] 218 indexA = first; 219 indexB = mid; 220 //在没有比较完两个子标的情况下,比较 v[indexA]和v[indexB] 221 //将其中小的放到临时变量tempV中 222 while (indexA mid indexB last) 223 { 224 if (arry[indexA] arry[indexB]) 225 { 226 tempV.Enqueue(arry[indexA]); 227 indexA++; 228 } 229 else 230 { 231 tempV.Enqueue(arry[indexB]); 232 indexB++; 233 } 234 } 235 //复制没有比较完子表中的元素 236 while (indexA mid) 237 { 238 tempV.Enqueue(arry[indexA]); 239 indexA++; 240 } 241 while (indexB last) 242 { 243 tempV.Enqueue(arry[indexB]); 244 indexB++; 245 } 246 int index = 0; 247 while (tempV.Count 0) 248 { 249 arry[first + index] = tempV.Dequeue(); 250 index++; 251 } 252 } 254 /// summary 255 /// 基数排序 256 /// 约定:待排数字中没有0,如果某桶内数字为0则表示该桶未被使用,输出时跳过即可 257 /// /summary 258 /// param name="arry" 待排数组 /param 259 /// param name="array_x" 桶数组第一维长度 /param 260 /// param name="array_y" 桶数组第二维长度 /param 261 public static void RadixSort(this int[] arry, int array_x = 10, int array_y = 100) 262 { 263 /* 最大数字不超过999999999...(array_x个9) */ 264 for (int i = 0; i array_x; i++) 265 { 266 int[,] bucket = new int[array_x, array_y]; 267 foreach (var item in arry) 268 { 269 int temp = (item / (int)Math.Pow(10, i)) % 10; 270 for (int l = 0; l array_y; l++) 271 { 272 if (bucket[temp, l] == 0) 273 { 274 bucket[temp, l] = item; 275 break; 276 } 277 } 278 } 279 for (int o = 0, x = 0; x array_x; x++) 280 { 281 for (int y = 0; y array_y; y++) 282 { 283 if (bucket[x, y] == 0) continue; 284 arry[o++] = bucket[x, y]; 285 } 286 } 287 } 289 } 291 } 293 }
![复制代码](http://common.cnblogs.com/images/copycode.gif)
博客版权: 本文以学习、研究和分享为主,欢迎转载,但必须在文章页面明显位置给出原文连接。
如果文中有不妥或者错误的地方还望高手的你指出,以免误人子弟。如果觉得本文对你有所帮助不如【推荐】一下!如果你有更好的建议,不如留言一起讨论,共同进步!
再次感谢您耐心的读完本篇文章。http://www.cnblogs.com/wolf-sun/p/4312475.html
[ICPC 46th Shanghai] Life is a Game 克鲁斯卡尔重构树 题目大意: 给定n个点,m条边,有q个询问 每个点有一个(能量值)点权,每条边有一个边权 m条边描述为u v w表示有一条u与v相连的边权为w的通路 在每一次询问中,给定一个点x和现有的能量值k,每次只能是在当前能量值大于边权的时候到达另一个点,并获取这个点的能量值(路可以重复走),问最终能够获得多大的能量值
ACM-ICPC 常用算法刷题网站整理 转载From http://blog.csdn.net/bat67/article/details/72765485 以及http://blog.csdn.net/pinellina/article/details/46843165 感谢原作者。
2018年美国大学生数学建模竞赛(MCM/ICM) F题解题思路 任务一:开发价格点,建立综合定价模型。 其中 a 代表开发价格点系数,代表个人财产评估。K 为 PI 交易系数 以这个进行评估,将个人划分为具有合理相似性的子组: 当 a 等于 0-30 时,子组为:k=1.35 当 a 等于 30-60 时,子组为:k=2.64 当 a 等于 60-90 时,子组为:k=3.78 价格点评估方案图如下: 可以得出个人特点为: 1)开发价格 PI 和 PP 的关系呈正相关。
2018年美国大学生数学建模竞赛(MCM/ICM) E题解题思路 任务一就是让大家去做个基本的评价,是典型的评价类问题,所以应该按照 指标+方法的步骤去做,首先就是寻找国家脆弱性的相关概念,然后选择影响国 家脆弱性的指标,如气候变化,经济发展,政治状况等等,再就是构建评价模型 去做即可。
相关文章
- 【经典算法】快速排序算法
- 面试-排序算法时间复杂度与空间复杂度
- 经典算法题每日演练——第二十题 三元组
- 内部排序算法:归并排序
- Java实现 蓝桥杯 算法训练 第五次作业:字符串排序
- Java实现 蓝桥杯 算法训练 第五次作业:字符串排序
- Java实现 蓝桥杯 算法训练 字符串长度(IO无敌)
- Java实现 蓝桥杯VIP 算法训练 sign函数
- Java实现 蓝桥杯VIP 算法训练 幂方分解
- Java实现 蓝桥杯VIP 算法训练 阶乘末尾
- Java实现 蓝桥杯 算法训练 最大最小公倍数
- Java实现 蓝桥杯 算法训练 排序
- Java实现蓝桥杯算法提高P0102
- 经典排序算法 数据结构
- 程序兵法:Java String 源码的排序算法(一)
- 数据挖掘算法R语言实现之决策树
- 浅谈压缩感知(二十八):压缩感知重构算法之广义正交匹配追踪(gOMP)
- 重新整理数据结构与算法(c#)—— 二叉树排序树补删除节点[二十二]
- Atitit.常用的gc算法
- ML之prophet:利用prophet算法对维基百科页面的日志每日页面浏览量实现回归预测(时间序列的趋势/周季节性趋势/年季节性趋势)案例
- 第十四届蓝桥杯集训——练习解题阶段(无序阶段)-分治算法
- Romberg算法(C语言实现)
- 智能优化算法:蝙蝠算法-附代码
- 基于三重动态调整的花授粉算法-附代码
- 强化狼群等级制度的灰狼优化算法-附代码
- 677. 键值映射-字符树算法应用
- 1338. 数组大小减半-排序加贪心算法
- 八排序算法汇总
- find_if算法
- 数据结构与算法之快速排序
- DSA 经典数据结构与算法 学习心得和知识总结(一) |排序 十大排序算法汇总(C++)