排序:将原来无序的一个序列重新排列成有序的序列。
排序的稳定性:指待排序的序列中有两个或两个以上相同的项,在排序前和排序后,它们的相对位置有没有发生变化,如果没有变化,则是稳定的;反之不稳定。
插入类的排序:直接插入排序、折半插入排序、希尔排序。
交换类的排序:冒泡排序、快速排序。
选择类排序:简单选择排序、堆排序。
归并类排序:两路合并排序。
基数类排序
冒泡排序:
算法思想:首先将第一个记录和第二个记录比较,如果第一个大,则二者交换,否则不交换;然后第二个记录和第三个记录比较,如果第二个大,则二者交换,否则不交换......一直进行下去,最终最大的那个记录被换到了最后,一趟冒泡完成。重复直到一趟排序过程中没有发生元素交换结束。
时间复杂度:
最好:O(n): 待排序列有序。
最坏:O(n^2) 待排序列逆序。
平均时间复杂度:O(n^2)
稳定性:稳定。
#include <iostream>
using namespace std;
void bubblesort(int *data,int count)
{
for(int i=0;i<count-1;i++)
{
for(int j=0;j<count-i-1;j++)
{
if(data[j]>data[j+1])
{
int temp =data[j];
data[j]=data[j+1];
data[j+1]=temp;
}
}
}
}
int main()
{
int data[]={5,2,7,3,6};
int len=sizeof(data)/sizeof(int);
bubblesort(data,len);
for(int i=0;i<len;i++)
{
cout<<data[i]<<" ";
}
return 0;
}
简单选择排序:
算法思想:从头到尾扫描序列,找出最小的一个记录,和第一个记录交换,接着从剩下的记录中继续这种选择和交换,最终是序列有序。
时间复杂度:
最好:O(n^2)
最坏:O(n^2)
平均时间复杂度:O(n^2)
稳定性:不稳定。
#include <iostream>
using namespace std;
void selectsort(int *data,int count)
{
for(int i=0;i<count-1;i++)
{
for(int j=i+1;j<count;j++)
{
if(data[i]>data[j])
{
int temp =data[i];
data[i]=data[j];
data[j]=temp;
}
}
}
}
int main()
{
int data[]={5,2,7,3,6};
int len=sizeof(data)/sizeof(int);
selectsort(data,len);
for(int i=0;i<len;i++)
{
cout<<data[i]<<" ";
}
return 0;
}
直接插入:
算法思想:每趟将一个待排序的元素作为关键字,按照其关键字值的大小插入到已经排好的
部分序列的适当位置上,直到插入完成。
时间复杂度:
最好:O(n) 待排序列有序。
最坏:O(n^2) 待排序列逆序。
平均时间复杂度:O(n^2)
稳定性:稳定。
#include <iostream>
using namespace std;
void insertsort(int *data,int count)
{
int temp,pos;
for(int i=1;i<count;i++)
{
temp=data[i];
pos=i-1;
while((pos>=0)&&temp<data[pos])
{
data[pos+1]=data[pos];
pos--;
}
data[pos+1]=temp;
}
}
int main()
{
int data[]={5,2,7,3,6};
int len=sizeof(data)/sizeof(int);
insertsort(data,len);
for(int i=0;i<len;i++)
{
cout<<data[i]<<" ";
}
return 0;
}
快速排序:
算法思想:一趟快速排序是以一个"枢轴"为中心,将序列分成两部分,枢轴的一边全是比它小的另一边全是比它大的。
时间复杂度:
最好:O(nlogn) 待排序列越接近无序。
最坏: O(n) 待排序列越接近有序。
平均时间复杂度:O(nlogn)
稳定性:不稳定。
#include <iostream>
using namespace std;
void quicksort(int *data,int l,int r)
{
if(l<r)
{
int i=l,j=r,x=data[l];
while(i<j)
{
while((i<j)&&(data[j]>=x))
j--;
if(i<j)
data[i++]=data[j];
while((i<j)&&(data[i]<x))
i++;
if(i<j)
data[j--]=data[i];
}
data[i]=x;
quicksort(data,l,i-1);
quicksort(data,i+1,r);
}
}
int main()
{
int data[]={5,2,7,3,6};
int len=sizeof(data)/sizeof(int);
quicksort(data,0,len);
for(int i=0;i<len;i++)
{
cout<<data[i]<<" ";
}
return 0;
}
堆排序:
算法思想:
堆是一种数据结构,可以把堆看成一棵完全二叉树,这棵树满足:任何一个非叶节点的值都不大于(或不小于)其左右孩子的值。若父亲大孩子小,则这样的堆叫做大顶堆,若父亲小孩子大,则这样的堆叫做小顶堆。
根据堆的定义知道,代表堆的这棵完全二叉树的根节点的值是最大(或最小)的,因此将一个无序序列调整为一个堆,就可以找出这个序列的最大(或最小)值,然后将找出的这个值交换到序列的最后(或最前),这样有序序列的元素增加1个,无序序列的元素减少1个,对新的无序序列重复这样的操作,就实现了排序。
时间复杂度:
最好:O(nlogn)
最坏:O(nlogn)
平均时间复杂度:O(nlogn)
稳定性:不稳定。
#include<iostream>
using namespace std;
void sift(int r[],int low,int high)
{
int i=2*low+1;
if(i<=high-1)
{
int righti=i+1;
if(righti<=high-1)
if(r[i]<r[righti])
i=righti;
if(r[low]<r[i])
{
int temp=r[i];
r[i]=r[low];
r[low]=temp;
sift(r,i,high);
}
}
}
void heapsort(int r[],int n)
{
for(int i=n-1;i>=0;i--)
{
sift(r,i,n);
}
int j=n-1;
for( i=1;i<=n;i++,j--)
{
int temp=r[0];
r[0]=r[j];
r[j]=temp;
sift(r,0,j);
}
}
int main()
{
int data[]={5,2,7,3,6};
int len=sizeof(data)/sizeof(int);
heapsort(data,len);
for(int i=0;i<len;i++)
{
cout<<data[i]<<" ";
}
return 0;
}
希尔排序:
算法思想:其本质还是插入排序,只是将待排序的序列按某种规则分成几个子序列,分别对这几个子序列进行直接插入排序。
平均时间复杂度:O(n^1.3)
稳定性:不稳定。
1、经过一趟排序,能够保证一个元素到达最终位置,这样的排序有交换类排序的两种(冒泡、快速)和选择类排序的(简单选择、堆)。
2、排序方法的元素比较次数和原始序列无关-----------简单选择排序和折半插入排序。
3、排序方法的排序趟数和原始序列有关----------交换类的排序。