您的位置:首页 > 其它

排序总结:堆排序、快速排序、归并排序、基数排序

2016-08-06 14:30 363 查看
排序算法按照不同的方式可以进行不同的分类:分为内部排序和外部排序;稳定性排序和不稳定性排序。

我们常用的简单排序方法(选择、交换、插入),尽管非常容易理解和实现,但是它们的效率不高,这点在数据量较大时尤为明显。

本文将简绍一些更高效的排序模式(堆排序、快速排序、归并排序、基数排序)的算法和实现,主要用于本人近期学习的总结,各位不喜勿喷



堆排序 

算法总结:堆,是一棵完全二叉树,其中每个节点的数据项大于或等于其子树的数据项。我们用堆实现排序,实际上就是利用树形结构查找方便的优势,这种排序方法已经在STL中实现,对应函数名分别是make_heap、push_heap、pop_heap、sort_heap。对于最大堆,堆的根实际上就是堆中所有元素的最大值,将根元素以堆最后一个元素交换,再经过调整堆中剩余元素,找出剩余元素中的最大值,这实际上是一种选择排序法的思想:通过对调整找到元素中的最大值,然后放到尾部。

实现代码:
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <iterator>

int * rand_seq(int num)
{
int *tem=new int[num];
srand((unsigned)time(NULL));
for(int i=0;i<num;i++) tem[i]=rand()%100;
return tem;
}
void print(int *data,int num)
{
std::copy(data,data+num,std::ostream_iterator<int>(std::cout,"  "));
std::cout<<std::endl;
}

//下调第i个元素,保证以i元素为根的堆结构
void adjust_heap(int *data, int i, int num)
{
if(i<num)
{
//左右子树索引
int left=2*i+1;
int right=2*i+2;
//找到i,left,right中最大数的索引
//当然还要确保索引值有效
int index=  (left<num&&data[left]>data[i])?
((right<num&&data[right]>data[left])?right:left):
((right<num&&data[right]>data[i])?right:i);
//交换
if(i!=index)
{
std::swap(data[i],data[index]);
adjust_heap(data,index,num);
}
}
}
//将无序的数据元素重建成堆
void  build_heap(int *data, int num)
{
int tree_index=(num-1)/2;//最后一个非叶子节点
for(int i=tree_index;i>=0;i--)
adjust_heap(data,i,num);
}

void heap_sort(int *data, int num)
{
if(num>1)
{
build_heap(data,num);
do
{
std::swap(data[0],data[--num]);
adjust_heap(data,0,num);
}while(num>1);
}
}

int main(int argc, char** argv) {
int *data=rand_seq(20);
print(data,20);
heap_sort(data,20);
print(data,20);
delete[] data;
return 0;
}





快速排序

算法总结:在冒泡排序法中,把一个元素移动到它的正确位置,需要许多次与相邻元素交换,往往很多交换都不是必须的。作为改进,快速排序法每次找到元素的正确位置,并交换,而且采用分治策略,将数据分成两部分。更贴切第讲:每次选定一个元素,将数据分成大于和小于等于该元素的两部分,再对两部分进一步快速排序。
实现代码:
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <iterator>

int * rand_seq(int num)
{
int *tem=new int[num];
srand((unsigned)time(NULL));
for(int i=0;i<num;i++) tem[i]=rand()%100;
return tem;
}
void print(int *data,int num)
{
std::copy(data,data+num,std::ostream_iterator<int>(std::cout,"  "));
std::cout<<std::endl;
}
//start、end分别是排序的起始索引
void quick_sort(int *data,int start,int end)
{
if(start<end)//迭代终止条件start==end
{
int tem=data[start];//临时变量
int left=start;
int right=end;
while(left<right)
{
//找得到小于等于tem的数,由于tem=data[start],所以不会越界
while(data[right]>tem) --right;
while(left<right&&data[left]<=tem) ++left;//找到大于tem的数
if(left<right)	std::swap(data[left],data[right]);
}
if(data[right]<tem)std::swap(data[right],data[start]);
quick_sort(data,start,right-1);
quick_sort(data,right+1,end);
}
}

int main(int argc, char** argv) {
int *data=rand_seq(20);
print(data,20);
quick_sort(data,0,19);
print(data,20);
delete[] data;
return 0;
}


归并排序

算法总结:我们常用的归并实际上是折半归并排序,它也是采用了分治策略,将要排序的序列均分成两份,每一份分别进行归并排序后,再将排序的两个序列合并在一起,形成有序的整体序列。

实现代码:
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <iterator>
#include <climits>

int * rand_seq(int num)
{
int *tem=new int[num];
srand((unsigned)time(NULL));
for(int i=0;i<num;i++) tem[i]=rand()%100;
return tem;
}
void print(int *data,int num)
{
std::copy(data,data+num,std::ostream_iterator<int>(std::cout,"  "));
std::cout<<std::endl;
}

void merge(int *data,int start,int mid,int end)
{
int *left=new int[mid-start+2];//需要用到额外空间
int *right=new int[end-mid+1];
for(int i=0;i<mid-start+1;i++) left[i]=data[start+i];
left[mid-start+1]=/*~(1<<31)*/INT_MAX;
for(int i=0;i<end-mid;i++)  right[i]=data[mid+1+i];
right[end-mid]=/*~(1<<31)*/INT_MAX;
int i=0;
int j=0;
while(start<=end)//注意合并已序序列的过程
{
if(left[i]<right[j]) data[start++]=left[i++];
else data[start++]=right[j++];
}
delete[] left;
delete[] right;
}

void merge_sort(int *data,int start,int end)
{
if(start<end)
{
int mid=(start+end)/2;
merge_sort(data,start,mid);//分别归并排序
merge_sort(data,mid+1,end);
merge(data,start,mid,end);//合并已序序列
}
}

int main(int argc, char** argv) {
int *data=rand_seq(20);
print(data,20);
merge_so
4000
rt(data,0,19);
print(data,20);
delete[] data;
return 0;
}


基数排序

算法总结:基数排序一种独特的排序方式,它是建立的数字的表示方式上的,基本思想:对一组数,先对各位排序,再对十位排序,百位...。这样,对于十进制的数,可以定义是个容器,该过程就可以描述成:分别按由低到高为放入容器,取出容器。
实现代码:
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <iterator>

int * rand_seq(int num)
{
int *tem=new int[num];
srand((unsigned)time(NULL));
for(int i=0;i<num;i++) tem[i]=rand()%100;
return tem;
}
void print(int *data,int num)
{
std::copy(data,data+num,std::ostream_iterator<int>(std::cout,"  "));
std::cout<<std::endl;
}

//数据data的pos位上的数
int pos_num(int data,int pos)
{
int tem=1;
for(int i=1;i<pos;i++) tem*=10;
return (data/tem)%10;
}

//容器类型
struct container
{
int num;
int *data;
};

void radix_sort(int *data,int num)
{
container con[10];
for(int i=0;i<10;i++)//清空容器
{
con[i].data=new int[num];
con[i].num=0;
}
for(int k=1;k<=2;k++)//每一位分别处理
{
for(int i=0;i<num;i++)//装入容器
{
int pos=pos_num(data[i],k);
con[pos].data[con[pos].num++]=data[i];
}
//清空容器
int tem=0;
for(int i=0;i<10;i++)
{
int con_data_num=con[i].num;
for(int j=0;j<con_data_num;j++)	data[tem++]=con[i].data[j];
con[i].num=0;
}
}
}

int main(int argc, char** argv) {
int *data=rand_seq(20);
print(data,20);
radix_sort(data,20);
print(data,20);
delete[] data;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