数据结构与算法之十大排序算法

十大排序算法

【前言】最近在重新研究算法,此篇博文供自己复习使用也为方便广大程序员同学!此文代码均为自己实现,通过对比经典解法校验,若有错请读者及时提出

//说明,为了方便统一方法,所以引进了一个基类,让子类去实现该方法.

public abstract class BaseSort {

    protected void swap(int[] A, int i, int j) {
        int temp = A[i];
        A[i] = A[j];
        A[j] = temp;
    }

    protected boolean isNullOrEmpty(int[] A){
       return A==null||A.length==0;
    }

    public abstract void sort(int[] array);
}

1.冒泡排序

package com.itheima.sort.impl;


import com.itheima.sort.BaseSort;
import org.junit.Test;

import java.util.Arrays;

//冒泡排序
//策略:每次遍历往上固定一个最小值
public class BubbleSort  extends BaseSort {
    
    @Override
    public void sort(int[] array) {
        if (isNullOrEmpty(array)) return;
        boolean flag;//在每一趟的比较中的标志位,我们可以用来优化冒泡排序
        //需要比较的趟数
        for (int i = 0; i < array.length - 1; i++) {
            flag = false;
            //需要比较的次数,默认按照升序进行排序
            for (int j = i; j < array.length; j++) {
                if (array[i] > array[j]) {
                    flag = true;
                    swap(array, i, j);
                }
            }
            if (!flag) {
                break;
            }
        }

    }



    @Test
    public void testList() {
        int[] ints = new int[]{11, 334, 64, 32, 667, 346, 478, 3, 1, 789, 453, 4};
        sort(ints);
        System.out.println("sort = " + Arrays.toString(ints));
    }

}

2.选择排序

package com.itheima.sort.impl;

import com.itheima.sort.BaseSort;
import org.junit.Test;

import java.util.Arrays;

//选择排序
//每次挑选出一个最值(最小值即为升序,最大值即为降序)
public class SelectSort extends BaseSort {


    @Override
    public void sort(int[] array) {
        if (isNullOrEmpty(array)) return;
        int minTemp;
        for (int i = 0; i < array.length-1; i++) {
            minTemp=i;
            //找到下标i开始后面的最小值
            for (int j = i+1; j <array.length ; j++) {
                if (array[minTemp]>array[j]){
                    minTemp=j;
                }
            }
            //确保稳定排序,数值相等就不用交换
            if(i!=minTemp){
                swap(array,i,minTemp);
            }
        }

    }

    @Test
    public void testList() {
        int[] ints = new int[]{11, 334, 64, 32, 667, 346, 478, 3, 1, 789, 453, 4};
        sort(ints);
        System.out.println("sort = " + Arrays.toString(ints));
    }



}

3.插入排序

package com.itheima.sort.impl;

import com.itheima.sort.BaseSort;
import org.junit.Test;

import java.util.Arrays;

//插入排序
public class InsertSort extends BaseSort {

    @Override
    public void sort(int[] array) {
        if (isNullOrEmpty(array)) return;
        //用模拟插入扑克牌的思想
        //插入的扑克牌
        int i, j, temp;
        //默认前面已经插入一张
        for (i = 1; i < array.length; i++) {
            //当前需要插入的值,然后进行插牌(将大于当前值的后移一位)
            temp=array[i];
            for ( j =i; j >0&&temp<array[j-1] ; j--) {
                array[j]=array[j-1];
            }
            //将牌插入
            array[j]=temp;
        }

    }


    @Test
    public void testList() {
        int[] ints = new int[]{11, 334, 64, 32, 667, 346, 478, 3, 1, 789, 453, 4};
        sort(ints);
        System.out.println("sort = " + Arrays.toString(ints));
    }
}

4.希尔排序

package com.itheima.sort.impl;

import com.itheima.sort.BaseSort;
import org.junit.Test;

import java.util.Arrays;

//希尔排序是将待排序的数组按照摸一个增量d(n/2,n为需要排序的元素个数)分为若干组,每组中记录小标相差d
//对每组中全部元素进行插入排序,然后再用一个较小的增量(d/2)对它进行分组,每组中在进行直接插入排序.当增量
//减到1时,进行直接插入排序后,排序完成

