冒泡排序,选择排序,插入排序,归并排序的笔记整理

本文为学习基础排序算法之后的整理的笔记,不完全为原创。个人学习能力有限,图片是本人制作,文字、图片可能存在错误,若发现希望能够指出。
因已有大佬对各个算法进行了深度分析,故此篇博客只是记录、整理、分享我自学算法的笔记和过程,希望能与算法学习者们交流,请看官们轻喷。

冒泡排序

从序列的一端开始比较相邻两个数字的大小,根据结果交换两个数的位置。此过程中数据就像泡泡一样,从一端“漂浮”到另一端。

以下为图解:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在学习过程中,思想比较好理解,可以写出如下代码:

public class BubbleSort {
        public static void BubbleSort (int []A) {
        for (int i = 0; i < A.length; i++) {
            for (int j = 0; j < A.length - 1; j++) {
                if (A[j+1] < A[j]) {
                    Swap.swap(A,j,j+1);
                }
            }
        }
    }
}

其中Swap的定义是:

public class Swap {
    public static void swap(int[] A,int i,int t){
        int temp=0;
        temp=A[i];
        A[i]=A[t];
        A[t]=temp;
    }
}

设数据数为n,则可以看出,第1轮要比较n-1次,第2轮需要比较n-2次…第 n-1 轮需要比较1次。所以总的比较次数为 (n - 1) + (n - 2) + … + 1 ≈ n2/2。其比较次数固定,与输入数据的排列顺序无关。 而交换次数与输入数据的排列顺序有关,以极端思想来看,如果输入数据刚好以目标顺序排列,则不需要任何交换,反之则每次比较都需交换数据。所以可知其时间复杂度为O(n2)。

查找排序

从待排序的数据中线性查找最小值(从小到大排序时,从大到小则寻找最大值),将其位置与未排序的数据中最左边的数据位置进行交换,交换完成的数据视为已排序。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码如下(从小到大):

public class SelectionSort {
    public static void selection(int[] A){
        int key=0, temp=0;
        for(int I=0;i<A.length-1;i++){
            key=i;  //记录未排序数据的首位位置,从这里开始寻找最小值
            for (int j=i+1;j<A.length;j++){
                if(A[key]>A[j]){		//寻找最小值
                    key=j;			//将最小值的下标记录在key
                }
            }
            if(i!=key)
			Swap.swap(A, i, key);	//若key值发生变化则交换数据位置,swap参考冒泡中的定义
        }
    }
}

选择排序使用线性查找,需要比较(n-1)+(n-2)+…+1 ≈ n2/2 次。交换次数与输入数据有关,若输入数据刚好为目标顺序,则不需要交换,反之则最多需要n-1次交换。复杂度为O(n2)。

插入排序

插入排序(以从小到大排序为例)是从左对数据进行比较排序的算法。排序时,可以把数组看成左边(已归位部分)和右边(未归位)两部分。从未归位部分的左边第一个数据开始,将其与左边已归位部分的数据比较,小于则与其交换位置,继续向左比较,大于则结束比较。

简单来说,就是从未排序(未归位)的部分中依次取出数据,在已归位的部分里为它寻找合适位置插入。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public class InsertionSort {
    public static void InsertionSort(int[] A) {
        int key = 0, flag = 0;
        for (int i = 1; i < A.length; i++) {
            key = A[i];                 //把进行交换的数存入key
            flag = i - 1;               //flag为在已归位的部分中为需要交换的数据寻找合适位置的一个"指针"(i-1即已归位部分最右边的数据)
            while (flag >= 0 && A[flag] > key) {//指针指向的数据大于key时
                A[flag + 1] = A[flag];//交换数据
                A[flag] = key;    //重新给key赋值
                flag--;               //指针向左移,准备下一次比较
            }
        }
    }
}

插入排序需要将未排序部分的数据依次取出与左边(已归位部分)的数据进行比较,若比较时左边的数据更小,就不需要再比较,直接结束此轮操作。但若每一次取出的数据都比左边(已归位)部分所有数据都小时,就是坏的情况。则第n次取数据时需要操作n-1次。时间复杂度为O(n2)。

归并排序

归并排序将待排序的序列尽可能分成长度相等的两半,细分到每个子序列都只有一个数据时结束,从最小的子序列一步一步合并成有序的更大的子序列,再合并成有序的原序列。

划分过程如图:
在这里插入图片描述
合并过程:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码如下(从小到大):

public class MergeSort {
    public static void merge(int[] A,int left,int right,int[] temp){//A:排序数组,temp:暂时存放数据的额外数组;
        if(right-left>1){
            //划分
            int m=left+(right-left)/2;//使其尽量分成元素数量相等的两半数组;m为前半数组的最大下标()
            int p=left,q=m,i=left;//p为前半数组的"指针"(下标),q为后半数组的"指针"(下标),i为额外数组的"指针"(下标);
            //
            merge(A, left, m, temp);//调用递归求解(划分数组再合并)前半
            merge(A, m, right, temp);//后半
            //合并
            while (p<m||q<right){//当左右两半数组任意数组还有未合并的数据时
                if(q>=right||p<m&&A[p]<=A[q])//依次比较左右两半数组对应下标的数据的大小,将小的抄入额外数组中;
                temp[i++]=A[p++];//从左半数组抄入额外数组;每抄入一个数据就使其下标p后移一位;
                else
                    temp[i++]=A[q++];//从右半数组抄入额外数组;
            }
            for(i=left;i<right;i++)//从额外数组抄回原数组A。
                A[i]=temp[i];
        }
    }
}
               

对于归并排序过程来说,每一步划分的子序列们中数据个数都是n,所以每行的运行时间都为O(n)。长度为n的序列分到最小,可以分成 log2n 次。因此,可以知道时间复杂度为 O(nlogn)。

致谢

最后,感谢学习和写作过程给我帮助的同学与朋友们。
新人第一次发博客,内容上可能有错误,希望读者看客们能够提出,让我加以改正,谢谢阅读。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值