排序算法-快速排序和堆排序
一:快速排序算法
快速排序在平均状况下,排序 n 个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。
快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。
算法步骤:
1 从数列中挑出一个元素,称为 “基准”(pivot),
2 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
3 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
在实现过程中,最后才对初始关键字赋值,注意交换过程中赋值下标顺序的正确性。
#include "iostream.h"
void Qsort(int a[],int low,int high)
{
int pivot,privotloc;
int first,last;
if(low>=high)
{
return;
}
first=low;last=high;
pivot=a[first];
while(first<last)
{
while(first<last&&a[last]>=pivot)--last;
a[first]=a[last]; //比初始关键字小的移到数组前面
while(first<last&&a[first]<=pivot)++first;
a[last]=a[first]; //比初始关键字小的移到数组末端
}
a[first]=pivot; //初始关键字将数组分成两部分后,记录位置
privotloc=first;
Qsort(a,low,privotloc-1); //递归实现前半区
Qsort(a,privotloc+1,high); //递归实现后半区
}
void main()
{
int b[8]={49,38,65,97,76,13,27,49}; //实例
Qsort(b,0,7);
for(int i = 0; i <8; i++)
{
cout <<b[i]<<endl;
}
}
二:堆排序算法
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
堆排序的平均时间复杂度为Ο(nlogn) 。
算法步骤:
- 创建一个堆H[0..n-1]
- 把堆首(最大值)和堆尾互换
3. 把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置
4. 重复步骤2,直到堆的尺寸为1
编写代码时,出现了很多次错误,原因主要是:数组实现时,下标从0开始的,多处地方的下标没注意导致数组越界。
#include "iostream.h"
void heapadjust(int a[],int s,int m)
{
int temp=a[s];
for(int j=2*s+1;j<m-1;j=j*2)
{
if(j<(m-1)&&a[j]<a[j+1])++j; //子节点中较大的一个
if(temp>a[j]) break; //temp插入到此处
a[s]=a[j]; //不满足堆定义,交换
s=j;
}
a[s]=temp; //插入
}
void heapsort(int a[],int len)
{
int temp;
for(int i=len/2-1;i>=0;--i) //建立初始的大顶堆
{
heapadjust(a,i,len);
}
for(i=len-1;i>0;--i)
{
temp=a[0];
a[0]=a[i];
a[i]=temp; //堆顶与未排序的最后一个记录交换
heapadjust(a,0,i); //重新调整为大顶堆
}
}
void main()
{
int b[8]={49,38,65,97,76,13,27,49};
heapsort(b,8);
for(int i = 0; i <8; i++)
{
cout <<b[i]<<endl;
}
}