排序算法

排序

稳定排序:Ri = Rj,排序前Ri 领先于 Rj,若排序后Ri 仍然领先于 Rj,则称为稳定排序
非稳定排序:与稳定排序相反。

内排序:待排文件在计算机的内部存储器中,其排序过程在内存中进行,速度较快,但内存容量一般很小,文件的长度(记录个数)n受到一定限制。
外排序:排序中文件存入外存储器,排序过程借助于内外数据交换(或归并)来完成

本文章讲述内排序,可归纳为五类:

  1. 插入排序

直接插入排序(类似扑克牌插入)时间复杂度O(n2)
i:对应无序序列下标,j:对应有序序列下标

void insert_sort(int *a)
{
        int i = 0,j = 0;
        int tmp = 0;
        for( i = 1; i < N; i++){
                tmp = a[i];
                for(j=i-1;j >= 0;j--){
                        if( a[j] > tmp ){
                                a[j+1] = a[j];
                        }else
                                break;
                }
                a[j+1] = tmp;
                show(a);
        }
}

(shell)希尔排序:时间复杂度O(nlogn)
对直接插入排序进行改进优化,减少直接排序中元素大量移动的时间和比较的次数。将序列分组,增量为d,序列相隔为d的所有元素为一组进行排序,排序完毕后增量为原来的一半,循环分组排序,直到 增量d 小于等于 0,最后进行直接插入排序。

void shell_sort(int *a)
{
        int i = 0,j = 0;
        int tmp = 0;
        int d = 0;
        for( d=N/2; d > 0; d /= 2){
                for( i = d-1; i < N; i++){
                        tmp = a[i];
                        for(j=i-d;j >= 0;j -= d){
                                if( a[j] > tmp ){
                                        a[j+d] = a[j];
                                }else
                                        break;
                        }
                        a[j+d] = tmp;
                }
                show(a);
        }
}
  1. 交换排序

冒泡排序(两两相邻记录的关键字,如果反序则调换,直到没有反序为止)时间复杂度O(n2)

void Bubblesort1(int k[],int n)
{
	int i, j, tmp;
	
	for( i = 0; i < n-1; i++){
		for(j = n-1; j > i; j--){
			if( k[j-1] > k[j] ){
				tmp = k[j];
				k[j] = k[j-1];
				k[j-1] = tmp;
			}
		}
	}
}
//优化
void Bubblesort2(int k[],int n)
{
	int i, j, tmp;
	bool flag = 1;
	int t;
	for( i = 0; i < n-1 && flag == 1; i++){
		flag = 0;
		for(j = n-1; j > i; j--){
			if( k[j-1] > k[j] ){
				tmp = k[j-1];
				k[j-1] = k[j];
				k[j] = tmp;
				flag = 1;
			}
		}
		for(t = 0; t < 10;t++)
		printf("%d\t",k[t]);
		printf("\n");
	}
}

快速排序(序列第一个作为基值,并找出基值的位置,在将序列分为左右两子序列,在对左右两序列重复操作,递归实现)

int get_base_pos(int *a, int low, int high)
{
        int base_val;
        base_val = a[low];//第一个值作为基值
        while(low < high){
                while(low < high && base_val <= a[high])
                        high--;
                //若基值比上界值大,则将上界对应下标high位置的数据赋给下界对应low位置
                if(low < high)
                        a[low] = a[high];
                while(low < high && base_val >= a[low])
                        low++;
                //若基值比下界值小,则将下界对应下标low位置的数据赋给上界对应high位置
                if(low < high)
                        a[high] = a[low];
        }
        //当low == high时,即为基值位置
        a[low] = base_val;
        return low;
}
void quick_sort(int *a,int low,int high)
{
        int base_pos = 0;
        //递归终止条件
        if(low >= high)
                return ;
        base_pos = get_base_pos(a, low, high);
        show(a);
        quick_sort(a, low, base_pos-1);//处理左序列
        quick_sort(a, base_pos+1, high);//处理右序列
}

快速排序的优化

  1. 当数组巧好为比较极端时候,例如987654321这排列,那么快速排序取基值位置分隔只能分隔一边,导致效率最低,那么我们可以对数组的基值作相应优化。
  2. 快速排序对数量级小的序列效率较低,而直接插入排序的性能相对较高,所以应该判断数据的量级,从而选择使用两种排序方法
  3. 对递归的方式优化,使用尾递归,(尾递归:函数中递归形式的调用出现在函数末尾,编译器检测到会覆盖当前活跃记录,而不是重新创建栈空间,当函数返回时,因为栈帧没有其他事情可做,也就没有必要保证栈空间,使用栈空间大大减少,提高运行效率,一般递归都尽量写成尾递归方式。)
