直接插入排序
平均情况:O(n*n) 最好情况:O(n) 最坏情况:O(n*n) 辅助空间:O(1) 稳定性:稳定
对第i+1位置上的数,将其插入前i个有序数组中,插入以后形成新的有序数组。
#include <iostream>
using namespace std;
void insert_sort(int arr[],int len)
{
int i,j,temp;
for (i=1;i<len;i++)
{
temp=arr[i];
for (j=i-1;j>=0&&temp<arr[j];j--)
arr[j+1]=arr[j];
arr[j+1]=temp;
}
}
void print_array(int a[],int len)
{
for(int i=0;i<len;i++)
cout<<a[i]<<" ";
}
void main()
{
int a[]={7,3,5,8,9,1,2,4,6};
insert_sort(a,9);
print_array(a,9);
}
希尔排序
由于分组的存在,相等的元素可能会分在不同组,导致它们的次序可能发生变化,因此 稳定性:不稳定 .
当待排序的记录较少或基本有序时,直接插入排序的优势比较明显,但在现实中满足这两个条件很难。如何让待排序的记录个数较少呢?方法:将记录分组,分割成若干个子序列,此时每个子序列待排序的记录个数就比较少了,在子序列内部进行直接插入排序。当整个序列都基本有序时,再对全体记录进行一次直接插入排序。
#include <iostream>
using namespace std;
void shell_sort(int arr[],int len)
{
int i,j,temp,d;
for (d=len/2;d>0;d/=2) //控制增量
{
for (i=d;i<len;i++) //这个for循环就是前面的直接插入排序
{
temp=arr[i];
for (j=i-d;j>=0&&temp<arr[j];j-=d)
arr[j+d]=arr[j];
arr[j+d]=temp;
}
}
}
void print_array(int a[],int len)
{
for(int i=0;i<len;i++)
cout<<a[i]<<" ";
}
void main()
{
int a[]={7,3,5,8,9,1,2,4,6};
shell_sort(a,9);
print_array(a,9);
}
冒泡排序
平均情况:O(n*n) 最好情况:O(n) 最坏情况:O(n*n) 辅助空间:O(1) 稳定性:稳定
根据轻气泡不能在重气泡之下的原则,从下往上扫描数组,凡扫描到较轻气泡,就使其向上"漂浮"。
#include <iostream>
using namespace std;
void bubble_sort(int arr[],int len)
{
int i=0,j=0,temp;
int exchange=0; //用于记录每次扫描时是否发生交换
for (i=0;i<len-1;i++)
{
exchange=0;
for (j=len-2;j>=i;j--)
{
if (arr[j+1] < arr[j])
{
temp=arr[j+1];
arr[j+1]=arr[j];
arr[j]=temp;
exchange=1;
}
}
if(exchange != 1)
return;
}
}
void print_array(int a[],int len)
{
for(int i=0;i<len;i++)
cout<<a[i]<<" ";
}
void main()
{
int a[]={7,3,5,8,9,1,2,4,6};
bubble_sort(a,9);
print_array(a,9);
}
快速排序
平均情况:O(nlogn) 最好情况:O(nlogn) 最坏情况:O(n*n) 稳定性:不稳定
选择一个记录作为基准,将小于此记录的划分到左区间,将大于次记录的划分到右区间.
#include <iostream>
using namespace std;
void qsort(int array[],int len)
{
int start,end,value;
if(len <= 1)
return;
start=0;
end=len-1;
value=array[0];
while(start < end)
{
for (;start<end;end--)
{
if(array[end] < value)
{
array[start++]=array[end];
break;
}
}
for (;start<end;start++)
{
if(array[start] > value)
{
array[end--]=array[start];
break;
}
}
}
array[start]=value;
qsort(array,start);
qsort(array+start+1,len-start-1);
}
void print_array(int a[],int len)
{
for(int i=0;i<len;i++)
cout<<a[i]<<" ";
}
void main()
{
int a[]={7,3,5,8,9,1,2,4,6};
qsort(a,9);
print_array(a,9);
}
选择排序
平均情况:O(n*n) 最好情况:O(n*n) 最坏情况:O(n*n) 辅助空间:O(1) 稳定性:不稳定
对当前第i个位置上的数,选择数组中从i到末尾最小的数字与其交换
#include <iostream>
using namespace std;
void select_sort(int arr[],int len)
{
int i,j,min,pos;
for (i=0;i<=len-2;i++)
{
min=arr[i];
pos=i;
for (j=i+1;j<len;j++)
{
if(arr[j] < min)
{
min=arr[j];
pos=j;
}
}
arr[pos]=arr[i];
arr[i]=min;
}
}
void print_array(int a[],int len)
{
for(int i=0;i<len;i++)
cout<<a[i]<<" ";
}
void main()
{
int a[]={7,3,5,8,9,1,2,4,6};
select_sort(a,9);
print_array(a,9);
}
堆排序
平均情况:O(nlogn) 最好情况:O(nlogn) 最坏情况:O(nlogn) 辅助空间:O(1) 稳定性:不稳定
在测试代码中为大根堆,所有子节点都小于其父节点。堆,实质上是满足如下性质的完全二叉树:树中任一非叶结点的关键字均不小于(或不大于)其左右子节点(若存在)的关键字。排序两大部分:初始建堆和堆重建。堆顶元素arr[0](数组的最大值)被置换到数组的尾部,故需要堆重建。
#include <iostream>
using namespace std;
int heapSize=0;
int Left(int index){return (index<<1)+1;}
int Right(int index){return (index<<1)+2;}
void Swap(int* a,int* b){int temp=*a;*a=*b;*b=temp;}
void maxHeapify(int arr[],int index)
{
int largest=0;
int left=Left(index);
int right=Right(index);
if(left<=heapSize && arr[left]>arr[index])
largest=left;
else
largest=index;
if(right<=heapSize && arr[right]>arr[largest])
largest=right;
if(largest != index)
{
Swap(&arr[index],&arr[largest]);
maxHeapify(arr,largest);
}
}
void buildMaxHeap(int arr[],int len)
{
heapSize=len;
int i;
for(i=(len>>1);i>=0;i--)
maxHeapify(arr,i);
}
void heap_sort(int arr[],int len)
{
int i;
buildMaxHeap(arr,len-1);
for (i=len-1;i>=1;i--)
{
Swap(&arr[0],&arr[i]);
heapSize--;
maxHeapify(arr,0);
}
}
void print_array(int a[],int len)
{
for(int i=0;i<len;i++)
cout<<a[i]<<" ";
}
void main()
{
int a[]={7,3,5,8,9,1,2,4,6};
heap_sort(a,9);
print_array(a,9);
}
归并排序
平均情况:O(nlogn) 最好情况:O(nlogn) 最坏情况:O(nlogn) 辅助空间:O(n) 稳定性:稳定
归并是指将若干个已排序的子文件合并为一个有序的文件。归并排序有两种实现方法:自底向上和自顶向下。本文介绍自顶向下的“二路归并排序”,设归并排序的当前区间是A[low,high],步骤如下:
(1)分解:将当前区间一分为二,即求分裂点;
(2)求解:递归地对两个子区间A[low,mid]和A[mid+1,high]进行归并排序;
(3)组合:将已排序的两个子区间归并为一个有序的区间R[low,high];
(4)递归的终止条件:子区间长度为1。
#include <iostream>
using namespace std;
void Merge(int arr[],int tmp[],int lPos,int rPos,int rEnd)
{
int i,lEnd,numElements,tmpPos;
lEnd=rPos-1;
tmpPos=lPos;
numElements=rEnd-lPos+1;
while(lPos<=lEnd && rPos<=rEnd)
{
if(arr[lPos] <= arr[rPos])
tmp[tmpPos++]=arr[lPos++];
else
tmp[tmpPos++]=arr[rPos++];
}
//到这里,左端或右端还可能含有剩余元素(只可能有一端剩余)
while(lPos <= lEnd)
tmp[tmpPos++]=arr[lPos++];
while(rPos <= rEnd)
tmp[tmpPos++]=arr[rPos++];
for(i=0;i<numElements;i++,rEnd--)
arr[rEnd]=tmp[rEnd];
}
void msort(int arr[],int tmp[],int low,int high)
{
if(low >= high)
return;
int middle=(high+low)/2;
msort(arr,tmp,low,middle);
msort(arr,tmp,middle+1,high);
Merge(arr,tmp,low,middle+1,high);
}
void merge_sort(int arr[],int len)
{
int* tmp=new int[len];
if(tmp != NULL)
{
msort(arr,tmp,0,len-1);
delete[] tmp;
}
}
void print_array(int a[],int len)
{
for(int i=0;i<len;i++)
cout<<a[i]<<" ";
}
void main()
{
int a[]={7,3,5,8,9,1,2,4,6};
merge_sort(a,9);
print_array(a,9);
}