数据结构与算法之常用排序算法-Java JavaScript实现

排序算法在一些算法 思想中会经常使用到下面就对一些常用的排序算法做一个记录,常见的排序算法可以分为:

0 排序基础知识

0.1 排序分类

比较类排序:通过比较来决定元素的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。

数据结构与算法之常用排序算法-Java JavaScript实现_第1张图片 

非比较类排序:不通过比较来确定元素的次序,可以突破基于比较的时间下界,时间是线性的。因此也叫线性时间非比较排序

 0.2 时间空间复杂度。

比较信息等可以参考下图,图片来自牛客网:

数据结构与算法之常用排序算法-Java JavaScript实现_第2张图片

0.3 相关概念

稳定:排序结果不受元素之间的相对位置限制,既a在b前面,且a=b,排序后a任然在b前面。

时间复杂度O() 即从序列的初始状态到经过排序算法的变换移位等操作变到最终排序好的结果状态的过程所花费的时间度量。

空间复杂度O() 就是从序列的初始状态经过排序移位变换的过程一直到最终的状态所花费的空间开销。

1、冒泡排序

1.1 冒泡算法介绍

冒泡排序算法是把较小的元素往前调或者把较大的元素往后调。这种方法主要是通过对相邻两个元素进行大小的比较,根据比较结果和算法规则对该二元素的位置进行交换,这样逐个依次进行比较和交换,就能达到排序目的。

1.2 基本思想

冒泡排序的基本思想是,

  • 1、首先将第1个和第2个记录的关键字比较大小,如果是逆序的,就将这两个记录进行交换,再对第2个和第3个记录的关键字进行比较,依次类推;
  • 2、重复进行上述计算,直至完成第(n一1)个和第n个记录的关键字之间的比较,
  • 3、此后,再按照上述过程进行第2次、第3次排序,直至整个序列有序为止。排序过程中要特别注意的是,当相邻两个元素大小一致时,这一步操作就不需要交换位置,因此也说明冒泡排序是一种严格的稳定排序算法,它不改变序列中相同元素之间的相对位置关系

1.3代码实现

	public static int[] BubbleSort(int[] array) {
		if(array.length<=1) return array;
		for(int i = 0;i<=array.length-1;i++) {
			//method1
			for(int j=i;jarray[j]) {
				    array = swap(array,i,i+1);
				}
			}

			//method2
			for(int j = 0;jarray[j+1]) swap(array,j,j+1);
		}
		return array;
		
	}
	
	private static int[] swap(int[] arr ,int a,int b) {
		int temp = arr[a];
		arr[a] = arr[b];
		arr[b] = temp;
		return arr;
	}

JavaScript实现

