if(k!
=i)
{
temp=a[i];
a[i]=a[k];
a[k]=temp;
}
}
}
4.归并排序
归并排序(Mergingsort),所谓归并,简单的讲,就是将两个有序的序列,合成一个新的有序表。
我们用这个思想,可以把一个n个元素的序列,看成n个长度为1的子序列,然后利用归并排序,两两合并,然后的到了n/2个长度为2的子序列,再次进行合并,重复上面的步骤,直到合并为一个序列,则归并完成。
归并排序的时间复杂度无论是在最好情况下还是在最坏情况下均是O(nlog2n)。
归并排序是稳定的排序算法
//将有序序列a[low..mid]和a[mid+1..high]归并到a[low..high]。
voidMerge(inta[],intlow,intmid,inthigh)
{
//归并到b[]
inti=low;
intj=mid+1;
intk=0;
int*b=newint[high-low+1];
while(i<=mid&&j<=high)
{
if(a[i]<=a[j]){b[k++]=a[i++];}
else{b[k++]=a[j++];}
}
//归并剩余元素
while(i<=mid)b[k++]=a[i++];
while(j<=high)b[k++]=a[j++];
//从b[]复制回a[]
for(i=0;i<=high-low;++i)
a[low+i]=b[i];
delete[]b;
}
//归并排序
//http:
//en.wikipedia.org/wiki/Mergesort
voidMergeSort(inta[],intlow,inthigh)
{
if(low>=high)return;
else
{
intmid=(low+high)/2;
MergeSort(a,low,mid);
MergeSort(a,mid+1,high);
Merge(a,low,mid,high);
}
}
//自底向上的归并排序
voidMergeSort2(inta[],intn)
{
ints,i,t=1;
while(t{
s=t;t=s*2;
for(i=0;i+t<=n;i+=t)
Merge(a,i,i+s-1,i+t-1);
if(i+sMerge(a,i,i+s-1,n-1);
}
}
归并排序在最坏的情况下都是O(NlogN)的时间复杂度,缺点是Merge的时候要有O(N)的额外的空间,如何改进?
//reversearray
voidreverse(intarr[],intsize)
{
intleft=0;
intright=size-1;
while(left{
inttemp=arr[left];
arr[left++]=arr[right];
arr[right--]=temp;
}
}
//swap[arr,arr+headSize)and[arr+headSize,arr+headSize+endSize)
voidSwapMemory(intarr[],intheadSize,intendSize)
{
reverse(arr,headSize);
reverse(arr+headSize,endSize);
reverse(arr,headSize+endSize);
}
//原地归并
voidInplace_Merge(intarr[],intbeg,intmid,intend)
{
inti=beg;//指示有序串1
intj=mid+1;//指示有序串2
while(i{
while(i{
++i;
}
intindex=j;
while(j<=end&&arr[j]<=arr[i])
{
++j;
}
SwapMemory(&arr[i],index-i,j-index);//swap[i,index)and[index,j)
i+=(j-index);
}
}
//原地归并排序
voidInplace_MergeSort(intarr[],intbeg,intend)
{
if(beg{
intmid=(beg+end)/2;
Inplace_MergeSort(arr,beg,mid);
Inplace_MergeSort(arr,mid+1,end);
Inplace_Merge(arr,beg,mid,end);
}
}
5.冒泡排序(BubbleSort)
冒泡排序方法是最简单的排序方法。
这种方法的基本思想是,将待排序的元素看作是竖着排列的“气泡”,较小的元素比较轻,从而要往上浮。
在冒泡排序算法中我们要对这个“气泡”序列处理若干遍。
所谓一遍处理,就是自底向上检查一遍这个序列,并时刻注意两个相邻的元素的顺序是否正确。
如果发现两个相邻元素的顺序不对,即“轻”的元素在下面,就交换它们的位置。
显然,处理一遍之后,“最轻”的元素就浮到了最高位置;处理二遍之后,“次轻”的元素就浮到了次高位置。
在作第二遍处理时,由于最高位置上的元素已是“最轻”元素,所以不必检查。
一般地,第i遍处理时,不必检查第i高位置以上的元素,因为经过前面i-1遍的处理,它们已正确地排好序。
冒泡排序是稳定的。
算法时间复杂度是O(n^2)。
//冒泡排序(相邻比较法)
voidBubbleSort(inta[],intn)
{
inti,j;
inttemp;
for(i=0;ifor(j=0;jif(a[j]>a[j+1])
{
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
//改进的冒泡排序
voidImprovedBubbleSort(inta[],intn)
{
inti,j;
inttemp;
boolchange=false;
for(i=0;i{
change=false;
for(intj=0;jif(a[j]>a[j+1])
{
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
change=true;
}
if(!
change)break;
}
}
//双向冒泡排序(鸡尾酒排序)
voidCocktailSort(inta[],intn)
{
inttop=n-1;
intbottom=0;
boolflag=true;
inti,j;
while(flag)
{
flag=false;
//从小到大,升序
for(i=bottom;i{
if(a[i]>a[i+1])
{
swap(a[i],a[i+1]);
flag=true;
}
}
bottom++;
//从大到小,降序
for(j=top;j>bottom;j--)
{
if(a[j]{
swap(a[j],a[j-1]);
flag=true;
}
}
top--;
}
}
6.希尔排序(ShellSort)
先将待排序列分割成若干个子序列,分别进行直接插入排序,基本有序后再对整个序列进行直接插入排序。
希尔排序是不稳定的。
时间复杂度大约为O(n^3/2)。
//希尔排序:
shell排序的核心仍然使用插入排序
voidShellSort(inta[],intn)
{
intdk=n/2;
inti,j;
while(dk>=1)
{
//一趟希尔排序,对dk个序列分别进行插入排序
for(i=dk;i{
intx=a[i];
for(j=i-dk;j>=0&&a[j]>x;j-=dk)
a[j+dk]=a[j];
a[j+dk]=x;
}
dk=dk/2;//缩小增量
}
}
7.堆排序(HeapSort)
堆排序是一种树形选择排序,在排序过程中,将A[n]看成是完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系来选择最小的元素。
对N个元素从小到大排序建立大根堆,然后交换堆顶与最后一个元素,将剩下的N-1个元素调整为大根堆,执行N-1此这样的操作。
堆排序是不稳定的。
算法时间复杂度O(nlogn)。
//调整大根堆
voidHeapAdjust(intdata[],intnStart,intnLen)
{
intnMaxChild=0;
intTemp;
while((2*nStart+1){
nMaxChild=2*nStart+1;
if((2*nStart+2){
//比较左子树和右子树,记录最大值的Index
if(data[2*nStart+1]{
nMaxChild=2*nStart+2;
}
}
//changedata
if(data[nStart]{
//交换nStart与nMaxChild的数据
Temp=data[nStart];
data[nStart]=data[nMaxChild];
data[nMaxChild]=Temp;
//堆被破坏,需要重新调整
nStart=nMaxChild;
}
else
{
//比较左右孩子均小则堆未破坏,不再需要调整
break;
}
}
}
//堆排序从小到大排序建立大顶堆
voidHeapSort(intdata[],intnLen)
{
inti;
intnTemp;
//建立堆
for(i=nLen/2-1;i>=0;i--)
{
HeapAdjust(data,i,nLen);
}
for(i=nLen-1;i>0;i--)
{
//交换堆顶元素和最后一个元素
nTemp=data[0];
data[0]=data[i];
data[i]=nTemp;
//将data[0...i]重写建成大根堆
HeapAdjust(data,0,i);
}
}
三、详细设计
四、调试分析
五、用户手册
六、测试结果
七、附录