//希尔排序算法(缩小增量法)属于插入排序类算法,将无序列分割成若干小的子序列分别进行插入排序.
public class ShellSort extends BaseSort {

    @Override
    public void sort(int[] array) {
        if (isNullOrEmpty(array)) return;
        int i, j, temp;
        //设定增量d,增量d/2逐渐减小
        for (int d = array.length/2; d >=1; d=d/2) {
            //从下标d开始,对d组进行插入排序
            for(i=d;i<array.length;i++){
                temp=array[i];
                for ( j = i; j>=d&&array[j-d]>temp ; j-=d) {
                    array[j]=array[j-d];
                }
                array[j]=temp;
            }
        }

    }



    @Test
    public void testList() {
        int[] ints = new int[]{11, 334, 64, 32, 667, 346, 478, 3, 1, 789, 453, 4};
        sort(ints);
        System.out.println("sort = " + Arrays.toString(ints));
    }
}

5.归并排序

package com.itheima.sort.impl;

import com.itheima.sort.BaseSort;
import org.junit.Test;

import java.util.Arrays;

//归并排序
//策略:将两个有序有序数组合并为一个有序数组
//将一个数组分解成一个个元素,那么可以将这些元素看做长度为1的有序数组,
//然后将这些子数组合并成一个有序数组
public class MergeSort extends BaseSort {

    @Override
    public void sort(int[] array) {
        if (isNullOrEmpty(array)) return;
        int[] tempArr = new int[array.length];
        sort(array, tempArr, 0, array.length - 1);
    }

    private void sort(int[] array, int[] tempArr, int startIndex, int endIndex) {
        if (startIndex == endIndex) return;
        //中部坐标
        int middleIndex = (startIndex + endIndex) / 2;
        //分解
        sort(array, tempArr, startIndex, middleIndex);
        sort(array, tempArr, middleIndex + 1, endIndex);

        //归并
        merge(array, tempArr, startIndex, middleIndex, endIndex);
    }

    private void merge(int[] array, int[] tempArr, int startIndex, int middleIndex, int endIndex) {
        //复制要合并的数据
        for (int s = startIndex; s <= endIndex; s++) {
            tempArr[s] = array[s];
        }

        int left = startIndex;//左边首位下标
        int right = middleIndex + 1;//右边首位下标


//        for (int k = startIndex; k <= endIndex; k++) {
//            if(left > middleIndex){
//                //如果左边的首位下标大于中部下标,证明左边的数据已经排完了。
//                array[k] = tempArr[right++];
//            } else if (right > endIndex){
//                //如果右边的首位下标大于了数组长度,证明右边的数据已经排完了。
//                array[k] = tempArr[left++];
//            } else if (tempArr[right] < tempArr[left]){
//                array[k] = tempArr[right++];//将右边的首位排入,然后右边的下标指针+1。
//            } else {
//                array[k] = tempArr[left++];//将左边的首位排入,然后左边的下标指针+1。
//            }
//        }


        int k=startIndex;
        while (left <= middleIndex && right <= endIndex){
            if (tempArr[left]<tempArr[right]){
                array[k++]=tempArr[left++];
            }else{
                array[k++]=tempArr[right++];
            }
        }
        while (left<=middleIndex&&k<=endIndex){
            array[k++]=tempArr[left++];
        }
        while (right<=endIndex&&k<=endIndex){
            array[k++]=tempArr[right++];
        }

    }


    @Test
    public void testList() {
        int[] ints = new int[]{11, 334, 64, 32, 667, 346, 478, 3, 1, 789, 453, 4};
        sort(ints);
        System.out.println("sort = " + Arrays.toString(ints));
    }


}

6.快排

package com.itheima.sort.impl;

import com.itheima.sort.BaseSort;
import org.junit.Test;

import java.util.Arrays;

//快速排序是对冒泡排序的一种改建,使用分治法策略见一个序列分为两个子序列
//步骤:从数列中跳出一个元素,称为枢轴
//重新排序数列,所有元素比枢轴小的摆放在基准前面,所有元素比枢轴大的摆放在枢轴后面(相同的数可以放到任意一边)
//在这个分区结束之后,该枢轴就处于中间位置,这个成为分区操作
//递归地把小于枢轴值元素的子数列和大于枢轴值元素的子数列排序
public class QuickSort extends BaseSort {

