提醒一下自己,面试的时候可以写成template。
冒泡排序(稳定)
冒泡排序是稳定的。基本的冒泡排序的比较次数与数组是否有序无关,但是数据交换次数与数组是否有序有关。基本冒泡排序时间复杂度为o(n^2)。改进型的冒泡排序最好的时间复杂度为o(n),比较次数与数组初始是否有序有关,交换次数也有关。
冒泡排序改进1:在某次遍历中如果没有数据交换,说明整个数组已经有序。因此通过设置标志位来记录此次遍历有无数据交换就可以判断是否要继续循环。
冒泡排序改进2:记录某次遍历时最后发生数据交换的位置,这个位置之后的数据显然已经有序了。因此通过记录最后发生数据交换的位置就可以确定下次循环的范围了。
(1)改进型前向冒泡排序,即循环一次,冒出一个最大值到末尾。
void BubbleSortForward(int arr[],int len)
{
int i,j;
if(!arr||len<=0)
throw new exception("NULL Array");
for(i = 0;i<len -1;++i){
bool flag = false;
for(j = 0;j<len - 1 -i;++j){
if(arr[j]>arr[j+1]){//保证稳定性无等号
swap(arr[j],arr[j+1]);
flag = true;
}
}
if(!flag)break;
}
}
(2)改进型后向冒泡排序,即循环一次,冒出一个最小值到数组前面。
void BubbleSortBackward(int arr[],int len)
{
int i,j;
bool flag;
if(!arr||len<=0)
throw new exception("NULL Array");
for(i = 0;i<len -1;++i){
flag = false;
for(j = len-1;j > i;--j){
if(arr[j]<arr[j-1]){
swap(arr[j],arr[j-1]);
flag = true;
}
}
if(!flag)break;
}
}
(3)第三种改进算法
template<typename T>
void BubbleSort(T arr[],int len)
{
int flag = len;
while(flag > 0){
int lastCmp = 0;
for(int i=0; i<flag-1; ++i){
if(arr[i] > arr[i+1]){
swap(arr[i],arr[i+1]);
lastCmp = i + 1;//记录上次比较的地方
}
}
flag = lastCmp;
}
}
选择排序(稳定)
选择排序每次将最小的选择出来放在前面,比较次数与数组是否有序无关,但是元素移动次数与数组是否有序有关,选择排序时间复杂度o(n^2)
int SelectionSort(int arr[],int len)
{
if(!arr||len<=0)
throw new exception("NULL Array");
for(int i =0;i<len-1;i++){
int k = i;
for(int j=i+1;j<len;++j)
if(arr[j]<arr[k])k = j;
if(k!=i)swap(arr[k],arr[i]);
}
}
插入排序(稳定)
插入排序最好的时间复杂度为o(n),只需要比较n-1次,插入排序的比较次数数组是否有序有关很大的关系。插入排序对于规模很小的数据排序很有效。
(1)直接插入排序
void InsertSort(int arr[],int start,int end)
{
if(!arr||start<0||start>end)
throw new exception("NULL Array");
for(int i=start+1;i<=end;i++){
if(arr[i]<arr[i-1]){
int base = arr[i];
int j = i;
while(j>=1&&arr[j-1]>base){//等号不取
arr[j] = arr[j-1];
j--;
}
arr[j] = base;
}
}
}
(2)折半插入排序(二分搜索)
void BinaryInsertSort(int arr[],int start,int end)
{
if(!arr||start<0||start>end)
throw new exception("NULL Array");
for(int i = start+1;i<=end;++i ){
int low = start;
int high = i - 1;
int base = arr[i];
while(low<=high){
int mid = (high - low>>1)+low;
if(base<arr[mid])high = mid-1;
else low = mid + 1;//包含等于
}
for(int k = i;k>low;k--){
arr[k] = arr[k-1];
}
arr[low] = base;
}
}
希尔排序(不稳定)
shell排序是在插入排序的基础上改进的。shell排序将一个数组分成gap个子序列,所有元素距离为gap的元素放在同一个子序列中,每个子序列中分别实行插入排序。每迭代一次,gap缩小。
gap = right - left +1;
迭代一次:gap = gap/3 + 1;
gap的取法有讲究,本来gap = gap/2+1,但是在这种取法方式中,要到最后一步奇数位置的元素才能和偶数元素位置比较,这样效率低。元素比较次数和移动次数:n^1.25~1.6n^1.25
void ShellSort(int arr[],int start,int end)
{
if(!arr||start<0||start>end)
throw new exception("NULL Array");
int gap = end - start + 1;
while(gap>1){
gap = gap/3 + 1;
for(int i = start+gap;i<=end;++i ){
if(arr[i]<arr[i-gap]){
int base = arr[i];
int j = i;
while(j>=gap&&arr[j-gap]>base){
arr[j] = arr[j-gap];
j -= gap;
}
arr[j] = base;
}
}
}
}
注:插入的排序的1被替换为gap了,有没有。