首页 > 代码库 > 软考笔记第六天之各排序算法的实现
软考笔记第六天之各排序算法的实现
对于前面的排序算法,用c#来实现
直接插入排序:
每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序。
第一趟比较前两个数,然后把第二个数按大小插入到有序表中; 第二趟把第三个数据与前两个数从前向后扫描,把第三个数按大小插入到有序表中;依次进行下去,进行了(n-1)趟扫描以后就完成了整个排序过程。
直接插入排序属于稳定的排序,最坏时间复杂性为O(n^2),空间复杂度为O(1)。
直接插入排序是由两层嵌套循环组成的。外层循环标识并决定待比较的数值。内层循环为待比较数值确定其最终位置。直接插入排序是将待比较的数值与它的前一个数值进行比较,所以外层循环是从第二个数值开始的。当前一数值比待比较数值大的情况下继续循环比较,直到找到比待比较数值小的并将待比较数值置入其后一位置,结束该次循环。
值得注意的是,我们必需用一个存储空间来保存当前待比较的数值,因为当一趟比较完成时,我们要将待比较数值置入比它小的数值的后一位 插入排序类似玩牌时整理手中纸牌的过程。插入排序的基本方法是:每步将一个待排序的记录按其关键字的大小插到前面已经排序的序列中的适当位置,直到全部记录插入完毕为止。
代码实现
1 static void Main(string[] args) 2 { 3 int[] arry = new int[] { 3, 5, 7, 4, 1, 0, -2, -1, 7, 3 }; 4 arry = InsertSort(arry); 5 foreach (var item in arry) 6 { 7 Console.Write("\t" + item); 8 } 9 Console.ReadKey(); 10 } 11 public static int[] InsertSort(int[] arry) 12 { 13 for (int i = 1; i < arry.Length; i++) 14 { 15 //需要插入 16 if (arry[i] < arry[i - 1]) 17 { 18 int temp = arry[i]; 19 int j; 20 //循环比较i-1次,满足条件,说明要被交换 21 for (j = i - 1; j >= 0 && temp < arry[j]; j--) 22 { 23 // 24 arry[j + 1] = arry[j]; 25 } 26 //由于最后一次j又--了,所有这里加1 27 arry[j + 1] = temp; 28 //第二种交换方法,从头开始遍历,如果有值大于要插入的值,那么两个值进行交换,并将temp重新赋值为遍历到的值 29 //for (j = 0; j < i; j++) 30 //{ 31 // if (temp < arry[j]) 32 // { 33 // 将temp重新赋值为遍历到的值 34 // temp = arry[j]; 35 // arry[j] = arry[i]; 36 // arry[i] = temp; 37 // } 38 //} 39 } 40 } 41 return arry; 42 }
希尔排序:
希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因DL.Shell于1959年提出而得名。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。
但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。
基本思想
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量 =1( < …<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
该方法实质上是一种分组插入方法
比较相隔较远距离(称为增量)的数,使得数移动时能跨过多个元素,则进行一次比[2] 较就可能消除多个元素交换。D.L.shell于1959年在以他名字命名的排序算法中实现了这一思想。算法先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。
一般的初次取序列的一半为增量,以后每次减半,直到增量为1。
代码实现
1 static void Main(string[] args) 2 { 3 int[] arry = new int[] { 57, 68, 59, 52, 72, 28, 96, 33, 24, 19, 19, 68 ,-12}; 4 arry = ShellSort(arry); 5 foreach (var item in arry) 6 { 7 Console.Write("\t" + item); 8 } 9 Console.ReadKey(); 10 } 11 12 13 public static int[] ShellSort(int[] arry) 14 { 15 int length = arry.Length; 16 for (int d = (int)Math.Ceiling(length/2.0); d > 0; d=(int)Math.Ceiling(d/2.0)) 17 { 18 //直接插入法 19 for (int i = d; i < arry.Length; i++) 20 { 21 int temp=arry[i]; 22 //需要插入。改变位置 23 if (temp < arry[i - d]) 24 { 25 for (int j = i-d; j < i; j += d) 26 { 27 if (temp < arry[j]) 28 { 29 temp = arry[j]; 30 arry[j] = arry[i]; 31 arry[i] = temp; 32 } 33 } 34 } 35 } 36 if (d == 1) 37 break; 38 } 39 return arry; 40 }
直接选择排序:
设所排序序列的记录个数为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)。
代码实现
1 static void Main(string[] args) 2 { 3 int[] arry = new int[] { 57, 68, 59, 52, 72, 28, 96, 33, 24, 19, 68, -12 }; 4 arry = DirectSelectSort(arry); 5 foreach (var item in arry) 6 { 7 Console.Write("\t" + item); 8 } 9 Console.ReadKey(); 10 } 11 12 public static int[] DirectSelectSort(int[] arry) 13 { 14 //最小数的下标 15 int minKey; 16 int temp; 17 for (int i = 0; i < arry.Length; i++) 18 { 19 minKey = i; 20 for (int j = i+1; j < arry.Length; j++) 21 { 22 if (arry[minKey] > arry[j]) 23 minKey = j; 24 } 25 temp = arry[minKey]; 26 arry[minKey] = arry[i]; 27 arry[i] = temp; 28 } 29 return arry; 30 }
冒泡排序:
已知一组无序数据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次交换。
代码实现
1 static void Main(string[] args) 2 { 3 int[] arry = new int[] { 1,3,4,2,6,-2}; 4 BubbleSort(ref arry); 5 foreach (var item in arry) 6 { 7 Console.Write("\t"+item); 8 } 9 Console.ReadKey(); 10 } 11 public static void BubbleSort(ref int[] arry) 12 { 13 for (int i = 0; i < arry.Length; i++) 14 { 15 for (int j = 0; j < arry.Length-1-i; j++) 16 { 17 if (arry[j] > arry[j + 1]) 18 { 19 int temp = arry[j + 1]; 20 arry[j + 1] = arry[j]; 21 arry[j] = temp; 22 } 23 } 24 } 25 }
快速排序:
设要排序的数组是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-完成的时候,此时令循环结束)。
代码实现
1 static void Main(string[] args) 2 { 3 int[] arry = new int[] { 1,3,4,2,6,-2,7,1}; 4 arry = QuickSort(arry,0,arry.Length-1); 5 foreach (var item in arry) 6 { 7 Console.Write("\t"+item); 8 } 9 Console.ReadKey(); 10 } 11 /// <summary> 12 /// 快速排序算法 13 /// </summary> 14 /// <param name="arry"></param> 15 /// <param name="left">低位</param> 16 /// <param name="right">高位</param> 17 public static int[] QuickSort(int[] arry, int left, int right) 18 { 19 if (left < right) 20 { 21 //选基准 22 int middle = arry[(left + right) / 2]; 23 int i = left - 1; 24 int j = right + 1; 25 while (true) 26 { 27 //从左往右直到找到一个值大于基准 28 while (arry[++i] < middle && i < right) ; 29 //从右往左直到找到一个值小于基准 30 while (arry[--j] > middle && j > left) ; 31 if (i >= j) 32 break; 33 //交换 34 int temp = arry[i]; 35 arry[i] = arry[j]; 36 arry[j] = temp; 37 } 38 //递归 39 QuickSort(arry, left, i - 1); 40 QuickSort(arry,j+1,right); 41 } 42 return arry; 43 }
堆排序:
堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。
代码实现
1 static void Main(string[] args) 2 { 3 int[] arry = new int[] { 34,12,32,2,54,6,23,-4,2,0,7,-9}; 4 arry=HeapSort(arry,arry.Length); 5 foreach (var item in arry) 6 { 7 Console.Write("\t"+item); 8 } 9 Console.ReadKey(); 10 } 11 12 public static int[] HeapSort(int[] arry, int top) 13 { 14 List<int> topNode = new List<int>(); 15 16 for (int i = arry.Length / 2 - 1; i >= 0; i--) 17 { 18 HeapAdjust(arry, i, arry.Length); 19 } 20 21 for (int i = arry.Length - 1; i >= arry.Length - top; i--) 22 { 23 int temp = arry[0]; 24 arry[0] = arry[i]; 25 arry[i] = temp; 26 HeapAdjust(arry, 0, i); 27 } 28 return arry; 29 } 30 /// <summary> 31 /// 构建堆 32 /// </summary> 33 /// <param name="arry"></param> 34 /// <param name="parent"></param> 35 /// <param name="length"></param> 36 private static void HeapAdjust(int[] arry, int parent, int length) 37 { 38 int temp = arry[parent]; 39 40 int child = 2 * parent + 1; 41 42 while (child < length) 43 { 44 if (child + 1 < length && arry[child] < arry[child + 1]) child++; 45 46 if (temp >= arry[child]) 47 break; 48 49 arry[parent] = arry[child]; 50 51 parent = child; 52 53 child = 2 * parent + 1; 54 } 55 56 arry[parent] = temp; 57 }
堆排序算法的实现是看别人博客的内容。
另外的归并排序和基数排序考的不多,就不写了。
软考笔记第六天之各排序算法的实现