1 选择排序
时间复杂度:
O
(
n
2
)
O(n^2)
O(n2);
唯一的好处:不占用额外的内存空间。
算法步骤:
1)首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置;
2)再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾;
3)重复第二步,直到所有元素均排序完毕。
//实现1
//内层循环用于比较i位置的元素和后面序列的所有元素依次比较;
//这种方式是在每次比较之后,会将较小的元素和自己进行交换,若后面碰到更小的元素,则再进行交换。
void selectionSort(T arr[],int n){
for(int i=0;i<n;++i)
for(int j=i+1;j<n;++j)
if(arr[i]>arr[j])
swap(arr[i],arr[j]);
}
//实现2
//
void selectionSort(T arr[],int n){
for(int i=0;i<n;i++){
//寻找[I,n)区间最小值
int minIndex=i;//存储最小值的索引
for(int j=i+1;j<n;j++){
if(arr[j]<arr[minIndex])
minIndex=j;
}
swap(arr[i],arr[minIndex]);
}
}
2 插入排序
思路:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
插入排序是依次与后一个位置的数据进行比较,如果前者小于(或大于)后者,就交换这两个元素。
下图的2比8小,所以将2和8进行交换:
算法步骤:
1)将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
2)从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。
(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
实现:
void insertionSort(T arr[],int n){
for(int i=1;i<n;i++){
//寻找元素arr[i]合适的插入位置
for(int j=i;j>0;j--){//这里是向前移动,所以j--
if(arr[j]<arr[j-1])//与前一个位置进行比较
swap(arr[j],arr[j-1]);
else
break;//如果不满足就跳出第二层for循环
}
}
}
优化算法:
将元素先拷贝一个出来,记为e,然后与前面的元素进行比较,如果小于前面的元素,就将前面的元素拷贝到自己的位置上;然后继续向前比较,直到出现大于前面的元素的情况,就将事先拷贝的e放置到后一个位置上。
void insertionSort(T arr[],int n){
for(int i=1;i<n;i++){
//寻找元素arr[i]合适的插入位置
T e=arr[i];//拷贝一个副本
int j;//j保存元素e应该插入的位置;
for( j=i;j>0&&arr[j-1]>e;j--){
arr[j]=arr[j-1];
}
arr[j]=e;
}
}
3 冒泡排序
算法步骤:
1)比较相邻的元素,如果第一个比第二个大,就交换他们两个;
2)对每一对相邻的元素工作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数;
3)针对所有的元素重复以上的步骤,除了最后一个。
实现:
//实现1
//内层循环用于每一次将未排序的序列中最小值移动到序列后面;
//外层循环用于控制内层循环的次数;
//这里和之前的双重循环有点不同,每次都需要从头开始遍历,所以第i次遍历时,j的初值仍然为0;
//注意:
//1)每经过一次内层遍历,待排序的序列长度就减少1,所以,j的终止条件是n-1-i;
//2)外层循环的终止条件可以写为n-1,因为一次交换会影响两个元素,举个例子:如果序列只有两个元素,那么交换一次就可以实现排序成功了。
template<typename T>
void bubbleSort(T arr[],int n){
for(int i=0;i<n-1;++i){//这里的终止是n-1
for(int j=0;j<n-1-i;++j){//这里的终止是n-1-i
if(arr[j]>arr[j+1])
swap(arr[j],arr[j+1]);
}
}
}
//实现2
void bubbleSort(T arr[],int n){
int newn;//使用newn进行优化
do{
newn=0;
for(int i=1;i<n;++i){
if(arr[i-1]>arr[i]) {
swap(arr[i - 1], arr[i]);
// 记录最后一次的交换位置,在此之后的元素在下一轮扫描中均不考虑
newn = i;
}
}
n=newn;
}while(newn>0);
}
4 希尔排序
递减增量排序算法,是插入排序的一种更搞笑的改进版本。但希尔排序是非稳定排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
- 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;
- 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位;
基本思想:
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
//实现1
void shellSort(T arr[], int n){
// 计算 increment sequence: 1, 4, 13, 40, 121, 364, 1093...
int h = 1;
while( h < n/3 )
h = 3 * h + 1;
while( h >= 1 ){
// h-sort the array
for( int i = h ; i < n ; i ++ ){
// 对 arr[i], arr[i-h], arr[i-2*h], arr[i-3*h]... 使用插入排序
T e = arr[i];
int j;
for( j = i ; j >= h && e < arr[j-h] ; j -= h )
arr[j] = arr[j-h];
arr[j] = e;
}
h /= 3;
}
}
//实现2
void shellSort(T arr[],int n){
for(int gap=n/2;gap>0;gap/=2){//希尔增量
for(int i=gap;i<n;i++){//插入排序
T e=arr[i];
int j;
for(j=i;j>=gap && e<arr[j-gap];j-=gap)//注意这里的边界
arr[j]=arr[j-gap];
arr[j]=e;
}
}
}
相关视频:希尔排序