各种排序算法总结&实现[Java]

链接: python版本.
主要排序算法:冒泡、选择、插入、希尔、归并、快速、堆排序。时间复杂度和空间复杂度及稳定性(原始序列中相同的两个元素经排序后前后顺序不改变)总结如下图。

方法平均时间复杂度最坏时间复杂度最好时间复杂度空间复杂度稳定
冒泡O(n^2)O(n^2)O(n^2)O(1)稳定
选择O(n^2)O(n^2)O(n^2)O(1)不稳定
插入O(n^2)O(n^2)O(n)O(1)稳定
希尔O(nlogn)O(n^2)O(n)O(1)不稳定
归并O(nlogn)O(nlogn)O(nlogn)O(n)稳定
快速O(nlogn)O(n^2)O(nlogn)O(nlogn)不稳定
堆排序O(nlogn)O(nlogn)O(nlogn)O(1)不稳定

1.冒泡排序

从序列第一个数开始,n-1趟遍历,每一趟比较相邻元素,逆序交换,目的在于使得每一趟最后一个元素是最大值。

public class Sort {
    //冒泡排序
    public static void main(String[] args){
        int[] num = {5, 8, 2, 3, 9, 1, 0};
        bubbleSort(num);
        System.out.println(Arrays.toString(num));
    }
    public static void bubbleSort(int[] num){
        int len = num.length;
        for(int i = 0; i < len - 1; i++){
            for(int j = 0; j < len - i - 1; j++){
                if(num[j] > num[j + 1]){
                    int tem = num[j];
                    num[j] = num[j + 1];
                    num[j + 1] = tem;
                }
            }
        }
    }
}

可加入检测机制改进冒泡法,当检测到某一趟无数据交换发生说明已无逆序数,可结束循环得到有序序列。

public class Sort {
    //冒泡排序
    public static void main(String[] args){
        int[] num = {5, 8, 2, 3, 9, 1, 0};
        bubbleSort(num);
        System.out.println(Arrays.toString(num));
    }
    public static void bubbleSort(int[] num){
        int len = num.length;
        for(int i = 0; i < len - 1; i++){
            boolean flag = true;
            for(int j = 0; j < len - i - 1; j++){
                if(num[j] > num[j + 1]){
                    int tem = num[j];
                    num[j] = num[j + 1];
                    num[j + 1] = tem;
                    flag = false;
                }
            }
            if(flag){
                break;
            }
        }
    }
}

2.选择排序

遍历序列,n-1趟,每一趟标记最大元素位置,选出最大元素与最后一个元素交换。相比于冒泡法交换次数减少。

public class Sort {
    //选择排序
    public static void main(String[] args){
        int[] num = {5, 8, 2, 3, 9, 1, 0};
        selectSort(num);
        System.out.println(Arrays.toString(num));
    }
    public static void selectSort(int[] num){
        int len = num.length;
        for(int i = 0; i < len - 1; i++){
            int tem = 0;
            for(int j = 1; j < len - i; j++){
                if(num[tem] < num[j]){
                    tem = j;
                }
            }
            int t = num[len - i - 1];
            num[len - i - 1] = num[tem];
            num[tem] = t;
        }
    }
}

3.插入排序

类似于整理扑克牌,从第二个元素开始,一次处理一个元素,将该元素与已已排序列比较并寻找插入位置(若当前元素小于已排序中元素i,则i开始整体后移,腾出一个空位给当前元素)。共需要处理n-1(2~末尾)个元素。

public class Sort {
    //插入排序
    public static void main(String[] args){
        int[] num = {5, 8, 2, 3, 9, 1, 0};
        insertSort(num);
        System.out.println(Arrays.toString(num));
    }
    public static void insertSort(int[] num){
        int len = num.length;
        for(int i = 1; i < len; i++){
            int tem = num[i];
            int j = i - 1;
            while(j >= 0 && tem < num[j]){
                num[j + 1] = num[j];
                j--;
            }
            num[j + 1] = tem;
        }
    }
}

4.希尔排序

对于插入排序而言,原始序列越短或列表越接近有序,插入比对次数越少,插入排序越高效。希尔排序在插入排序的基础上改进,将无序表进行间隔划分(逻辑划分,可理解为等间隔采样)形成子列表,再对子列表进行插入排序,这样做的目的是构造短的和接近有序的子列表以提升插入排序效率。间隔从n/2开始依次减半,直到为1。

public class Sort {
    //希尔排序
    public static void main(String[] args){
        int[] num = {5, 8, 2, 3, 9, 1, 0};
        shellSort(num);
        System.out.println(Arrays.toString(num));
    }
    public static void shellSort(int[] num){
        int len = num.length;
        //从增量开始插入排序,直至完毕
        for(int step = len / 2; step > 0; step /= 2){
            for(int i = step; i < len; i++){
                int tem = num[i];
                int j = i;
                //j - step表示同组的隔壁元素
                while(j - step >= 0 && tem < num[j - step]){
                    num[j] = num[j - step];
                    j -= step;
                }
                num[j] = tem;
            }
        }
    }
}

5.归并排序

分治思想,将原始序列分为一个个子序列,对子序列进行排序合并,直到整个序列有序。

