7种排序算法
来源:互联网 发布:cms绑定域名 编辑:程序博客网 时间:2024/06/02 00:50
说是复习,与其说是学习更加的准确,毕竟大部分的思想都是忘记了,而且书有弄丢了,所以在网上东拼西凑的找了一下资料,来学习排序算法,
毕竟这个是非常基础而且重要的东西,大部分是使用C#来实现的,有用List的,也有用IList的,总之主要的目的是想了解这些算法背后的编程思想,
这个是非常重要的,毕竟 语言知识工具,算法才是程序的灵魂
1 选择排序:
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法(比如序列[5, 5, 3]第一次就将第一个[5]与[3]交换,导致第一个5挪动到第二个5后面)。
思想:
n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果:
①初始状态:无序区为R[1..n],有序区为空。
②第1趟排序
在无序区R[1..n]中选出关键字最小的记录R[k],将它与无序区的第1个记录R[1]交换,使R[1..1]和R[2..n]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。
③第i趟排序
第i趟排序开始时,当前有序区和无序区分别为R[1..i-1]和R(i..n)。该趟排序从当前无序区中选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1..i]和R分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。
通俗的解释
对比数组中前一个元素跟后一个元素的大小,如果后面的元素比前面的元素小则用一个变量k来记住他的位置,接着第二次比较,前面“后一个元素”现变成了“前一个元素”,继续跟他的“后一个元素”进行比较如果后面的元素比他要小则用变量k记住它在数组中的位置(下标),等到循环结束的时候,我们应该找到了最小的那个数的下标了,然后进行判断,如果这个元素的下标不是第一个元素的下标,就让第一个元素跟他交换一下值,这样就找到整个数组中最小的数了。然后找到数组中第二小的数,让他跟数组中第二个元素交换一下值,以此类推。
/// <summary> /// 选择排序 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="arr"></param> static void selection_sort<T>(T[] arr) where T : System.IComparable<T> { int i, j, min, len = arr.Length; T temp; for (i = 0; i < len - 1; i++) { min = i; for (j = i + 1; j < len; j++) { if (arr[min].CompareTo(arr[j]) > 0) { min = j; } } temp = arr[min]; arr[min] = arr[i]; arr[i] = temp; } }
二分法插入排序是在插入第i个元素时,对前面的0~i-1元素进行折半,先跟他们中间的那个元素比,如果小,则对前半再进行折半,否则对后半进行折半,直到left>right,然后再把第i个元素前1位与目标位置之间的所有元素后移,再把第i个元素放在目标位置上。
/// <summary> /// 二分法插入排序 /// </summary> /// <param name="data"></param> static void InsertSort(int[] data) { int i, j; int count = data.Length; for (i = 1; i < count; i++) { int t = data[i]; for (j = i - 1; j > 0 && data[i] > t; j--) { data[j + 1] = data[j]; } data[j + 1] = t; } } public static void InsertSortImprovedWithBinarySearch(IList<int> data) { int temp; int tempIndex; for (int i = 1; i < data.Count; i++) { temp = data[i]; tempIndex = BinarySearchForInsertSort(data, 0, i, i); for (int j = i - 1; j >= tempIndex; j--) { data[j + 1] = data[j]; } data[tempIndex] = temp; } } public static int BinarySearchForInsertSort(IList<int> data, int low, int high, int key) { if (low >= data.Count - 1) return data.Count - 1; if (high <= 0) return 0; int mid = (low + high) / 2; if (mid == key) return mid; if (data[key] > data[mid]) { if (data[key] < data[mid + 1]) return mid + 1; return BinarySearchForInsertSort(data, mid + 1, high, key); } else { if (mid - 1 < 0) return 0; if (data[key] > data[mid - 1]) return mid; return BinarySearchForInsertSort(data, low, mid - 1, key); } }
3。快速排序:
设要排序的数组是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-完成的时候,此时令循环结束)。
private static void QuicklySort(int[] numbers, int left, int right) { if (left < right) { int middle = numbers[(left + right) / 2]; int i = left - 1; int j = right + 1; while (true) { while (numbers[++i] < middle) ; while (numbers[--j] > middle) ; if (i > j) break; } Swap(numbers, left, i - 1); Swap(numbers, j + 1, right); } } private static void Swap(int[] numbers, int i, int j) { int number = numbers[i]; numbers[i] = numbers[j]; numbers[j] = number; }
4。归并排序:
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(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]。
归并操作的工作原理如下:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
public static List<int> Sort(List<int> list) { if (list.Count <= 1) return list; int mid = list.Count / 2; List<int> left = new List<int>(); List<int> right = new List<int>(); for (int i = 0; i < mid; i++) { left.Add(list[i]); } for (int i = mid; i < list.Count; i++) { right.Add(list[i]); } left = Sort(left); right = Sort(right); return Merge(left, right); } private static List<int> Merge(List<int> left, List<int> right) { List<int> temp = new List<int>(); while (left.Count > 0 && right.Count > 0) { if (left[0] < right[0]) { temp.Add(left[0]); left.RemoveAt(0); } else { temp.Add(right[0]); right.RemoveAt(0); } if (left.Count > 0) { for (int i = 0; i < left.Count; i++) { temp.Add(left[i]); } } if (right.Count > 0) { for (int i = 0; i < right.Count; i++) { temp.Add(right[i]); } } } }
5.堆排序:
堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。
private static void Swap(IList<int> numbers, int i, int j) { int number = numbers[i]; numbers[i] = numbers[j]; numbers[j] = number; } public static void HeapSort(IList<int> data) { BuildMaxHeapify(data); int j = data.Count; for (int i = 0; i < j; ) { Swap(data, i, --j); if (j - 2 < 0) { break; } int k = 0; while (true) { if (k > (j - 2) / 2) break; else { int temp = k; k = ReSortMaxBranch(data, k, 2 * k + 1, 2 * k + 2, j - 1); if (temp == k) break; } } } } public static void BuildMaxHeapify(IList<int> data) { for (int i = data.Count / 2 - 1; i >= 0; i--) { int temp = i; temp = ReSortMaxBranch(data, i, 2 * i + 1, 2 * i + 2, data.Count - 1); if (temp != i) { int k = i; while (k != temp && temp <= data.Count / 2 - 1) { k = temp; temp = ReSortMaxBranch(data, temp, 2 * temp + 1, 2 * temp + 2, data.Count); } } } } public static int ReSortMaxBranch(IList<int> data, int maxIndex, int left, int right, int lastIndex) { int temp; if (right > lastIndex) temp = left; else { if (data[left] > data[right]) { temp = left; } else { temp = right; } } if (data[maxIndex] < data[temp]) { Swap(data, maxIndex, temp); } else { temp = maxIndex; } return temp; }
6. 希尔排序:
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量 =1( < …<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
该方法实质上是一种分组插入方法
比较相隔较远距离(称为增量)的数,使得数移动时能跨过多个元素,则进行一次比[2] 较就可能消除多个元素交换。D.L.shell于1959年在以他名字命名的排序算法中实现了这一思想。算法先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。
一般的初次取序列的一半为增量,以后每次减半,直到增量为1。
给定实例的shell排序的排序过程
假设待排序文件有10个记录,其关键字分别是:
49,38,65,97,76,13,27,49,55,04。
增量序列的取值依次为:
5,2,1[3]
public static void ShellSort(IList<int> data) { int temp; for (int gap = data.Count / 2; gap > 0; gap /= 2) { for (int i = dap; i < data.Count; i++) { temp = data[i]; for (int j = i - gap; j >= 0; j -= gap) { if (data[j] > temp) { data[j + gap] = data[j]; if (j == 0) { data[j] = temp; break; } } else { data[j + gap] = temp; break; } } } } }
7.桶排序:
public static void BucketSortOnlyUnitDigit(IList<int> data) { int[] indexCounter = new int[10]; for (int i = 0; i < data.Count; i++) { indexCounter[data[i]]++; } int[] indexBegin = new int[10]; for (int i = 1; i < 10; i++) { indexBegin[i] = indexBegin[i - 1] + indexBegin[i - 1]; } IList<int> tempList = NewInstance(data, data.Count); for (int i = 0; i < data.Count; i++) { int number = data[i]; tempList[indexBegin[number]++] = data[i]; } }
0 0
- 7种排序算法
- 排序算法-7种常见算法
- 7种常用排序算法
- 排序算法(7)----桶排序
- 几种排序算法(冒泡排序算法,选择排序算法,快速排序算法,插入排序)
- C++排序算法(7种)
- 7种常用排序算法总结:
- 7种排序算法(java实现)
- 7种常用的排序算法
- 视觉直观感受7种排序算法
- 7种常用排序算法总结
- 7 种常用的排序算法解析
- C++: 7种排序 算法原理展示
- 7种排序算法实现及分析
- 7种经典排序算法的图解
- 数据结构中的7种排序算法
- 数据结构中的7种排序算法
- 数据结构中的7种排序算法
- (转)Android 软键盘弹出时布局内指定内容上移实现及问题解决
- git学习-使用ssh
- 2.centos下搭建lamp环境
- 最长公共子串
- 使程序在后台执行,并将日志输出至文件
- 7种排序算法
- 【POJ 2182 Lost Cows】+ 线段树
- HDU 2504
- Hibernate5.2.4环境搭建
- 平衡二叉树
- Tips
- java 内存泄漏
- Toolbar的使用
- git学习-上传项目