function bubbleSort(arr){
    let len = arr.length;
    for(let i = 0;i

经过两次比较,是稳定的排序算法 因此平均、最坏时间复杂度均为O(n^2),最好时间复杂度O(n), 空间复杂度O(1)

排序方法 时间复杂度(平均) 时间复杂度(最坏) 时间复杂度(最坏) 空间复杂度 稳定性
冒泡 O(n^2) O(n^2) O(n) O(1) 稳定

2选择排序

2.1 基本思想

选择排序算法的基本思路是首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果

2.2 算法描述

  • 首先从第1个位置开始对全部元素进行选择,选出全部元素中最小的给该位置,再对第2个位置进行选择,在剩余元素中选择最小的给该位置即可;
  • 以此类推,重复进行“最小元素”的选择,直至完成第(n-1)个位置的元素选择,则第n个位置就只剩唯一的最大元素,此时不需再进行选择。

使用这种排序时,要注意其中一个不同于冒泡法的细节。

举例说明:序列58539.我们知道第一遍选择第1个元素“5”会和元素“3”交换,那么原序列中的两个相同元素“5”之间的前后相对顺序就发生了改变。因此,我们说选择排序不是稳定的排序算法,它在计算过程中会破坏稳定性

2.3 代码实现

	public static int[] selectionSort(int[] arr) {
		int len = arr.length;
		int minPoint,temp;
		for(int i = 0;i

JavaScript实现

function selectionSort(arr){
    let len = arr.length;
    if(len<=1) return arr;
    let minPoint;
    for(let i=0;i

数据结构与算法之常用排序算法-Java JavaScript实现_第3张图片

2.4 算法分析

选择排序的结果不稳定,任何情况下时间复杂度永远是O(n^2),所以数量较小时速度处理较快,但是空间复杂度较小

排序方法 时间复杂度(平均) 时间复杂度(最坏) 时间复杂度(最坏) 空间复杂度 稳定性
选择排序 O(n^2) O(n^2) O(n^2) O(1) 不稳定

不稳定可以在排序数组中添加两个相同的数字,出现以下结果

数据结构与算法之常用排序算法-Java JavaScript实现_第4张图片

3 插入排序

3.1 基本思想

插入排序算法是基于某序列已经有序排列的情况下,通过一次插入一个元素的方式按照原有排序方式增加元素。

3.2 算法描述

这种比较是从该有序序列的最末端开始执行

  • 1、要插入序列中的元素最先和有序序列中最大的元素比较(默认第一个元素已经排序好,从第一个元素开始),
  • 2、若其大于该最大元素,则可直接插入最大元素的后面即可,否则再向前一位比较查找直至找到应该插入的位置为止。
  • 插入排序的基本思想是,每次将1个待排序的记录按其关键字大小插入到前面已经排好序的子序列中,寻找最适当的位置,直至全部记录插入完毕。执行过程中,若遇到和插入元素相等的位置,则将要插人的元素放在该相等元素的后面,因此插入该元素后并未改变原序列的前后顺序。

我们认为插入排序也是一种稳定的排序方法。插入排序分直接插入排序、折半插入排序和希尔排序3类

3.3 算法实现

//method1	
private static int[] DirectInsertSort(int[] array) {
		if(array.length<=1) return array;
		for(int i=0;i0&&temp

JavaScript实现

//插人排序
//基本思想:在序号i之前的元素(0到i-1)已经排好序,
//本趟需要找到i对应的元素x (此时即arr[i]) 的正确位置k,
//在寻找位置k的过程中与序号i-1到0的元素依次进行比较。
//如果x小于比较元素,则比较元素向后移动一位;否则,结束移位,
//将x插入当前位置k
function insertSort(arr){
    let len = arr.length;
    if(arr.length<=0) return ;
    for(let i = 1;i=0;j--){
            if(arr[j]>temp){

                //插入元素小于比较元素 比较元素则向后移动一位
                arr[j+1]=arr[j];

            }else{
                //否则结束移位
                break;
            }
        }
        arr[j+1]=temp;
    }
    return arr;

}

console.log(insertSort([7,3,4,5,10,7,8,2,9,]))

数据结构与算法之常用排序算法-Java JavaScript实现_第5张图片

3.4 算法分析

插入排序采用in-palce排序(可以理解为不需要辅助数组,原地排序)

排序方法 时间复杂度(平均) 时间复杂度(最坏) 时间复杂度(最坏) 空间复杂度 稳定性
插入排序 O(n^2) O(n^2) O(n) O(1) 稳定

4、希尔排序

4.1 基本思想

在要排序的一组数中,根据某一增量分为若干子序列,并对子序列分别进行插入排序。
然后逐渐将增量减小,并重复上述过程。直至增量为1,此时数据序列基本有序,最后进行插入排序。

4.2 算法描述

将待排序的序列分割成若干个子序列分别进行直接插入排序

  • 选择增量序列:K1,K2,...,Kn,其中Ki>Kj,Kn=1;
  • 按增量序列个数n,对序列进行kn趟排序;
  • 每趟排序,根据对应的增量Ki,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

4.3 算法实现

public int[] shellSort(int[] arr){
    int len = arr.length;
    int step ;
    for(step = len/2;step>0;step/=2){  //基数为2的希尔排序
        for(int i =step;istep-1&&temp0){
			//先根据增量排序
			for(int i = 0;istep-1&&temp<=str[j-step]) {
					
					str[j]=str[j-step];  //temp小于 前面位数上的值 做交换
					j-=step;  //步长之间比较
					
				}
				str[j] = temp;
				
				//交换大小2
//				while(j>step-1&&temp

JavaScript实现

//希尔排序
function shellSort(arr){
    let d = arr.length
    while(true){
        d = Math.floor(d/2)
        for(let x = 0;x=0&&arr[j]>temp;j=j-d){
                    arr[j+d] = arr[j];
                }
                arr[j+d] = temp;
            }
        }
        if(d==1){
            break;
        }
    }
    return arr
}

console.log(shellSort([7, 3, 4, 5, 10, 7, 8, 2]))

4.4 算法分析

排序方法 时间复杂度(平均) 时间复杂度(最坏) 时间复杂度(最坏) 空间复杂度 稳定性
希尔排序 O(n^1.3) O(n^2) O(n) O(1) 不稳定

 

5 归并排序

5.1 基本思想

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用。
首先考虑下如何将2个有序数列合并。这个非常简单,只要从比较2个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。

5.2 算法描述

  • 把长度为n的输入序列分成两个长度为n/2的子序列;
  • 对这两个子序列分别采用归并排序;
  • 将两个排序好的子序列合并成一个最终的排序序列。

5.3 代码实现

	 /**
     * 归并排序
     *
     * @param array
     * @return
     */
    public static int[] MergeSort(int[] array) {
        if (array.length < 2) return array;
        int mid = array.length / 2;
        int[] left = Arrays.copyOfRange(array, 0, mid);
        int[] right = Arrays.copyOfRange(array, mid, array.length);
        return merge(MergeSort(left), MergeSort(right));
    }
    /**
     * 归并排序——将两段有序数组结合成一个有序数组
     *
     * @param left
     * @param right
     * @return
     */
    public static int[] merge(int[] left, int[] right) {
       int[] result = new int[left.length + right.length];
       int i = 0,j = 0,k = 0;
       while (i < left.length && j < right.length) {
            if (left[i] <= right[j]) {
                result[k++] = left[i++];
            } else {
                result[k++] = right[j++];
            }
        }
        while (i < left.length) {
            result[k++] = left[i++];
        }
        while (j < right.length) {
            result[k++] = right[j++];
        }
        return result;
    }

JavaScript实现

function merge(left,right){
    let result = []
    while(left.length>0&&right.length>0){
        if(left[0]

5.4 算法分析

归并排序的形式就是一棵二叉树,它需要遍历的次数就是二叉树的深度,而根据完全二叉树的可以得出它在任何情况下时间复杂度均是O(nlogn)。

排序方法 时间复杂度(平均) 时间复杂度(最坏) 时间复杂度(最坏) 空间复杂度 稳定性
归并排序 O(nlogn) O(nlogn) O(nlogn) O(n) 稳定

--------2019.8.20 未完待续

 

参考链接

1、排序算法-百度百科 https://baike.baidu.com/item/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/5399605?fr=aladdin

2、十大经典排序算法(动图演示)

3、菜鸟教程排序算法

4、一文搞定十大排序算法

 

 

你可能感兴趣的:(Java,JavaScript,编程思想,数据结构)