【七个排序】选择排序、冒泡排序、快速排序、插入排序、希尔排序、堆排序、归并排序

选择排序

import java.util.Arrays;

//选择排序
//(一直拿后边的元素去比较边界元素)
public class selectSort {
    public static void selectSort(int[] arr){
        //创建一个变量bound表示已排序区间和待排序区间的边界,
        //[0, bound)以排序区间
        //[bound, length)待排序区间
        int bound = 0;
        for(; bound < arr.length; bound++){
            //里层循环要进行打擂台的过程
            //擂台的位置就是bound下标的位置
            for(int cur = bound + 1; cur < arr.length; cur++){
                if(arr[cur] < arr[bound]){
                    //如果发现挑战者比擂主小,就交换两个元素
                    swap(arr, cur, bound);
                }
            }
        }
    }
    public static void swap(int[] arr, int x, int y){
        int tmp = arr[x];
        arr[x] = arr[y];
        arr[y] = tmp;
    }
    public static void main(String[] args) {
        int[] arr = {9, 5, 2, 7, 3, 6, 8};
        selectSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

冒泡排序

import java.util.Arrays;
//冒泡排序
public class bubbleSort {
    public static void bubbleSort(int[] arr){
        //bound用来区分两个区间
        for(int bound = 0; bound < arr.length; bound++){
            for(int cur = arr.length - 1; cur > bound; cur--){
                if(arr[cur - 1] > arr[cur]){
                    swap(arr, cur - 1, cur);
                }
            }
        }
    }
    public static void swap(int[] arr, int x, int y){
        int tmp = arr[x];
        arr[x] = arr[y];
        arr[y] = tmp;
    }
    public static void main(String[] args) {
        int[] arr = {9, 5, 2, 7, 3, 6, 8};
        bubbleSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

快速排序

非递归

import java.util.Arrays;
import java.util.Stack;

//快速排序
//以下是非递归
public class quickSort {
    public static void quickSortByLoop(int[] arr){
        //1.先创建一个栈,这个栈用来保存当前的每一个待处理区间
        Stack<Integer> stack = new Stack<>();
        //2.把根节点入栈,整个数组对应的区间
        stack.push(0);
        stack.push(arr.length - 1);
        //3.循环取栈顶元素
        while (!stack.isEmpty()){
            //取的元素就是当前的待处理的区间
            //取的顺序正好和插入的顺序相反
            int right = stack.pop();
            int left = stack.pop();
            if(left >= right){
                //如果是空区间或者只有一个元素,不需要排序
                continue;
            }
            //调用partit方法整理当前区间,得到基准值的位置
            int index = partition(arr, left, right);
            //右侧区间: [index + 1, right]
            stack.push(index + 1);
            stack.push(right);
            //左侧区间: [left, index - 1]
            stack.push(left);
            stack.push(index - 1);
        }
    }
    public static int partition(int[] arr, int left, int right){
        //选取最右侧元素作为基准值
        int v = arr[right];
        int l = left;
        int r = right;
        //如果l和r重合,说明遍历完成
        while(l < r){
            //先从左往右,找一个比基准值大的数字
            while(l < r && arr[l] <= v){
                l++;
            }
            //当循环结束的时候,l就指向了比基准值大的元素
            //再从右往左,找一个比基准值小的数字
            while(l < r && arr[r] >= v){
                r--;
            }
            swap(arr, l, r);
        }
        //当l和r重合的时候,就把重合位置的元素和基准值位置进行交换
        swap(arr, l, right);
        //最终方法返回基准值所在的位置(l和r重合的位置)
        return l;
    }
    public static void swap(int[] arr, int x, int y){
        int tmp = arr[x];
        arr[x] = arr[y];
        arr[y] = tmp;
    }
    public static void main(String[] args) {
        int[] arr = {9, 5, 2, 7, 3, 6, 8};
        quickSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

递归

//以下是递归
import java.util.Arrays;
public class quickSort {
    public static  void quickSort(int[] arr){
        //创建一个辅助递归的方法
        //在这个方法的参数中,明确指定针对哪个区间进行递归
        //[0, length - 1]
        _quickSort(arr, 0, arr.length - 1);
    }
    public static void _quickSort(int[] arr, int left, int right){
        if(left >= right){
            //如果当前的区间为空,或者只有一个元素
            //都不需要进行任何处理
            return;
        }
        //先针对当前[left, right]区间进行partition操作
        //方法的返回值表示整理完当前区间后,基准值所在的位置
        //即遍历过程中的left和right的重合位置
        int index = partition(arr, left, right);
        //递归的对左侧区间进行快速排序
        _quickSort(arr, left, index - 1);
        //递归的对右侧区间进行快速排序
        _quickSort(arr, index + 1, right);
    }
    public static int partition(int[] arr, int left, int right){
        //选取最右侧元素作为基准值
        int v = arr[right];
        int l = left;
        int r = right;
        //如果l和r重合,说明遍历完成
        while(l < r){
            //先从左往右,找一个比基准值大的数字
            while(l < r && arr[l] <= v){
                l++;
            }
            //当循环结束的时候,l就指向了比基准值大的元素
            //再从右往左,找一个比基准值小的数字
            while(l < r && arr[r] >= v){
                r--;
            }
            swap(arr, l, r);
        }
        //当l和r重合的时候,就把重合位置的元素和基准值位置进行交换
        swap(arr, l, right);
        //最终方法返回基准值所在的位置(l和r重合的位置)
        return l;
    }
    public static void swap(int[] arr, int x, int y){
        int tmp = arr[x];
        arr[x] = arr[y];
        arr[y] = tmp;
    }
    public static void main(String[] args) {
        int[] arr = {9, 5, 2, 7, 3, 6, 8};
        quickSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

插入排序

import java.util.Arrays;
//插入排序
public class MySort {
    public static void insertSort(int[] arr){
        int bound = 1;
        //[0, bound)是已排序区间
        //[bound, length)待排序区间
        for(; bound < arr.length; bound++){
            //取出待排序区间的最开始元素
            int v = arr[bound];
            int cur = bound - 1;
            for(cur = bound - 1; cur >= 0; cur--){
                //拿着v这个值依次往前进行比较,找到合适位置
                if(arr[cur] > v){
                    //说明 v 应该插入到arr[cur]之前
                    //于是就得把cur位置的元素往后搬运一个格子
                    arr[cur + 1] = arr[cur];
                }else{
                    //说明已经找到合适的位置了,就可以结束循环了
                    //这个合适的位置,就是cur的后面
                    //也就是cur + 1这个下标
                    break;
                }
            }
            arr[cur + 1] = v;
        }
    }

    public static void main(String[] args) {
        int[] arr = {9, 5, 2, 7, 3, 6, 8};
        insertSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

希尔排序

import java.util.Arrays;

//希尔排序
public class shellSort {
    public static void shellSort(int[] arr){
        //指定gap序列,len/2,len/4,len/8...
        int gap = arr.length / 2;
        while(gap >= 1){
            _shellSort(arr, gap);
            gap = gap / 2;
        }
    }

    public static void _shellSort(int[] arr, int gap){
        //进行分组插排,分组依据就是gap
        //gap同时也表示分的组数
        //同组的相邻元素,下标差值就是gap
        //下面的代码其实和插入排序是一样的,尤其是gap设W为1的时候
        int bound = gap;
        for(; bound < arr.length; bound++){
            int v = arr[bound];
            int cur = bound - gap;
            for(; cur >= 0; cur -= gap){
                if (arr[cur] > v){
                    //进行搬运
                    arr[cur + gap] = arr[cur];
                }else{
                    break;
                }
            }
            arr[cur + gap] = v;
        }
    }
    public static void main(String[] args) {
        int[] arr = {9, 5, 2, 7, 3, 6, 8};
        shellSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

堆排序

import java.util.Arrays;

//堆排序
public class heapSort {
    public static void heapSort(int[] arr){
        //1.先建立堆
        createHeap(arr);
        //2.需要循环的取出堆顶元素,和最后一个元素交换并删除之
        //  再从0位置进行调整
        int heapsize = arr.length;
        for(int i = 0; i < arr.length; i++){
            //交换0号元素和堆的最后一个元素
            swap(arr, 0, heapsize - 1);
            //把最后一个元素从堆上删除
            heapsize--;
            //从0号位置开始往下进行调整
            shiftDown(arr, heapsize, 0);
        }
    }

    public static void createHeap(int[] arr){
        for(int i = (arr.length - 1 -1) / 2; i >= 0; i--){//最后一个非叶子节点
            shiftDown(arr, arr.length, i);
        }
    }

    public static void shiftDown(int[] arr, int size,int index){
        int parent = index;
        int child = 2 * parent + 1;
        while(child < size){
            //先找出左右子树比较大的
            if(child + 1 < size && arr[child + 1] > arr[child]){
                child = child + 1;
            }
            //再去比价child和parent
            if(arr[parent] < arr[child]){
                swap(arr, parent, child);
            }else{
                break;
            }
            parent = child;
            child = 2 * parent + 1;
        }
    }

    public static void swap(int[] arr, int x, int y){
        int tmp = arr[x];
        arr[x] = arr[y];
        arr[y] = tmp;
    }
    public static void main(String[] args) {
        int[] arr = {9, 5, 2, 7, 3, 6, 8};
        heapSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

归并排序

非递归

import java.util.Arrays;

//归并排序
public class mergeSort {
    //以下是非递归排序
    public static void mergeSortByLoop(int[] arr){
        //gap用来限定分组
        //gap值的含义就是每个待归并数组的长度
        int gap = 1;
        for(; gap < arr.length; gap *=2){
            //当前两个待归并的数组
            for(int i = 0; i < arr.length; i += 2*gap){
                //在这个循环中控制两个相邻的数组进行归并
                //[left, mid)和[mid, right)就要进行归并
                int left = i;
                int mid = i + gap;
                if(mid >= arr.length){//防止越界,判断一下
                    mid = arr.length;
                }
                int right = i + 2 * gap;
                if(right >= arr.length){
                    right = arr.length;
                }
                merge(arr, left, mid, right);
            }
        }
    }

    //归并排序中的关键操作,就是归并两个有序数组
    //使用该merge方法完成数组归并的guoc
    //此处两个数组就通过参数的left, mid, right描述
    //[left, mid)左侧数组
    //[mid, right)右侧数组
    public static void merge(int[] arr, int left, int mid, int right){
        //进行具体的归并操作
        //需要创建一个临时的空间用来保存归并的结果
        //临时空间得能保存下待归并的两个数组
        //即right - left这么长
        if(left >= right){
            //空区间就直接忽略
            return;
        }
        int[] tmp = new int[right - left];
        int tmpIndex = 0;//这个下标表示当前元素该放到临时空间的哪个位置上
        int cur1 = left;
        int cur2 = mid;
        while(cur1 < mid && cur2 < right){
            //此处最好写成<=,目的就是稳定性
            //由于cur1是在左侧区间,cur2是在右侧区间
            //此时如果发现cur1和cur2的值相等
            //就希望左侧区间的cur1在最终结果中仍然是在左侧
            //于是就把cur1对应的元素给先放到结果中
            if(arr[cur1] <= arr[cur2]){
                //把cur1对应的元素插入到临时空间中
                tmp[tmpIndex] = arr[cur1];
                tmpIndex++;
                cur1++;
            }else{
                //把cur2对应的元素插入到临时空间中
                tmp[tmpIndex] = arr[cur2];
                tmpIndex++;
                cur2++;
            }
        }
        //循环结束之后,需要把剩余的元素也都给拷贝到最终结果里
        while(cur1 < mid){
            tmp[tmpIndex] = arr[cur1];
            tmpIndex++;
            cur1++;
        }
        while(cur2 < right){
            tmp[tmpIndex] = arr[cur2];
            tmpIndex++;
            cur2++;
        }
        //还需要把tmp的结果再放回arr数组(因为是原地排序)
        //把原始数组的[left, right)区间替换回排序后的结果
        for(int i = 0; i < tmp.length; i++){
            arr[left + i] = tmp[i];
        }
    }
    public static void main(String[] args) {
        int[] arr = {9, 5, 2, 7, 3, 6, 8};
        mergeSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

递归

import java.util.Arrays;
public class mergeSort {
    public static  void mergeSort(int[] arr){
        _mergeSort(arr, 0, arr.length);
    }
    //辅助递归的方法
    public static void _mergeSort(int[] arr, int left, int right){
        if(right - left <= 1){
            //判定当前区间是不是只有一个元素或者没有元素
            //此时不需要进行排序
            return;
        }
        int mid = (left + right) / 2;
        //先让[left, mid)区间变成有序
        _mergeSort(arr, left, mid);
        //再让[mid, right)区间变成有序
        _mergeSort(arr, mid, right);
        //合并两个有序区间
        merge(arr, left, mid, right);
    }
    public static void merge(int[] arr, int left, int mid, int right){
        //进行具体的归并操作
        //需要创建一个临时的空间用来保存归并的结果
        //临时空间得能保存下待归并的两个数组
        //即right - left这么长
        if(left >= right){
            //空区间就直接忽略
            return;
        }
        int[] tmp = new int[right - left];
        int tmpIndex = 0;//这个下标表示当前元素该放到临时空间的哪个位置上
        int cur1 = left;
        int cur2 = mid;
        while(cur1 < mid && cur2 < right){
            //此处最好写成<=,目的就是稳定性
            //由于cur1是在左侧区间,cur2是在右侧区间
            //此时如果发现cur1和cur2的值相等
            //就希望左侧区间的cur1在最终结果中仍然是在左侧
            //于是就把cur1对应的元素给先放到结果中
            if(arr[cur1] <= arr[cur2]){
                //把cur1对应的元素插入到临时空间中
                tmp[tmpIndex] = arr[cur1];
                tmpIndex++;
                cur1++;
            }else{
                //把cur2对应的元素插入到临时空间中
                tmp[tmpIndex] = arr[cur2];
                tmpIndex++;
                cur2++;
            }
        }
        //循环结束之后,需要把剩余的元素也都给拷贝到最终结果里
        while(cur1 < mid){
            tmp[tmpIndex] = arr[cur1];
            tmpIndex++;
            cur1++;
        }
        while(cur2 < right){
            tmp[tmpIndex] = arr[cur2];
            tmpIndex++;
            cur2++;
        }
        //还需要把tmp的结果再放回arr数组(因为是原地排序)
        //把原始数组的[left, right)区间替换回排序后的结果
        for(int i = 0; i < tmp.length; i++){
            arr[left + i] = tmp[i];
        }
    }
    public static void main(String[] args) {
        int[] arr = {9, 5, 2, 7, 3, 6, 8};
        mergeSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

时间复杂度与空间复杂度

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值