排序基础

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进行交换:
Alt
Alt
算法步骤
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循环
        }
    }
}

优化算法:
Alt将元素先拷贝一个出来,记为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;
        }
    }
}

相关视频:希尔排序
Alt

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值