插入排序:
概念:插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。
最坏时间复杂度:o(0+1+2+...+n-1)=o((n^2-n)/2)=o(n^2);
最好时间复杂度:o(n-1);
平均时间复杂度:o(n^2);
空间复杂度:o(1)。
适用性:插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,例如,量级小于千,那么插入排序还是一个不错的选择。
稳定性:如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。
代码:
void InsertSort(int arr[],int first,int last)
{
int i,j;
int temp;
for(i=first+1;i<=last;i++)
{
temp=arr[i];
j=i-1;
//与已排序的数逐一比较,大于temp时,该数移后
while((j>=0)&&(arr[j]>temp))
{
arr[j+1]=arr[j];
j--;
}
//存在大于temp的数
if(j!=i-1)
{
arr[j+1]=temp;
}
}
}
冒泡排序:
概念:它重复地走访过要排序的数列,一次比较相邻的两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的尾端,故名冒泡。
冒泡排序算法的运作如下:(从后往前)
(1)比较相邻的元素。如果第一个比第二个大,就交换他们两个。
(2)对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
(3)针对所有的元素重复以上的步骤,除了最后一个。
(4)持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
最好时间复杂度:比较n-1次,o(n),交换0次,赋值0次;
最坏时间复杂度:比较1+2+....+n-1=n(n-1)/2次,o(n^2);交换:每次比较都要交换,n(n-1)/2次,o(n^2);赋值:3*交换=o(n^2)。
平均时间复杂度:o(n^2)
算法稳定性
void BubbleSort(int a[],int n)//n为数组a的元素个数
{
int count=0,temp;
for(int i=0;i<n-1;i++){
for(int j=0;j<n-1-i;j++){
if(a[j]>a[j+1])//数组元素大小按升序排列
{
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
++count;
}
}
if(count==0)
return;
else
count=0;
}
}
快速排序:
void QuickSort(int arr[], int start, int end,int n){
if(start==end)
return;
int k=Partition(arr,start, end, n);
if(k>start)
QuickSort(arr,start,k-1,n);
if(k<end)
QuickSort(arr,k+1,end,n);
}
int Partition(int arr[],int start,int end,int n){
if(arr==NULL||start<0||end>=n||n<=0)
throw std::exception("Invalid Parameter");
int j=start;
for(int i=start;i<end;i++){
if(arr[i]<=arr[end]){
if(i!=j)
swap(&arr[j],&arr[i]);
j++;
}
}
swap(&arr[j],&arr[end]);
return j;
}
void swap(int* a,int* b){
int temp=*a;
*a=*b;
*b=temp;
}
划分函数Partition的的应用: