注:以下提到的数组均可替换为表结构。
冒泡排序:依次比较相邻的两个数,如果不满足规定的排序规则,就交换顺序,依次往复,直至有序,主要操作为比较和交换。时间复杂度 O(n2),稳定。
从前往后
//标志是否交换过位置,若=false,说明数组已经达到有序,不必再进行。 boolean change = true; for (int i = 0;i < length -1 && change;i++){ change = false; for (int j = 0;j < length-i-1;j++){ if(a[j] > a[j+1]){ change = true; int temp = a[j+1]; a[j+1] = a[j]; a[j] = temp; } } }
从后往前
boolean change = true; for (int i = 0;i < length -1 && change;i++){ change = false; for (int j = length - 1;j > i;j--){ if(a[j-1] > a[j]){ change = true; int temp = a[j]; a[j] = a[j-1]; a[j-1] = temp; } } }
简单选择排序:每趟找出最小/最大的值后将其放入正确位置,与冒泡排序相比,该算法减少了交换的次数,比较次数未变,时间复杂度 O(n2),但优于冒泡,稳定。
如何找每趟最小:借助临时变量min(最小值在数组中的位置),循环未排序数组,若有比arr[min]更小的数,将min的值替换为更小值所在的位置,直至完成本趟循环。
for (int i = 0;i < length - 1;i++){ int min = i; for (int j = i+1;j < length;j++){ if (arr[j] < arr[min]){ min = j; } } if (i != min){ int temp = arr[i]; arr[i] = arr[min]; arr[min] = temp; } }
直接插入排序:将一个数插入到一个已有序数组中,得到一个新的,长度+1的有序数组。特点是在插入的时候就将元素放在使新数组有序的位置。时间复杂度,最好O(n):数组本就有序,则只会进行n比较,最坏O(n2):但仍优于冒泡与简单排序。
//说明:因为旧元素已经有序,所以在有序的表中,第一个元素必为最小,最后一个元素必为最大。 for (int i = 1;i < length - 1;i++){//i从1开始,因为默认第0个元素已有序 if (arr[i-1] > arr [i]){//最后一个元素比新元素大,则依次将比新元素大的元素向后移,为新元素腾出位置 int j; int new_ele = arr[i];//新插入元素,需要存到一个临时变量,不然在前面元素向后移动的时候,其值会被覆盖掉 for (j = i;j > 0 && new_ele < arr [j-1];j--){ arr[j] = arr[j-1];//新加入元素比前一个更小,将前一个向后移动,此时j-1应该是新元素应在的位置 } arr[j] = new_ele;//此处j的值为新元素最终应该插入的位置 } //默认else是arr[i] > arr [i-1],即新元素比最大的元素还大,那就在数组最后,即i,不做任何变化,继续下次循环,寻找i+1的正确位置。 }
希尔排序:利用直接插入的优点,当元素基本有序或者元素很少时,直接插入排序表现很好。所以,希尔排序将带排序数组先拆分为多个分组,分别对分组中的元素进行直接插入排序后合并,得到一个基本有序的数组,最后再进行一次直接排序,得出有序数组。基本有序即小的基本在左边,大的基本在右边,不大不小的基本在中间。不稳定。
在这里,为了得到最终基本有序的数组,最初的分组不能随意分,需要采用跳跃分割策略,简单讲就是将相距相等增量的元素分到同一组。通过跳跃分组是可以达到基本有序的效果的,已想通。
具体分法可看:https://blog.csdn.net/daiyudong2020/article/details/52445044
//gap即为增量,通过不断减小增量直至1时,得到最终排序结果。其实gap=1是就是最后一次合并排序 for (int gap = length/2;gap > 0;gap/=2){ //此for循环内部其实就是直接插入排序,只是元素的距离不是连续的,而是选择间隔为gap的元素做直接插入排序 for(int i = gap;i<length;i++){ int j; int new_ele = arr[i]; for(j = i;j>i-gap && new_ele < arr[j-gap];j-=gap){ arr[j] = arr[j-gap]; } arr[j] = new_ele; } }
注意:增量序列的最后一个值必须是1
希尔算法是冲破O(n2)的第一批算法之一,希尔排序中对于增量序列的选择十分重要,直接影响到希尔排序的性能。其最坏时间复杂度依然为O(n2),一些经过优化的增量序列如Hibbard经过复杂证明可使得最坏时间复杂度为O(n3/2),但最佳增量的选择是目前还是数学难题。