排序方法分为两大类:内部排序和外部排序
内部排序分为插入排序、选择排序、交换排序、归并排序、基数排序
1.插入排序
将一个记录插入到已排好序的有序表中,从而得到一个新的、记录数增1的有序表。
此处采用不用哨兵位的方法:
void InsertSort(int arr[],int len)
{
for(int i=1;i<len;i++) //默认第一个元素已经排好序
{
for(int j=i-1;j>=0 && tmp<arr[j];j--)
{
arr[j+1]=arr[j];
}
arr[j+1]=tmp;
}
}
时间复杂度:
元素已经排好序时,时间复杂度为O(n)
元素是逆序时的时间复杂度为O(n^2)
因此直接插入排序的平均时间复杂度为O(n^2)
空间复杂度:O(1)
稳定性:稳定
折半插入排序查找速度快,但移动时还是得遍历元素,记录的移动次数不变,仅仅优化了查找过程,所以时间复杂度还是O(n^2).
2.希尔排序
先将整个待排记录序列分割成为若干个子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。
希尔排序需要设置增量,但各增量要互素,并且最后一个增量值必须等于1,目前一般设置为5,3,1
void Shell(int *arr,int arr_len,int dk)
{
for(int i=dk;i<arr_len;i++)
{
tmp=arr[i];
for(int j=i-dk;j>=0 && tmp<arr[j];j-=dk)
{
arr[j+dk]=arr[j];
}
arr[j+dk]=tmp;
}
}
void ShellSort(int*arr,int arr_len,int dka[],int dka_len)
{
for(int i=0;i<dka_len;i++)
{
Shell(arr,arrr_len,dka[i]);
}
}
int main()
{
int dk[3]={5,3,1};
int arr[]={5,2,6,8,7,6,1,3};
ShellSort(arr,sizeof(arr)/sizeof(arr[0]),dka,
sizeof(dka)/sizeof(dka[0]));
for(int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
{
printf("%d ",arr[i]);
}
return 0;
}
时间复杂度 O(n^1.3)
空间复杂度O(1)
稳定性:不稳定
只要有跳跃式交换则数据就不稳定
3.选择排序
通过n-i次关键字间的比较,从n-i-1个记录中选出关键字最小的记录,并和第i个交换。
void SelectSort(int arr[],int len)
{
int min;
int tmp;
for(int i=0;i<len;i++)
{
min=i;
for(int j=i+1;j<len;j++)
{
if(arr[min]>arr[j])
{
min=j;
}
}
tmp=arr[min];
arr[min]=arr[i];
arr[i]=tmp;
}
}
时间复杂度 O(n^2)
空间复杂度O(1)
稳定性:不稳定
4.堆排序
先建一个“大顶堆”,选出一个关键字为最大的记录并与序列中最后一个记录交换。然后将前n-1个序列调整为“大顶堆”,如此反复直到排序结束。
void HeapAdjust(int *arr,int i,int len)
{
int max=arr[i];
for(int j=2*i;j<len;j++) // 从最后一个父节点开始调整
{
if(arr[j]<arr[j+1] && j<len)
{
j++;
}
if(max > arr[j])
{
break;
}
arr[i]=arr[j];
arr[j]=max;
i=j;//修改i的值,重复进行调整
}
}
void HeapSort(int *arr,int len)
{
for(int i=len/2;i>0;i--)
{
HeapAdjust(arr,i,len-1);
}
for(int j=len-1;j>0;j--)//与最大的值进行交换,如此反复
{
int tmp=arr[1];
arr[1]=arr[j];
arr[j]=tmp;
HeapSort(arr,1,j-1);//每次从第一个开始进行“大顶堆”排序
}
}
时间复杂度:O(nlogn)
空间复杂度:O(1)
稳定性:不稳定
5.冒泡排序
每次将相邻两个数比较,将小的调到前面。
void Bubblesort(int *arr,int len)
{
int tmp;
for(int i=0;i<len-1;i++)
{
for(int j=0;j<len-1-i;j++)
{
if(arr[j] > arr[j+1])
{
tmp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=tmp;
}
}
}
}
时间复杂度O(n^2)
空间复杂度O(1)
稳定性:稳定
6.归并排序
首先每个子序列的长度为1,然后两两合并,再两两合并……直至得到一个长度为n的有序序列为止。
void Merge(int arr[],int tmp,int startindex,int midindex,int endindex)
{
int i=startindex;
int j=midindex+1;
int k=startindex;
while(i!=midindex+1 && j!=endindex+1)
{
if(arr[j] > arr[i])
{
tmp[k++]=arr[i++];
}
else
{
tmp[k++]=arr[j++];
}
}
while(i != midindex+1)
{
tmp[k++]=arr[i++];
}
while(j != endindex+1)
{
tmp[k++]=arr[j++];
}
for(int i=startindex;i<endindex+1;i++)
{
arr[i]=tmp[i];
}
}
void MergeSort(int arr[],int tmp[],int startindex,int endindex)
{
if(startindex < endindex)
{
int minindex=(startindex + endindex)/2;
Merge(arr,tmp,startindex,midindex);
Merge(arr,tmp,midindex+1,endindex);
MergeSort(arr,tmp,startindex,midindex,endindex);
}
}
时间复杂度:O(nlogn)
空间复杂度:O(n)
稳定性:稳定