排序算法--整理and笔记

每次用排序算法的时候都是用的冒泡法,这里整理下排序算法,用于以后应用。

C++库里带的函数为sort(start,end,compare);qsort(...);

最近都在用sort进行排序,用于vector的排序十分有效。qsort没怎么用过,等以后了解过再贴。

参考链接:

1)http://blog.csdn.net/likefrank/article/details/2974949

2)http://blog.csdn.net/hguisu/article/details/7776068

3)http://blog.csdn.net/xiazdong/article/details/8462393

4)http://blog.chinaunix.net/uid-25906157-id-3318529.html

5)http://www.cnblogs.com/eniac12/p/5329396.html--喜欢这篇文章里面的图,强推。

6)http://www.cnblogs.com/eniac12/p/5332117.html--记录非比较方法,接链接5)

7)http://blog.csdn.net/hguisu/article/details/7776068#t7

先上图,各排序算法的空间复杂度和稳定性情况:表来自链接1)

排序法 平均时间最差情形稳定度额外空间备注
冒泡 O(n2)  O(n2) 稳定O(1)n小时较好
交换  O(n2)  O(n2)不稳定O(1)n小时较好
选择 O(n2) O(n2)不稳定O(1)n小时较好
插入 O(n2) O(n2)稳定O(1)大部分已排序时较好
基数O(logRB)O(logRB)稳定O(n+r)

B是真数(0-9),

R是基数(个十百)

ShellO(nlogn)O(ns) 1<s<2不稳定O(1)s是所选分组
快速O(nlogn)O(n2)不稳定O(nlogn)n大时较好
归并O(nlogn)O(nlogn)稳定O(n)n大时较好
O(nlogn)O(nlogn)不稳定O(1)n大时较好

因为冒泡,交换,选择和插入排序复杂度类似,都是在小型数据应用较好,所以在此不详细记录。

主要对基数,Shell(希尔),快速,归并,堆排序进行讨论说明

//代码参考链接及书《C和C++程序员面试秘籍》

一、基数排序

当时学语言和数据结构的时候并没有第一次听说过这种算法。参考链接3)4)5)

不过这种算法只适用于整数的排序,浮点数的排序,需要重新映射

思想:它是一张非比较的算法,根据位的高低进行排序,所以先按个位数进行排序,再根据十位数进行排序......以此类推

//find the max number
int find_max(int a[],int len)
{
	int max=a[0];
	for(int i=1;i<len;++i)
	{
		if(max<a[i])
			max=a[i];
	}
	return max;
}
int digit_number(int number)
{
	int digit=0;
	while(number!=0)
	{
		number/=10;
		digit++;
	}
	return digit;
}
//return kth number
int kth_digit(int number,int kth)
{
	number/=pow(10,kth);
	return number%10;
}
void radix_sort(int a[],int len)
{
	int **temp=new int *[10];
	int count[10];
	int max=find_max(a,len);
	int maxDigit=digit_number(max);
	for(int i=0;i<10;++i)
	{
		temp[i]=new int[len];
		memset(temp[i],0,sizeof(int)*len);
	}
	for(int i=0;i<maxDigit;++i)
	{
		memset(count,0,sizeof(int)*10);
		for(int j=0;j<len;++j)
		{
			int xx=kth_digit(a[j],i);
			temp[xx][count[xx]]=a[j];
			count[xx]++;
		}
		int index=0;
		for(int j=0;j<10;++j)
		{
			for(int k=0;k<count[j];++k)
			{
				a[index++]=temp[j][k];
			}
		}
	}

}


二、希尔排序

插入排序的高速尔稳定的改进版本。

将数据分成不同组,先对每一组进行排序,再对所有的元素进行插入排序。

希尔排序,也叫递减增量排序,是插入排序的一种更高效的改进版本。希尔排序是不稳定的排序算法。

  希尔排序是基于插入排序的以下两点性质而提出改进方法的:

  • 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率
  • 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位
void shell_sort(int a[],int len)
{
	int j;
	for(int h=len/2;h>0;h=h/2)
	{
		for(int i=h;i<len;++i)
		{

				int temp=a[i];
				j=i-h;
				while(j>=0&&temp<a[j])
				{
					a[j+h]=a[j];
					j-=h;
				}
				a[j+h]=temp;
		}
	}
}


三、快速排序

一般选择序列最左边的值作为支点数据,将序列分成2部分,一部分大于另一部分小于,再对两边的数据进行递归排序。

快速排序使用分治策略(Divide and Conquer)来把一个序列分为两个子序列。步骤为:

  1. 从序列中挑出一个元素,作为"基准"(pivot).
  2. 把所有比基准值小的元素放在基准前面,所有比基准值大的元素放在基准的后面(相同的数可以到任一边),这个称为分区(partition)操作。
  3. 对每个分区递归地进行步骤1~3,递归的结束条件是序列的大小是0或1,这时整体已经被排好序了。