    @Override
    public void sort(int[] array) {
        if (isNullOrEmpty(array)) return;
        sort(array, 0, array.length - 1);
    }


    private void sort(int[] array, int startIndex, int endIndex) {
        if (endIndex <= startIndex) return;
        int pivotIndex = partition(array, startIndex, endIndex);
        sort(array, startIndex, pivotIndex - 1);
        sort(array, pivotIndex + 1, endIndex);

    }

    private int partition(int[] array, int startIndex, int endIndex) {
        int pivot = array[startIndex];//取基准值
        int mark = startIndex;//Mark初始化为起始下标
        for (int i = startIndex + 1; i <= endIndex; i++) {
            if (array[i] < pivot) {
                //小于基准值 则mark+1,并交换位置。
                mark++;
                swap(array, mark, i);
            }
        }
        //基准值与mark对应元素调换位置
        array[startIndex] = array[mark];
        array[mark] = pivot;
        return mark;
    }


    @Test
    public void testList() {
        int[] ints = new int[]{11, 334, 64, 32, 667, 346, 478, 3, 1, 789, 453, 4};
        sort(ints);
        System.out.println("sort = " + Arrays.toString(ints));
    }
}

7.堆排序

package com.itheima.sort.impl;

import com.itheima.sort.BaseSort;
import org.junit.Test;

import java.util.Arrays;

public class HeapSort extends BaseSort {

    @Override
    public void sort(int[] array) {
        if (isNullOrEmpty(array)) return;
        buildHeap(array, array.length);
        for (int i = array.length - 1; i > 0; i--) {
            //将堆顶元素与末位元素调换
            swap(array, 0, i);
            heapAdjust(array, 0, i);
        }

    }

    //构建堆
    //节点:index 左孩子:2*index+1 右孩子:2*index+2
    private void buildHeap(int[] array, int length) {
        for (int i = length / 2; i >= 0; i--) {
            heapAdjust(array, i, length);
        }
    }

    //调整堆(递归写法)
    private void heapAdjust(int[] array, int index, int length) {
        int leftChild = 2 * index + 1;//左子节点下标
        int rightChild = 2 * index + 2;//右子节点下标
		int present = index;//要调整的节点下标

        //指向左孩子
        if (leftChild < length && array[leftChild] > array[present]) {
            present = leftChild;
        }
        //指向右孩子
        if (rightChild < length && array[rightChild] > array[present]) {
            present = rightChild;
        }

        //调整该节点及其子树
        if (index!=present){
            swap(array,index,present);
            heapAdjust(array,present,length);
        }


    }

    @Test
    public void testList() {
        int[] ints = new int[]{11, 334, 64, 32, 667, 346, 478, 3, 1, 789, 453, 4};
        sort(ints);
        System.out.println("sort = " + Arrays.toString(ints));
    }


}

8.计数排序

package com.itheima.sort.impl;

import com.itheima.sort.BaseSort;
import org.junit.Test;

import java.util.Arrays;

//计数排序
//计数排序是基于一种肺比较的排序算法,我们之间的各种排序算法都是基于元素之间的比较来进行排序的,
//计数排序的时间复杂度是O(n+m)m指的是数据量,简单来说就是计数排序的时间复杂度为O(n),快于任何比较型的排序算法


//对于计数排序呢也存在相当多的bug
// 1)如果数组中存在负数,可以用偏移量来解决
public class CountSort extends BaseSort {

    @Override
    public void sort(int[] array) {
        if (isNullOrEmpty(array)) return;
        //找出数组中的最大值
        int max=array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i]>max){
                max=array[i];
            }
        }

        //初始化计数数组
        int[] countArray = new int[max + 1];

        //计数
        for (int i = 0; i < array.length; i++) {
            countArray[array[i]]++;
        }

        int index=0;
        for (int i = 0; i < countArray.length; i++) {
            while (countArray[i]-->0){
                array[index++] = i;
            }
        }
    }

    @Test
    public void testList() {
        int[] ints = new int[]{11, 334, 64, 32, 667, 346, 478, 3, 1, 789, 453, 4,11};
        sort(ints);
        System.out.println("sort = " + Arrays.toString(ints));
    }
}

9.桶排序

package com.itheima.sort.impl;

import com.itheima.sort.BaseSort;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

//桶排序可以看成是计数排序的升级版,他可以将排的数据分到多个有序的桶里,每个桶里的数据在单独排序,再把每个桶的数据依次取出,
// 再把每个每个桶的数据依次取出即可完成排序
public class BucketSort extends BaseSort {
    @Override
    public void sort(int[] array) {
        if (isNullOrEmpty(array)) return;
        //最大最小值
        int max = array[0], min = array[0];
        for (int i = 0; i < array.length; i++) {
            if (array[i] > max) {
                max = array[i];
            }
            if (array[i] < min) {
                min = array[i];
            }
        }

        //最大值和最小值的差
        int diff = max - min;

        //桶列表
        ArrayList<ArrayList<Integer>> bucketList = new ArrayList<>();
        for (int i = 0; i < array.length; i++) {
            bucketList.add(new ArrayList<>());
        }


        //每个桶的存数区间
        int section = diff / (array.length - 1);

        //数据入桶
        for (int i = 0; i < array.length; i++) {
            //当前数除以区间得出存放桶的位置 减1后得出桶的下标
            int num = (int) (array[i] / section) - 1;
            if (num < 0) {
                num = 0;
            }
            bucketList.get(num).add(array[i]);
        }

        //桶内排序
        for (int i = 0; i < bucketList.size(); i++) {
            //jdk的排序速度当然信得过
            Collections.sort(bucketList.get(i));
        }

        //写入原数组
        int index = 0;
        for (ArrayList<Integer> arrayList : bucketList) {
            for (int value : arrayList) {
                array[index] = value;
                index++;
            }
        }


    }


    @Test
    public void testList() {
        int[] ints = new int[]{11, 334, 64, 32, 667, 346, 478, 3, 1, 789, 453, 4};
        sort(ints);
        System.out.println("sort = " + Arrays.toString(ints));
    }
}

10.基数排序


package com.itheima.sort.impl;

import com.itheima.sort.BaseSort;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;

//基数排序:是一种非比较的整数排序算法,其原理是将数据按位数切割成不同的数字,然后按每个位数分别比较
//假设说要对100万个数据进行排序,name应该选择什么排序算法呢,排的比较快的有归并与快排,计数排序和桶排序虽然更快一些,但是需要多少桶呢
//内存条表示不服,这个时候基数排序就是最好的选择
public class RadixSort extends BaseSort {

    @Override
    public void sort(int[] array) {
        if (isNullOrEmpty(array)) return;
        int max = array[0];
        for (int i = 0; i < array.length; i++) {
            if (array[i] > max) {
                max = array[i];
            }
        }

        //当前排序位置
        int location = 1;
        //桶列表
        ArrayList<ArrayList<Integer>> bucketList = new ArrayList<>();
        //长度为10 装入余数0-9的数据
        for (int i = 0; i < 10; i++) {
            bucketList.add(new ArrayList());
        }

        while (true) {
            //判断是否排完
            int dd = (int) Math.pow(10, (location - 1));
            if (max < dd) {
                break;
            }

            //数据入桶
            for (int i = 0; i < array.length; i++) {
                //计算余数 放入相应的桶
                int number = ((array[i] / dd) % 10);
                bucketList.get(number).add(array[i]);
            }

            //写回数组
            int index = 0;
            for (int i = 0; i < 10; i++) {
                for (int j = 0; j < bucketList.get(i).size(); j++) {
                    array[index++] = bucketList.get(i).get(j);
                }
                bucketList.get(i).clear();
            }
            location++;
        }

    }


    @Test
    public void testList() {
        int[] ints = new int[]{11, 334, 64, 32, 667, 346, 478, 3, 1, 789, 453, 4};
        sort(ints);
        System.out.println("sort = " + Arrays.toString(ints));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值