C++数据结构与算法分析_排序(1)

学习数据结构,记录以c++语言解释的排序算法。介绍基础的插入排序、选择排序和冒泡排序,以及高效的希尔排序,剩下的堆排序、快速排序、归并排序、基数排序在下一篇提到。


关键属性/衡量标准

当对可选方法进行比较效率时,定义了两个时间复杂度关键属性:比较次数和数据移动次数。这两个的衡量标准是采取数量级O的表示方式,在最好情况(通常数据已排序)、最坏情况(数据按相反顺序排序)、平均情况(数据顺序是随机的)下计算算法效率。几个排序算法的时间复杂度和空间复杂度概览:

 

一、基本的排序方法之插入排序

以从小到大的规则排序为例,插入排序首先考虑数组data中的前两个元素data[0]和data[1],如果data[0]大于data[1]则交换位置,认为前面两个已经是有序了。然后继续考虑下一个元素data[2],如果data[2]同时小于前面的元素data[0]和data[1]则将data[0]和data[1]后移一位,data[2]放到位置0上,如果data[2]小于data[1]大于data[0]则只将data[1]右移一位,data[2]放到位置1上,如果data[2]都不小于前面则不动。然后继续这种策略,从左到右逐步有序化。代码实现:

template<class T>
void insertionsort (T data[], int n){
    for(int i=1,j;i<n;i++){
        T tmp=data[i];
        for(j=i;j>0 && tmp<data[j-1];j--) //观察第i个元素跟前面有序元素的大小
            data[j]=data[j-1];            //小于就将前面的右移(通过后面的复制前面的值)
        data[j]=tmp;
      }
}

时间复杂度:最好O(n),最差O(n^2),平均O(n^2)

二、基本的排序方法之选择排序

以从小到大的规则排序为例,选择排序其基本思想是先找出数组中的最小元素将其与第一个位置上的元素进行交换,然后在剩余元素data[1],....,data[n-1]中找到最小的元素放在第二个位置,依此类推即在每次迭代中找出元素data[i],...,data[n-1]中的最小元素,然后将其与data[i]交换位置,直到所有元素都放到了合适的位置。代码实现:

template<class T>
void selection(T data[], int n){
    for(int i=0,j,least;i<n-1;i++){
    for(j=i+1,least=i;j<n;j++)  //找出从i序号往后元素的最小元素序号
        if(data[j] < data[least])
            least=j;  
        swap(data[least],data[i])  //交换最小元素和第i个元素
    }
}

时间复杂度:最好O(n^2),最差O(n^2),平均O(n^2)

三、基本的排序方法之冒泡排序

以从小到大的规则排序为例,冒泡排序其基本思想是从最右开始扫描,如果相邻两个元素是逆序的则交换位置,即在第一轮扫描中先比较data[n-1]和data[n-2]如果逆序就交换,接着比较data[n-2]和data[n-3]如果逆序就交换,一直比较到data[1]和data[0],这样最小的元素就冒到了数组的第0个位置;在第二次扫描时最后比较data[2]和data[1]找出第二个最小的元素冒到位置1上;一直扫描到排完序为止。代码实现:

template<class T>
void bubblesort(T data,int n){
    for(i=0,j;i<n-1;i++){
        for(j=n-1;j>i;--j)  //j++和++j的循环效果是一样的,都是在一次循环之后变值
            if(data[j]<data[j-1])
                swap(data[j],data[j-1]);
    }
}

时间复杂度:最好O(n^2),最差O(n^2),平均O(n^2)   

在改进的冒泡排序算法(更多情况提到冒泡排序可能是指这个算法)时间复杂度:最好O(n),最差O(n^2),平均O(n^2)

template <class T>
void bubblesort2 (T data[],int n) //改进的冒泡算法,设置了一个布尔量监控迭代的冒泡过程
{
	bool again=true;//当某次冒泡不发生交换时说明已经有序,不用再继续冒泡
	for(int i==0,j;i<n-1 && again;i++){
		for(j=n-1,again=false;j>i;j--)
			if(data[j]<data[j-1]){
				swap(data[j],data[j-1])
				again=true;
			}
	}
}

在改进的冒泡排序基础上,提出comb_sort梳排序算法,先将部分大数值的元素放到数组后面,然后再进行改进的冒泡排序,表现出的良好性能可以与快速排序媲美,最好O(nlog(n)),最差O(n^2)。

template<class T >
void combsort(T data[],int n)
{	//先处理数组,将一些大数值调整到数组后面
	for(int step=n/1.3;step>1;step/=1.3)
		for(int i=n-1;i-step>=0;i-=step)
			if(data[i]<data[i-step])
				swap(data[i],data[i-step]);
        //最后进行改进的冒泡排序
	bool again=true;
	for(int a=0;a<n-1 && again;a+++)
		for(int b=n-1,again=false;b>a;b--)
			if(data[b]<data[b-1]){
				swap(data[b],data[b-1]);
				again=true;}
}

四、高效的排序方法之希尔排序

希尔排序的基本思想是将数组data在逻辑上分成几个子数组(物理上元素序列没变),比如分成ht个子数组则具体操作是从原始数组中每隔ht个元素作为一个子数组的一部分(因此ht又称为增量值),那么可以得到共ht个子数组,对于其中第ha个子数组元素,即data_ht_ha[i]=data[ht*i+(ha-1)],然后在每个子数组中使用指定的排序方法(一般插入排序 ),然后再进行分割成ht2个子数组,调用相同的处理过程,然后再重新分割,以此类推。增量值的经验性选取h(1)=1,h(i+1)=3h(i)+1比较合适,当h(t+1)>n时停止选取,最大值为h(t),(比如n=10000则增量值为1,4,13,40,121,364,1093,3280)。然后从以最大数值增量值开始分割原始数组,在其中的每个子数组中进行排序,然后逐次递减增量值分割重复过程,即首先比较相隔很远的元素,然后比较相隔较近的元素。以此类推,最后一次比较相邻的两个元素。代码实现:

template<class T>
void ShellSort(T data[],int arrSize){
    register int i,j,hCnt,h;
    //构建增量值序列
    int increments[20],k;
    for(h=1, i=0; h<arrSize; i++){
        increments[i]=h;
        h=3*h+1;
    }
    //从满足条件的序列中取最大值开始分割,然后逐渐减小
    for(i--;i>=0;i--){
        h=increment[i];
        //遍历一个增量值分割出的几个逻辑子数组,从每个子数组的1序号元素开始
        for(hCnt=h;hCnt<2*h;hCnt++){
            //单个子数组序列中排序过程
            for(j=hCnt;j<arrSize;){
                //插入排序
                T temp=data[j];
                k=j;
                while(k-h>0 && temp<data[k-h]){
                    data[k]=data[k-h];
                    k-=h;        
                }
                data[k]=tmp;
                j+=h;
            }
        }
    }
}

时间复杂度:最好O(n),最差O((nlog(n))^2),平均O((nlog(n))^2)

 

后面再讲高效的堆排序、快速排序、归并排序、基数排序,即这里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值