void quick_sort(int a[],int low,int high)
{
	int pivot;
	if(low<high)
	{
		pivot=a[low];
		int i=low;
		int j=high;
		while(i<j)
		{
			while(i<j&&a[j]>=pivot)
				--j;
			if(i<j)
				a[i++]=a[j];
			while(i<j&&a[i]<pivot)
				i++;
			if(i<j)
				a[j--]=a[i];
		}
		a[i]=pivot;
		quick_sort(a,low,i-1);
		quick_sort(a,i+1,high);
	}
}



四、归并排序

归并排序的实现分为递归实现与非递归(迭代)实现。递归实现的归并排序是算法设计中分治策略的典型应用,我们将一个大问题分割成小问题分别解决,然后用所有小问题的答案来解决整个大问题。非递归(迭代)实现的归并排序首先进行是两两归并,然后四四归并,然后是八八归并,一直下去直到归并了整个数组。

归并排序算法主要依赖归并(Merge)操作。归并操作指的是将两个已经排序的序列合并成一个序列的操作,归并操作步骤如下:

  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置
  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
  4. 重复步骤3直到某一指针到达序列尾
  5. 将另一序列剩下的所有元素直接复制到合并序列尾

void Merge(int *r,int *rf, int i, int m, int n)  
{  
    int j,k;  
    for(j=m+1,k=i; i<=m && j <=n ; ++k){  
        if(r[j] < r[i]) rf[k] = r[j++];  
        else rf[k] = r[i++];  
    }  
    while(i <= m)  rf[k++] = r[i++];  
    while(j <= n)  rf[k++] = r[j++];  
    //print(rf,n+1);  
}  
  
void MergeSort(int *r, int *rf, int length)  
{   
    int len = 1;  
    int *q = r ;  
    int *tmp ;  
    while(len < length) 
	{  
        int s = len;  
        len = 2 * s ;  
        int i = 0;  
        while(i+ len <length)
		{  
            Merge(q, rf,  i, i+ s-1, i+ len-1 ); //对等长的两个子表合并  
            i = i+ len;  
        }  
        if(i + s <=length)
		{  
            Merge(q, rf,  i, i+ s-1 , length -1); //对不等长的两个子表合并  
        }  
        tmp = q; q = rf; rf = tmp; //交换q,rf,以保证下一趟归并时,仍从q 归并到rf  
    }  
}  



五、堆排序

堆排序是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构(通常堆是通过一维数组来实现的),并同时满足堆的性质:即子结点的键值总是小于(或者大于)它的父节点。

  我们可以很容易的定义堆排序的过程:

  1. 创建一个堆
  2. 把堆顶元素(最大值)和堆尾元素互换
  3. 把堆的尺寸缩小1,并调用heapify(A, 0)从新的堆顶元素开始进行堆调整
  4. 重复步骤2,直到堆的尺寸为1

/** 
 * 已知H[s…m]除了H[s] 外均满足堆的定义 
 * 调整H[s],使其成为大顶堆.即将对第s个结点为根的子树筛选,  
 * 
 * @param H是待调整的堆数组 
 * @param s是待调整的数组元素的位置 
 * @param length是数组的长度 
 * 
 */  
void HeapAdjust(int H[],int s, int length)  
{  
    int tmp  = H[s];  
    int child = 2*s+1; //左孩子结点的位置。(i+1 为当前调整结点的右孩子结点的位置)  
    while (child < length) {  
        if(child+1 <length && H[child]<H[child+1]) { // 如果右孩子大于左孩子(找到比当前待调整结点大的孩子结点)  
            ++child ;  
        }  
        if(H[s]<H[child]) {  // 如果较大的子结点大于父结点  
            H[s] = H[child]; // 那么把较大的子结点往上移动,替换它的父结点  
            s = child;       // 重新设置s ,即待调整的下一个结点的位置  
            child = 2*s+1;  
        }  else {            // 如果当前待调整结点大于它的左右孩子,则不需要调整,直接退出  
             break;  
        }  
        H[s] = tmp;         // 当前待调整的结点放到比其大的孩子结点位置上  
    }  
    //print(H,length);  
}  
  
  
/** 
 * 初始堆进行调整 
 * 将H[0..length-1]建成堆 
 * 调整完之后第一个元素是序列的最小的元素 
 */  
void BuildingHeap(int H[], int length)  
{   
    //最后一个有孩子的节点的位置 i=  (length -1) / 2  
    for (int i = (length -1) / 2 ; i >= 0; --i)  
        HeapAdjust(H,i,length);  
}  
/** 
 * 堆排序算法 
 */  
void HeapSort(int H[],int length)  
{  
    //初始堆  
    BuildingHeap(H, length);  
    //从最后一个元素开始对序列进行调整  
    for (int i = length - 1; i > 0; --i)  
    {  
        //交换堆顶元素H[0]和堆中最后一个元素  
        int temp = H[i]; H[i] = H[0]; H[0] = temp;  
        //每次交换堆顶元素和堆中最后一个元素之后,都要对堆进行调整  
        HeapAdjust(H,0,i);  
  }  
}   


上面内容来源于别人的博客加以整理。了解排序算法的过程。


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值