排序算法
来源:互联网 发布:ae软件下载官方中文版 编辑:程序博客网 时间:2024/06/08 11:35
排序
4.1 插入排序
4.1.1简单插入排序
将一个记录插入到已排好序的有序表中,从而得到一个新的、记录数增1的有序表。
实现方法:把第n个元素与第n-1个元素进行比较,在这次比较中,如果第n个元素要小,则把第n-1个元素向后移一位。这样直到比第n个元素小时才结束。
void insertsort(int a[],int n)
{
int i,j;
int tmp;
for(i=1;i<n;i++)
{
tmp=a[i];
j=i-1;
while(tmp<a[j])
{
a[j+1]=a[j];
j--;
}
a[j+1]=tmp;
}
}
4.1.2 二路插入排序
用二分查找的方法找到要插入的位置,然后把该位置后的元素都后移一位,把添加的元素插入到该位置。要主要后移时结束条件为:i>=low.
void BInsertsort(int a[],int n)
{
int low,high,k,tmp,m; //low,high表示当前循环中最前一个位置和最后一个位置,k表示插入第几个元素
for(k=1;k<n;k++)
{
low=0;
high=k-1;
tmp=a[k];
while(low<=high)
{
m=(low+high)/2;
if(tmp>a[m])
low=m+1;
else
high=m-1;
}
for(inti=k-1;i>=low;i--)
a[i+1]=a[i];
a[low]=tmp;
}
}
4.1.3希尔排序
先把整个待排元素序列分割为若干个子序列(距离为“增量”),在子序列上进行直接插入排序,然后再缩减增量,待整个序列中的元素基本有序时,再对全体元素进行一次插入排序。
void shellsort(int a[],int n)
{
int i,j;
int tmp;
int gap=n/2;
while(gap>0)
{
for(i=gap;i<n;i++)
{
tmp=a[i];
j=i-gap;
while(j>=0&&tmp<a[j])
{
a[j+gap]=a[j];
j-=gap;
}
a[j+gap]=tmp;
}
gap/=2;
}
}
4.2 交换排序
4.2.1冒泡排序
N个元素进行排序,两两比较待排序的元素,发现两个元素的次序相反时即进行交换,重复n-1次。
void bubblesort(int a[],int n)
{
int i,j,tmp;
for(i=0;i<n-1;i++)
for(j=n-1;j>i;j--)
{
if(a[j-1]>a[j])
{
tmp=a[j];
a[j]=a[j-1];
a[j-1]=tmp;
}
}
}
4.2.2快速排序——void quicksort(int a[],int low,int high)
通过一趟排序将待排元素分割成独立的两部分,其中一部分的元素都比另一部分小,则分别对这两部分进行排序,最后达到整体有序。
使用了递归的方法。
void quicksort(int a[],int low,int high)
{
int i,j,tmp;
i=low;
j=high;
if(low<high)
{
tmp=a[low];
while(low<high)
{
while(low<high&&a[high]>=tmp)
high--;
a[low]=a[high];
while(low<high&&a[low]<=tmp)
low++;
a[high]=a[low];
}
a[low]=tmp;
quicksort(a,i,low-1);
quicksort(a,low+1,j);
}
}
4.3 选择排序
4.3.1简单选择排序
思想:每趟从待排序元素中选出最小的一个元素,顺序放在已排好序的末尾。
实现方法:假设位置i后再没有比位置i上的元素大的元素,遍历i+1到n-1,查找是否有比a[i]小的元素,若有就交换位置。
void selectsort(int a[],int n)
{
int i,j,k,tmp;
for(i=0;i<n;i++)
{
k=i;
for(j=i+1;j<n;j++)
{
if(a[j]<a[k])
k=j;
}
if(k!=i)
{
tmp=a[k];
a[k]=a[i];
a[i]=tmp;
}
}
}
4.3.2堆排序——两个函数voidheapadjust(int d[],int ind, int len);Voidheapsort(inta[],int n)
对heapsort函数,先对原数组建立大顶堆,再遍历数组依次交换a[0]与a[n-j-1],最后对a[0]~a[n-j-1]建立大顶堆。建立大顶堆的目的是把数组中最大的元素放到a[0]位置上。
对heapadjust函数,先找到顶点i和其左孩子节点2*i+1,左孩子未遍历到数组末尾时判断是否存在右孩子节点,如果存在且右孩子节点大于左孩子节点,则左孩子下标加1(得到要被交换的节点),判断要被交换的节点是否比父节点i大,大则交换两者值,再设置父节点和左孩子节点。
//#筛选算法#%
void heapadjust(int d[],int ind,int len)
{
//#置i为要筛选的节点#%
int i = ind;
//#c中保存i节点的左孩子#%
int c = i * 2+ 1; //#+1的目的就是为了解决节点从0开始而他的左孩子一直为0的问题#%
while(c< len)//#未筛选到叶子节点#%
{
//#如果要筛选的节点既有左孩子又有右孩子并且左孩子值小于右孩子#%
//#从二者中选出较大的并记录#%
if(c+ 1 < len && d[c] <d[c+ 1])
c++;
//#如果要筛选的节点中的值大于左右孩子的较大者则退出#%
if(d[i]> d[c])break;
else
{
//#交换#%
int t = d[c];
d[c]= d[i];
d[i]= t;
//
//#重置要筛选的节点和要筛选的左孩子#%
i = c;
c = 2 * i +1;
}
}
return;
}
void heapsort(int d[],int n)
{
//#初始化建堆, i从最后一个非叶子节点开始#%
for(inti = (n - 2) / 2; i>= 0; i--)
heapadjust(d, i, n);
for(int j= 0; j< n; j++)
{
//#交换#%
int t = d[0];
d[0]= d[n- j -1];
d[n - j -1] = t;
//#筛选编号为0 #%
heapadjust(d,0, n- j -1);
}
}
4.4 归并排序voidMerge(int r[],int r1[],int s,int m,int t); void MergeSort(int r[],int r1[],int s,int t)
采用分治算法,即将一组元素通过几次平分,分成若干组元素(最终单个元素为一组),这样就形成了一个满二叉树形结构,叶子节点为单个元素,归属于同一个父节点的两组元素排序后归并成一组元素,最终归属于根节点的两组元素再次归并成一组元素。
void Merge(int r[],int r1[],int s,int m,int t)
{
int i=s;
int j=m+1;
int k=s;
while(i<=m&&j<=t)
{
if(r[i]<=r[j])
r1[k++]=r[i++];
else
r1[k++]=r[j++];
}
if(i<=m)
while(i<=m)
r1[k++]=r[i++];
else
while(j<=t)
r1[k++]=r[j++];
for(int n=s;n<=t;n++)
r[n]=r1[n];
}
void MergeSort(int r[],int r1[],int s,int t)
{
if(s<t)
{
int m=(s+t)/2; //a[8],函数调用MergeSort(a,b,0,7)
MergeSort(r,r1,s,m);
MergeSort(r,r1,m+1,t);
Merge(r,r1,s,m,t);
}
}
4.5 基数排序intmaxbit(int data[],int n); void radixsort(intdata[],int n)
思想: 是一种借助多关键字排序的思想对单逻辑关键字进行排序的方法,又称为“桶子法”,即通过键值,将要排序的元素分配到某些“桶”中。
实现方法:
最低位优先(LSD)方法——即从低位向高位排序
将整形10进制按每位拆分,然后从低位到高位依次比较各个位。主要分为两个过程:
(1)分配,先从个位开始,根据位值(0-9)分别放到0~9号桶中(比如53,个位为3,则放入3号桶中)
(2)收集,再将放置在0~9号桶中的数据按顺序放到数组中
重复(1)(2)过程,从个位到最高位(比如32位无符号整形最大数4294967296,最高位10位)
//这里求数组中元素的最大位数的方法很好
int maxbit(int data[],int n)//辅助函数,求数据的最大位数
{
int d =1;//保存最大的位数
int p =10;
for(int i= 0;i< n;++i)
{
while(data[i]>= p)
{
p *= 10;
++d;
}
}
return d;
}
void radixsort(int data[],int n)//基数排序
{
int d = maxbit(data,n);
int * tmp= new int[n];
int * count= new int[10];//计数器
int i,j,k;
int radix =1;
for(i= 1; i<= d;i++)//进行d次排序
{
for(j= 0;j< 10;j++)
count[j]= 0;//每次分配前清空计数器
for(j= 0;j< n; j++)
{
k = (data[j]/radix)%10;//统计每个桶中的记录数
count[k]++;
}
for(j= 1;j< 10;j++)
count[j]= count[j-1]+ count[j];//将tmp中的位置依次分配给每个桶,因为相同的某一位可能有几个数,所以要用递增的形式计算下标
for(j =n-1;j>= 0;j--) //将所有桶中记录依次收集到tmp中
{
k = (data[j]/radix)%10;
tmp[count[k]-1] = data[j];
count[k]--;
}
for(j= 0;j< n;j++)//将临时数组的内容复制到data中
data[j]= tmp[j];
radix = radix*10;
}
delete [] tmp;
delete [] count;
}
4.6 排序算法比较
数据原始状态对排序的影响:
1) 当原表有序或基本有序时,插入排序(简单插入排序、二路插入排序、希尔排序)和冒泡排序将大大减少比较次数和移动记录的次数,时间复杂度可降至O(n);
2) 而快速排序则相反,当原表基本有序时,将蜕化为冒泡排序,时间复杂度提高为O(n2);
3) 原表是否有序,对选择排序(简单选择排序、堆排序)、归并排序和基数排序的时间复杂度影响不大。
4) 所有选择排序都是不稳定的且不受原表顺序的影响。
其它总结:
1) 从平均时间性能而言,快速排序最佳,所需时间最省,但在最坏的情况下,时间性能不如堆排序和归并排序,后两者相比较的结果是,在n比较大时,归并排序所需时间较堆排序省,但所需辅助存储量最多。
2) 简单排序包括:除希尔排序外的所有插入排序、冒泡排序和简单选择排序。
3) 基数排序的时间复杂度也可以写成O(d*n)。因此,它最适合n值很大而关键字较小的序列。
4) 基数排序是稳定的内排方法,所有时间复杂度为O(n2)的简单排序法都是稳定的。快速排序、堆排序和希尔排序等时间性能较好的排序方法都是不稳定的。一般来说,排序过程中的“比较”是在“相邻的两个记录关键字”间进行的排序方法是稳定的。稳定性由方法本身决定。
稳定:除希尔排序外的所有插入排序、冒泡排序、归并排序和基数排序;
不稳定:希尔排序,所有选择排序(简单选择排序和堆排序)、快速排序。
影响:插入排序和交换排序
不影响:选择排序,归并排序和基数排序
引用的文章
http://www.cnblogs.com/mengdd/archive/2012/11/30/2796845.html
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 比较纠结的逻辑判断
- Ubuntu Server 10.10 DNS服务器的配置方法
- poj 1014 Dividing (搜索:DFS)
- Object-c基础编程学习笔记-NSString
- linux上安装tomcat,配置tomcat服务开机自启动
- 排序算法
- 学习Spring必学的Java基础知识(5)----注解
- 自定义实现RatingBar
- 下面这个专题我想主要总结一些各种不同的排序
- 限制恶意轰炸注册的妙招
- 测试用例设计白皮书--边界值分析方法
- Android上的否认和欺骗
- 模板消息接口文档
- OK6410(s3c6410)存储之MMU(内存管理单元)