常用的排序算法总结
来源:互联网 发布:python 接收上传图片 编辑:程序博客网 时间:2024/06/05 14:34
插入排序的基本思想是每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子文件中的适当位置,直到全部记录插入完成为止。常见的插入排序有插入排序(Insertion Sort),希尔排序(Shell Sort),二叉查找树排序(Tree Sort),图书馆排序(Library Sort),Patience排序(Patience Sort)。下面介绍前两种:
- 直接插入排序
最差时间复杂度:O(n^2) 最优时间复杂度:O(n) 平均时间复杂度:O(n^2) 稳定性:稳定
直接插入排序(Insertion Sort),是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对未排序的数据,在已排序序列中从后向前扫描,找到相应位置并插入。
插入排序算法的一般步骤:
1.从第一个元素开始,该元素可以认为已被排序;
2.取出下一个元素,在已经排序的元素序列中从后向前扫描;
3.如果该元素(已排序)大于新元素,将该元素移到下一个位置;
4.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
5.将新元素插入到该位置后,重复2~5
- void InsertionSort(int *a, int len)
- {
- for (int j=1; j<len; j++)
- {
- int key = a[j];
- int i = j-1;
- while (i>=0 && a[i]>key)
- {
- a[i+1] = a[i];
- i--;
- }
- a[i+1] = key;
- }
- }
- 希尔排序
平均时间复杂度:O(nlogn) 稳定性:不稳定
希尔排序(Shell Sort),也称为递减增量排序算法,是插入排序的一种高速而稳定的改进版本。希尔排序是基于插入排序的以下两点性质而提出改进方法的:1.插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;2.但插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位。
希尔排序的一般步骤为:
1.先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中,在各组内进行直接插人排序。
2.取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
步长的选择是希尔排序的重要部分。只要最终步长为1任何步长串行都可以工作。算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。
- void ShellSort(int *a, int len)
- {
- int h = 1;
- while( h<len )
- h = 3*h + 1;
- while( h>0 )
- {
- for (int j=h; j<len; j++)
- {
- int key = a[j];
- int i = j-h;
- while( i>=0 && a[i]>key )
- {
- a[i+h] = a[i];
- i = i-h;
- }
- a[i+h] = key;
- }
- h = h/3;
- }
- }
- 快速排序
最差时间复杂度 O(n^2) 最好时间复杂度 O(nlogn) 平均时间复杂度O(nlogn) 不稳定
由C. A. R. Hoare在1962年提出,该算法是目前实践中使用最频繁,实用高效的最好排序算法,
快速排序算法是采用分治思想的算法,算法分三个步骤
- 从数组中抽出一个元素作为基数v(我们称之为划界元素),一般是取第一个、最后一个元素或中间的元素
- 将剩余的元素中小于v的移动到v的左边,将大于v元素移动到v的右边
- 对左右两个分区重复以上步骤直到所有元素都是有排序好
int partition(int a[], int p, int r) {
int key = a[r];//取最后一个
int i = p - 1;
for (int j = p; j < r; j++)
{
if (a[j] <= key)
{
i++;
//i一直代表小于key元素的最后一个索引,当发现有比key小的a[j]时候,i+1 后交换
exchange(&a[i], &a[j]);
}
}
exchange(&a[i + 1], &a[r]);//将key切换到中间来,左边是小于key的,右边是大于key的值。
return i + 1;
}
void quickSort(int a[], int p, int r) {
int position = 0;
if (p<r)
{
position = partition(a,p,r);//返回划分元素的最终位置
quickSort(a,p,position-1);//划分左边递归
quickSort(a, position + 1,r);//划分右边递归
}
}
选择排序算法就是每一趟从待排序的记录中选出关键字最小(最大)的记录,顺序放在已排好序的子文件的最后(最前),直到全部记录排序完毕。常见的选择排序有直接选择排序(Selection Sort),堆排序(Heap Sort)
最差时间复杂度:O(n^2) 最优时间复杂度:O(n^2) 平均时间复杂度:O(n^2) 稳定性:不稳定
直接选择排序(Selection Sort),这是一种简单直观的排序算法。它首先在未排序序列中找到最小(大)元素,存放到排序序列的其起始位置,然后再从剩余未排序的序列元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素排序完毕。
- void SelectSort(int *a, int len)
- {
- for (int i=0; i<len-1; i++)
- {
- int k = i;
- int key = a[i];
- for (int j=i+1; j<len; j++)
- {
- if (a[j]<key)
- {
- k = j;
- key = a[j];
- }
- }
- if (k!=i)
- swap(a[i], a[k]);
- }
- }
- 堆排序:堆排序是利用堆的性质进行的一种选择排序。
最差时间复杂度:O(nlogn) 最优时间复杂度:O(nlogn) 平均时间复杂度:O(nlogn) 稳定性:不稳定 - 堆:一棵完全二叉树,对于大根堆来说,其每一个节点的值都大于或者等于任意一个子节点的值。小根堆反之。
下面举例说明:
给定一个整形数组a[]={16,7,3,20,17,8},对其进行堆排序。 首先根据该数组元素构建一个完全二叉树,得到
然后需要构造初始堆,则从最后一个非叶节点开始调整,调整过程如下:
20和16交换后导致16不满足堆的性质,因此需重新调整
这样就得到了初始堆。
即每次调整都是从父节点、左孩子节点、右孩子节点三者中选择最大者跟父节点进行交换(交换之后可能造成被交换的孩子节点不满足堆的性质,因此每次交换之后要重新对被交换的孩子节点进行调整)。有了初始堆之后就可以进行排序了。
3位于堆顶不满堆的性质,则需调整继续调整
下面的图也可以说明推排序的思想:
- voidHeapAdjust(int*array,inti,intsize)
- {
- intlchild = 2 * i + 1;
- intrchild = 2 * i + 2;
- intmax = i;
- if(lchild < size&&array[lchild] > array[max])
- {
- max = lchild;
- }
- if(rchild < size&&array[rchild] > array[max])
- {
- max = rchild;
- }
- if(max != i)
- {
- swap(array[i],array[max]);
- HeapAdjust(array, max, size);
- }
- }
- voidBuildHeap(int*array,intsize)
- {
- for(inti = (size/ 2)-1; i >= 0; i--)
- HeapAdjust(array, i, size);
- for(inti = size - 1; i >= 1; i--)
- {
- swap(array[0],array[i]);
- HeapAdjust(array, 0, i);
- }
- }
- 归并排序
最差时间复杂度:O(nlogn) 最优时间复杂度:O(nlogn) 平均时间复杂度:O(nlogn) 稳定性:稳定
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
首先考虑下如何将将二个有序数列合并。这个非常简单,只要从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。
解决了上面的合并有序数列问题,再来看归并排序,其的基本思路就是将数组分成二组A,B,如果这二组组内的数据都是有序的,那么就可以很方便的将这二组数据进行排序。如何让这二组组内数据有序了?
可以将A,B组各自再分成二组。依次类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的二个小组就可以了。这样通过先递归的分解数列,再合并数列就完成了归并排序。
- void Merge(int * a, int low, int mid, int high, int * temp)
- {
- int i,j,k;
- i = low;
- j = mid + 1;//避免重复比较a[mid]
- k = 0;
- while (i <= mid && j <= high)//数组a[low,mid]与数组(mid,high]均没有全部归入数组temp中去
- {
- if(a[i] <= a[j]) //如果a[i]小于等于a[j]
- temp[k++] = a[i++]; //则将a[i]的值赋给temp[k],之后i,k各加一,表示后移一位
- else
- temp[k++] = a[j++]; //否则,将a[j]的值赋给temp[k],j,k各加一
- }
- while(i <= mid) //表示数组a(mid,high]已经全部归入temp数组中去了,而数组a[low,mid]还有剩余
- temp[k++] = a[i++]; //将数组a[low,mid]剩下的值,逐一归入数组temp
- while(j <= high) //表示数组a[low,mid]已经全部归入到temp数组中去了,而数组(mid,high]还有剩余
- temp[k++] = a[j++]; //将数组a(mid,high]剩下的值,逐一归入数组temp
- for (i = 0; i < k; i++) //将归并后的数组的值逐一赋给数组a[low,high]
- a[low+i] = temp[i]; //注意,应从a[low+i]开始赋值
- }
- //二路归并(递归实现)
- void MergeSort(int * a, int low, int high, int * temp)
- {
- if (low < high)
- {
- int mid = (low + high)/2;
- MergeSort(a,low,mid,temp); //左边有序
- MergeSort(a,mid+1,high,temp); //右边有序
- Merge(a,low,mid,high,temp); //再将两个有序序列合并
- }
- }
- 计数排序
最差时间复杂度:O(n) 最优时间复杂度:O(n) 平均时间复杂度:O(n) 稳定性:稳定
以往的排序算法中,各个元素的位置基于元素直接的比较,这类排序称为比较排序。任意一个比较排序算法在最坏情况下,都需要做Ω(nlgn)次的比较。而计数排序是基于非排序的思想的,计数排序假设n个输入元素中的每一个都是介于0到k之间的整数。
计数排序的思想是对每一个输入元素x,确定出小于x的元素个数,有了这一信息,就可以把x直接放在它在最终输出数组的位置上,例如,如果有17个元素小于x,则x就是属于第18个输出位置。当几个元素相同是,方案要略作修改。计数排序是稳定的。
- voidCountingSort(int*array,intlength)
- {
- inttemp = array[0];
- for(inti = 1; i < length; i++)
- {
- if(temp < array[i])
- temp =array[i];
- }
- intbucket[10] = { 0 };//注意,需要提前定义好bucket中的大小,待改进。
- for(inti = 0; i <length; i++)
- bucket[array[i]]++;
- intj = 0;
- for(inti = 0; i < temp + 1; i++)
- {
- while(bucket[i] > 0)
- {
- array[j++] = i;
- bucket[i]--;
- }
- }
- }
常见的排序算法总结:
阅读全文
0 0
- 常用的排序算法总结
- 常用的排序算法总结
- 常用的排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法 总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- Struts2.x中实现文件上传功能
- unicode编码转中文处理
- 笔记9--CSS基础知识
- java 中的while循环
- LintCode 463.整数排序 II [快速排序基础应用]
- 常用的排序算法总结
- poj 1573 Robot Motion 模拟
- HDU1005
- Ubuntu安装navicat
- 单链表的插入,查找,删除
- rpm&&yum
- 把本地项目推送到github的命令
- 解决IDEA乱码问题
- JVM垃圾回收机制