int get_base_pos(int *a, int low, int high)
{
        int base_val;
      /****************基值优化部分********************/
        int tmp;
        int m = low + (high - low)/2;
        if(a[low] > a[high]){
        	tmp = a[low];
			a[low] = a[high];
			a[high] = tmp;
		}
		if(a(m) > a(high)){
			tmp = a[m];
			a[m] = a[high];
			a[high] = tmp;
		}
		if(a(m) > a(low)){
			tmp = a[m];
			a[m] = a[low];
			a[low] = tmp;
		}
	/***********************************************/
        base_val = a[low];//第一个值作为基值
        while(low < high){
                while(low < high && base_val <= a[high])
                        high--;
                //若基值比上界值大,则将上界对应下标high位置的数据赋给下界对应low位置
                if(low < high)
                        a[low] = a[high];
                while(low < high && base_val >= a[low])
                        low++;
                //若基值比下界值小,则将下界对应下标low位置的数据赋给上界对应high位置
                if(low < high)
                        a[high] = a[low];
        }
        //当low == high时,即为基值位置
        a[low] = base_val;
        return low;
}

void quick_sort(int *a,int low,int high)
{
        int base_pos = 0;
        //递归终止条件
        if(low >= high)
                return ;
       	while( low < high){
        	base_pos = get_base_pos(a, low, high);
        	if( base_pos-low < high- base_pos ){
        		quick_sort(a, low, base_pos-1);//处理左序列
        		low = base_pos + 1;
        	}else{
        		quick_sort(a, base_pos+1,high);//处理右序列
        		high = base_pos - 1;
      		}
        }
}
  1. 选择排序:(通过 n-i 次关键字间的比较,从n-i+1 个记录中选出关键字最小的记录,并和第i个记录交换)时间复杂度O(n2)
void selectsort(int k[],int n)
{
	int i,j,tmp,min;
	for(i=0;i<n-1;i++){
		min = i;
		for(j=i+1;j<n-2;i++){
			if( k[j] < k[min] ){
				min = j;
			}
		}
		if( min != i){
			temp = k[min];
			k[min] = k[i];
			k[i] = temp;
		}
	}
}

堆排序:对选择排序的优化,时间复杂度O(nlogn)
对二叉树的应用,后续补上代码。。。。

  1. 归并排序(先将序列拆分成两部分直到序列只含单个元素,在两两进行合并形成有序的子序列,最后在合并成一个主序列,即排序结束)
    递归实现
void merging(int *list1,int list1_size,int *list2,int list2_size)
{
	int temp[N] = {0};
	int i,j,k,m;
	i = j = k = m = 0;
	while( i < list1_size && j < list2_size ){
		if( list1[i] < list2[j] )
			temp[k++] = list1[i++];
		else
			temp[k++] = list2[j++];
	}
	while(i < list1_size)
		temp[k++] = list1[i++];
	while(j < list2_size)
		temp[k++] = list2[j++];
	for(m = 0; m < list1_size + list2_size; m++)
		list1[m] = temp[m];
}

void mergesort(int k[], int Num)
{
	if(Num <= 1)
		return ;
	int *list1 = k;
	int list1_size = Num/2;
	int *list2 = k + list1_size;
	int list2_size = Num - list1_size;
	
	mergesort(list1, list1_size);
	mergesort(list2, list2_size);
	
	merging(list1,list1_size,list2,list2_size);
}

迭代实现

void mergesort(int k[], int n)
{
	int i, left_min, left_max, right_min, right_max,next;
	int *temp = (int *)malloc(n * sizeof(int));
	
	for( i=1; i < n; i*=2 ){
		for( left_min = 0; left_min < n-i ; left_min = right_max){
			
			right_min = left_min + i;
			left_max = left_min + i;
			right_max = left_max + i;
			
			if( right_max > n){
				right_max = n;
			}
			
			next = 0;
			
			while( left_min < left_max && right_min < right_max ){
				
				if( k[left_min] < k[right_min] ){
					temp[next++] = k[left_min++];
				}else{
					temp[next++] = k[right_min++];
				}
			}
			
			while(left_min < left_max ){
				k[--right_min] = k[--left_max];
			}
			
			while( next > 0 ){
				k[--right_min] = temp[--next];
			}
		}
	}
}
  1. 基数排序
    这里未作讲解,感兴趣的可以去其他论坛找资料

比较分析

这里说明一下经过优化的快速排序在数据级较大时发挥最好,数量级小的用直接插入,而堆排序一般用在对内存比较苛刻的单片机和嵌入式领域比较合适。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值