四种简单排序的详细分析与总结

it2023-01-12  50

直接插入排序:

  直接插入排序就是就是从end的下一位挑选一个数字不断地向前进行插入,整个过程伴随着end的位置从0置end-1,该无序数列也逐渐成为了一个有序数列!思想还是比较简单的,当原合越接近有序时,直接插入排序算法的效率越高。时间复杂度是0N的二次方,是一种比较稳定的排序方式!

  当写直接插入排序的代码时,我们可以先写单次循环的代码,最后再通过在外部控制end的位置写一个大循环 !

int InsertSort(int *a, int n) {     for (int i = 0; i <= n - 2; i++)     {         int end = i;         int tmp = a[end + 1]         while(end>=0){             if (a[end] > a[tmp])             {                 a[end + 1] = a[end];                 --end;             }             else                 break;         }     }     a[end + 1] = tmp; }

这是插入排序的代码,其中需要注意的点在于先写单次循环,而后再整体大循环,可能很多人会对a[end+a]=tmp这一句比较疑惑。其实当,end'一直减减到头会导致,end出现在-1这个位置上,tmp自然而然就会插入到end=0的位置上上。

希尔排序:

  希尔排序说白了就是一种优化后的直接插入排序,不同的点在于他对数组进行了分组操作,复杂度有所减小,可以达到ON的一点三次方。希尔排序会对整个数据进行预排序->使数组接近于有序,而后会进行直接插入排序。

  预排序:数组进行分组,间隔是gap的分为一组,分别进行排序,分别让着gap组数据进行插入排序。gap越小,会越接近于有序,跳的越慢。gap越大,越不接近于有序,跳的越快。当多次进行预排序,gap会变得越来越小。当gap=1时,显而易见他就是一个直接插入排序!

int ShellSort(int *a, int n) {     int gap = n;     while (gap>1)     {          gap = gap / 3 + 1;     for (int i = 0; i <= n - gap; i++)     {         int end = i;         int tmp = a[end + gap]         while(end>=0){             if (a[end] > a[tmp])             {                 a[end + gap] = a[end];                 end -= gap;             }             else                 break;         }     }     a[end + gap] = tmp; }

  这就是希尔排序的算法代码,可以看出很明显就是对直接插入排序的变形,增加了一个gap变量,用于进行分组!gap=gap/3+1这里3不能写成二,一旦写成2,会出现死循环的情况!为什么要进行+1操作呢,保证不伦n多大,最终都可以跳回到gap=1,从而进行直接插入排序!这个算法比较巧妙的地方在于,gap个间隔为gap的组进行同时交插排序!

选择排序:

  一次选择两个数,最小的数放在第一个位置,最大的数放在最后的一个位置!应该去找到最小数与最大数的下标,而不是找到数,这样能防止覆盖!

void SelectSort(int *a, int n){     int begin = 0, end = n - 1;     while (begin < end)     {//[begin,end]中选出一个最小的,选出一个最大的下标!         int mini = begin, maxi = end;         for (int i = begin; i <= end; ++i)         {             if (a[i]>a[maxi])                 maxi = i;             if (a[i] < a[mini])                 mini = i;         }         Swap(&a[begin], &a[mini]);         if (begin == maxi){             maxi = mini;         }         Swap(&a[end], &a[maxi]);         ++begin;         --end;     }

}

这种排序特别简单,需要注意的点就是

   if (begin == maxi){             maxi = mini;

这一块,当出现情况开头第一个数字是最大的时候,会对begin与mini进行交换,但是这个时候maxi位置且没有发生变化,直接导致后一步end与maxi交换时出现,刚换过去的mini指向的最小值被交换到了数组的end端!

冒泡排序:

  一次又一次的向下沉底,下面是基本代码

void BubbleSort(int *n, int n) {     for (int end = n - 1; end > 0;--end){         int flag = 0;         for (int i = 0, i < end; ++i)         {             if (a[i] > a[i + 1]){                 Swap(&a[i], a[i + 1]);                 flag = 1;             }         }         if (flag == 0)//说明并没有发生交换             break;     } } 对于这个排序我想说的就是这个flag这一点新意,它是对冒泡排序的一种优化,当一次 内循环没有发生任何交换时(flag值恒为0)那么就可以直接跳出,这种方法对于特定的数组提高了不小的效率!

 

最新回复(0)