public class Sort {
    //归并排序
    public static void main(String[] args){
        int[] num = {5, 8, 2, 3, 9, 1, 0};
        int len = num.length;
        mergeSort(num, 0, len - 1);
        System.out.println(Arrays.toString(num));
    }
    public static void mergeSort(int[] num, int l, int r){
        if(l >= r) return;
        int mid = (l + r) / 2;
        mergeSort(num, l, mid);
        mergeSort(num, mid + 1, r);
        merge(num, l, mid, r);
    }
    public static void merge(int[] num, int l, int mid, int r){
        int[] tem = new int[num.length];
        for(int i = l; i <= r; i++){
            tem[i] = num[i];
        }
        int i = l, j = mid + 1;
        for(int k = l; k <= r; k++){
            if(i == mid + 1){
                num[k] = tem[j];
                j++;
            }else if(j == r + 1){
                num[k] = tem[i];
                i++;
            }else if(tem[i] > tem[j]){
                num[k] = tem[j];
                j++;
            }else{
                num[k] = tem[i];
                i++;
            }
        }
    }
}

6.快速排序

(1)选择原始序列中任意元素(一般为头、尾或中间)作为基值。本例选取中间值
(2)一趟排序:将所有小于基值的元素移动到左边,左右大于基值的元素移动到右边,基值放中间。
(3)重复(2)直到所有元素都排好。
快速排序有两种实现方式:
1.递归

public class Sort {
    //快速排序--递归
    public static void main(String[] args){
        int[] num = {5, 8, 2, 3, 9, 1, 0};
        int len = num.length;
        quickSort(num, 0, len - 1);
        System.out.println(Arrays.toString(num));
    }
    public static void quickSort(int[] num, int start, int end){
        if(start >= end) return;
        int index = partition(num, start, end);
        quickSort(num, start, index - 1);
        quickSort(num, index + 1, end);
    }
    public static int partition(int[] num, int start, int end){
        int tem = num[(start + end) / 2];
        int i = start, j = end;
        while(i < j){
            while (i < j && num[i] <= tem) i++;
            while (i < j && num[j] >= tem) j--;
            if(i <= j){
                swap(num, i, j);
                i++;
                j--;
            }
        }
        num[(start + end) / 2] = num[j];
        num[j] = tem;
        return j;
    }
    public static void swap(int[] num, int i, int j){
        int tem = num[i];
        num[i] = num[j];
        num[j] = tem;
    }
}

2.非递归–借助栈实现

public class Sort {
    //快速排序--非递归
    public static void main(String[] args){
        int[] num = {5, 8, 2, 3, 9, 1, 0};
        int len = num.length;
        quickSort(num, 0, len - 1);
        System.out.println(Arrays.toString(num));
    }
    //仅修改了以下函数
    public static void quickSort(int[] num, int start, int end){
        if(start < end) {
            Stack<Integer> set = new Stack<>();
            set.push(start);
            set.push(end);
            while (!set.isEmpty()) {
                int _e = set.pop();
                int _s = set.pop();
                if (_s < _e) {
                    int index = partition(num, _s, _e);
                    set.push(_s);
                    set.push(index - 1);
                    set.push(index + 1);
                    set.push(_e);
                }
            }
        }
    }
    public static int partition(int[] num, int start, int end){
        int tem = num[(start + end) / 2];
        int i = start, j = end;
        while(i < j){
            while (i < j && num[i] <= tem) i++;
            while (i < j && num[j] >= tem) j--;
            if(i <= j){
                swap(num, i, j);
                i++;
                j--;
            }
        }
        num[(start + end) / 2] = num[j];
        num[j] = tem;
        return j;
    }
    public static void swap(int[] num, int i, int j){
        int tem = num[i];
        num[i] = num[j];
        num[j] = tem;
    }
}

7.堆排序

应用二叉堆(满足堆次序的完全二叉树)实现排序。时间复杂度o(nlogn),不稳定。

#思路:建立大顶堆-堆顶与最后一个元素(最小值)交换减小规模形成不包含最后一个元素的子堆-堆调整函数实现子堆调整成大顶堆-重复直到堆规模为1。

public class Sort {
    //堆排序
    public static void main(String[] args){
        int[] num = {5, 8, 2, 3, 9, 1, 0};
        int len = num.length;
        int size = len - 1;
        maxHeap(num, len);
        for(int i = 0; i < len; i++){
            int tem = num[len - 1 - i];
            num[len - i - 1] = num[0];
            num[0] = tem;
            heapify(num, 0, size);
            size--;
        }
        System.out.println(Arrays.toString(num));
    }
    public static void maxHeap(int[] num, int size){
        for(int i = size - 1; i >= 0; i--){
            heapify(num, i, size);
        }
    }
    public static void heapify(int[] num, int currentRootNode, int size){
        if(currentRootNode < size){
            int max = currentRootNode;
            int left = currentRootNode * 2 + 1;
            int right = currentRootNode * 2 + 2;
            if(left < size){
                if(num[max] < num[left]){
                    max = left;
                }
            }
            if(right < size){
                if(num[max] < num[right]){
                    max = right;
                }
            }
            if(max != currentRootNode){
                int tem = num[currentRootNode];
                num[currentRootNode] = num[max];
                num[max] = tem;
                heapify(num, max, size);
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值