关于排序算法的一些总结

112 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情

我们第一次接触到的算法,应该都是冒泡吧。我个人是这样的,那么在java类库可以直接调用的基础上,对于这些算法的底层逻辑,以及如何手敲实现,我们还是需要非常熟悉的。

冒泡排序

什么是冒泡?我们可以想象一下鱼儿吐泡泡,是不是慢慢的一步一步从鱼嘴到水面。下图是一次冒泡

image.png

冒泡排序基本思想:每次比较两个相邻元素,如果他们顺序错误就交换。假设是从大到小排序,那么越小的越靠近后面,当我们在比较两个数大小时候,把小的放在后面。

但是一次冒泡后,只有一个数满足要求了,那么还需要进行其他数遍历,但是因为最后一位我们第一次冒泡确定了,所以第二次只需要到倒数第二位就可以完成了。我们要一直重复这个步骤,直到最后一个没有归位的数。

分析好之后就可以尝试书写代码了

public void MaoPaoSort(int[] num){
if(num.length<=1){
return num;
}
for(inr i=0;i<num.length;i++){
for(int j=1;j<n-i;j++){
if(num[j]>num[j+1]){
swap(num[i],num[i+1]);
}
}
}
}
public void swap(int a,int b){
int tmp=a;
a=b;
b=tmp;
}

冒泡法核心,是双循环嵌套,那么我们循环语句是交换,时间复杂度很明显O(n^2)

桶排序

在日常生活中,我们经常遇到排序问题,如果说体育课排队按照高矮是冒泡的启发,那么按照分数排名次就是桶排序的启发了。

桶排序需要借助一维数组,但是一位数组下标从0开始的,和位次不匹配,所以一般申请空间会比时间数据最大值多1,保证0下标位置不进行操作。

image.png

内容初始化为0,如果对应下标有值,则数组内容加1

image.png

在返回值时候:如果当前数组内容为0,表示没有出现过,不打印

代码如下: 1.数组声明和初始化 2.数组内容修改 3.打印数组

public void TongSort(int[] nums){
int[] num=new int[最大值+1];//这个看实际情况而定
Scanner sc=new Scanner(System.in);
for(int i=0;i<nums.lengthl;i++){
int b=sc.nextInt();
num[b]++;
}
for(int i=0;i<num.length;i++){
if(num[i]!=0){
System.out.println(num[i]);
}
}
}

该算法时间复杂度为O(m+n),这只是桶排序一个简单抽象,真正的桶排序可复杂了。

快排

快速排序听起来就很快,确实,他解决了冒泡事件On2的问题,那么快速排序思想是什么呢?

假设我们以最左边为基数,想得到结果左边全部是比基数小,右边比他大的数,如何实现? 我们用双指针,当然java无指针,我们是用两个变量移动模拟指针。 假设 i=0;j=num.length-1 那么结果如下:

image.pngi右移(i++) 找比基数大的 j左移(J--) 找比基数小的

最开始,我们选定6作为基数,然后开始让j左移,当找到第一个比基数小的,这里是5,然后停下,开始移动i,i右移,当找到第一个比6大的,这里是7,停下。交换num[i],num[j]。

image.png继续j--;遇到的第一个比6小的是4,停下,开始i++,遇到9,交换 得到:6 1 2 5 4 3 9 7 8

image.png然后j--继续,发现3比6小,停下,i++ 发现ij相遇了,那么把基数和3交换。

image.png到这里第一次排序完成,接下来从6开始,分两边,左边以3为基数,右边以9,同样完成上面操作接下来继续,,,

代码如何实现??

void quicksort(int left,int right){
int i,j,t,temp;
if(left>right){
return;
}else{
temp=num[left];
i=left;
j=right;
while(i!=j){
while(num[j]>=temp&& i<j)
j--;
while(num[i]<=temp&& i<j)
i++;

if(i<j){
t=num[i];
num[i]=num[j];
num[j]=t;
}
}
//ij不满足了
num[left]=num[i];
num[i]=temp;
quicksort(left ,i-1);
quicksort(i+1,right)
}
}

插入排序

在数据结构里面,我们还学过插入排序,到底是怎么插入的呢?

直接插入排序(Straight Insertion Sort)是一种最简单的排序方法,它的基本操作是将一个记录插入到已排好序的有序表中,从而得到一个新的、记录数增1的有序表。

将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。

从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)

    [初始关键字]:   (49) (38    65    97     76    13    27    49
    i=2             (38) (38    49)   65     97    76    13    27    49
    i=3             (65) (38    49    65)    97    76    13    27    49
    i=4             (97) (38    49    65     97)   76    13    27    49
    i=5             (76) (38    49    65     76    97)   13    27    49
    i=6             (13) (13    38    49     65    76    97)   27    49
    i=7             (27) (13    27    38     49    65    76    97)   49
    i=8             (49) (13    27    38     49    49    65    76    97)  
                           监视哨L.r[0]

假设第一个是49,那么插入38,发现38比49小,插入变成 (38 49) ,接下来插入65,得到有序的 (38 49 65)

代码如下:

void InsertSort (SqList&L){    
  //对顺序表L作直接插入排序。
    for(i=2;i<=L.length;++i)
      if LT(L.r[i].key,L.r[i-1].key){ //“<”,需将L.r[i]插入有序子表
              L.r[0]=L.r[i];    //复制为哨兵
              for( j=i-1 ; LT(L.r[0].key,L.r[j].key);   --j)    
                          L.r[j+1]=L.r[j]//记录后移
              L.r[j+1]=L.r[0]    //  插入到正确位置
       }
} //Insertsort

时间复杂度O(n^2)