排序的分类:
ps:我在这里实现的排序算法,都是用数组来实现的。
1.插入排序
基本思想:将一个数插入到已排好序的数组中,从而得到一个新的,个数加1的数组。
ps:index为要插入的数的下标,pos为已排好序的数组的最后一个数的下标。
时间复杂度为:O(n^2)
void InsertSort(int* a,size_t n) //按升序
{
for(size_t index=1;index<n;++index)
{
int pos=index-1;
int tmp=a[index];
while(pos>=0&&a[pos]>tmp)
{
a[pos+1]=a[pos];
--pos;
}
a[pos+1]=tmp;
}
}
2.希尔排序
基本思想:它分为预排序和插入排序,预排序:实现跳跃性的排序。
时间复杂度为:O(nlogn)~O(n^2)
void ShellSort(int* a,size_t n)
{
//1.预排序
int gap=n;
while(gap>1)
{
gap=gap/3+1;
for(int index=gap;index<n;++index)
{
int tmp=a[index];
int pos=index-gap;
while(pos>=0&&a[pos]>tmp)
{
a[pos+gap]=a[pos];
pos-=gap;
}
a[pos+gap]=tmp;
}
}
//2.插入排序
InsertSort(a,n);
}
3.选择排序
基本思想:每一趟选出一个最小值和最大值,分别插入到左右两边的位置。
时间复杂度:O(n^2)
void SelectSort(int* a,size_t n)
{
int left=0;
int right=n-1;
int min,max;
while(left<right)
{
min=max=left;
for(size_t i=left;i<=right;++i)
{
if(a[i]<a[min])
min=i;
if(a[i]>a[max])
max=i;
}
swap(a[left],a[min]);
if(left==max)
max=min;
swap(a[right],a[max]);
left++;
--right;
}
}
4.堆排序
基本思想:将待排序的序列构成一个大堆,此时,整个序列的最大值就在堆顶,将它与堆数组的最后一位数交换,此时末尾就是最大值,将剩余的n-1个数重新调整为大堆,就会得到次大值,在交换,反复执行,就会得到一个语序序列。
时间复杂度为:O(nlogn)
void AdjustDown(int* a,int parent,size_t n) //建大堆
{
int sub=parent*2+1;
while(sub<n)
{
if(sub<n-1&&a[sub]<a[sub+1])
++sub;
if(a[sub]>a[parent])
{
swap(a[sub],a[parent]);
parent=sub;
sub=parent*2+1;
}
else
break;
}
}
void HeapSort(int* a,size_t n)
{
//建大(小)堆
for(int i=(n-2)/2;i>=0;--i)
{
AdjustDown(a,i,n);
}
//排序
for(int j=n-1;j>0;--j)
{
swap(a[0],a[j]);
AdjustDown(a,0,j);
}
}
5.冒泡排序
基本思想:亮亮比较相邻的数,如果反序就交换,知道没有反序的数为止。
时间复杂度为:0(n^2)
void BubbleSort(int* a,size_t n)
{
int flag=false;
for(int i=0;i<n-1;++i) //趟数
{
for(int j=0;j<n-1-i;++j)
{
if(a[j]>a[j+1])
{
swap(a[j],a[j+1]);
flag=true;
}
}
if(flag==false)
break;
}
}
6.快速排序
基本思想:通过一趟排序将待排序的序列分割为独立的两部分,其中一部分的值均比另一部分的值小,则可分别对这两部分值继续进行排序,以达到整个序列有序的目的。
时间复杂度为:O(nlogn)
递归的写法:
void QuickSort(int* a,int begin,int end)
{
//一趟排序
//int pivo=PartSort1(a,begin,end);
//int pivo=PartSort2(a,begin,end);
int pivo=PartSort3(a,begin,end);
if(begin<pivo-1) //不止一个数
QuickSort(a,begin,pivo-1);
if(pivo+1<end)
QuickSort(a,pivo+1,end);
}
单趟排序有三种方法:
(1).左右指针法
//左右指针法
int PartSort1(int* a,int begin,int end)
{
int left=begin;
int right=end;
//int key=a[end];
//三数取中法
int mid=GetMidNum(a,begin,end);
swap(a[mid],a[end]);
int key=a[end];
while(left<right)
{
while(left<right&&a[left]<=key)
left++;
while(left<right&&a[right]>=key)
right--;
if(left<right)
swap(a[left],a[right]);
}
swap(a[left],a[end]);
return left;
}
(2).挖坑法
//挖坑法
int PartSort2(int* a,int begin,int end)
{
//int key=a[end];
//三数取中法
int mid=GetMidNum(a,begin,end);
swap(a[mid],a[end]);
int key=a[end];
int left=begin;
int right=end;
while(left<right)
{
while(left<right&&a[left]<=key)
left++;
a[right]=a[left];
while(left<right&&a[right]>=key)
right--;
a[left]=a[right];
}
a[left]=key;
return left;
}
(3).前后指针法
//前后指针法
int PartSort3(int* a,int begin,int end)
{
int prev=begin-1;
int cur=begin;//找比key小的值就停下
int mid=GetMidNum(a,begin,end);
swap(a[mid],a[end]);
int key=a[end];
while(cur<end)
{
if(a[cur]<key&&++prev!=cur)
swap(a[prev],a[cur]);
++cur;
}
swap(a[++prev],a[end]);
return prev;
}
void QuickSortNonR(int* a,int begin,int end)
{
stack<int> s;
s.push (begin);
s.push (end);
while(!s.empty ())
{
int right=s.top ();
s.pop();
int left=s.top();
s.pop();
int pivo=PartSort1(a,left,right);
if(left<pivo-1)//不止一个数
{
s.push(left);
s.push(pivo-1);
}
if(pivo+1<end)
{
s.push(pivo+1);
s.push(end);
}
}
}
7.归并排序
时间复杂度为:O(nlogn)
void _MergeSort(int* a,int* tmp,int begin,int end)
{
int mid=begin+(end-begin)/2;
if(begin<mid) //不止一个数
{
_MergeSort(a,tmp,begin,mid);
}
if(mid+1<end)
{
_MergeSort(a,tmp,mid+1,end);
}
int begin1=begin;
int end1=mid;
int begin2=mid+1;
int end2=end;
int index=begin;
while(begin1<=end1&&begin2<=end2) //两个数组都不为空
{
if(a[begin1]<a[begin2])
tmp[index++]=a[begin1++];
else
tmp[index++]=a[begin2++];
}
while(begin1<=end1) //不为空
{
tmp[index++]=a[begin1++];
}
while(begin2<=end2) //不为空
{
tmp[index++]=a[begin2++];
}
for(size_t i=begin;i<=end;++i)
{
a[i]=tmp[i];
}
}
void MergeSort(int* a,size_t n)
{
int* tmp=new int[n];
_MergeSort(a,tmp,0,n-1);
delete[] tmp;
}