当前位置: 首页 > article >正文

常见的排序

概述

常见的10大排序,这里先详细的介绍前7种排序;

稳定性

定义:如果两个元素具有相同的关键字,那么在排序后他们的相对顺序不变;

排序前有标记的5在前面,排序后依旧在前面即稳定,如果位置互换了就不稳定;

直接插入排序

- 原理:将未排序的数据插入到已排序部分的合适位置。通常从第二个元素开始,将其与前面已排好序的元素进行比较,找到合适位置插入。


- 使用场景:对于接近有序的数组效率较高。


- 与其他算法的联系:希尔排序是对插入排序的优化。插入排序在处理部分有序数据时具有一定优势,其思想在一些高级算法处理小规模数据时也会被借鉴,比如快速排序在处理小规模数据时可能会切换为插入排序。

代码:

  public void Insertint(int[] array){
        for (int i = 1; i < array.length; i++) {
            int j=i-1;
            int tem=array[i];
            for ( ; j >=0; j--) {
                if(array[j]>tem){
                  array[j+1]=array[j];
                }else {
                    array[j+1]=tem;
                    break;
                }
                array[j]=tem;
            }
        }
    }

 时间复杂度:O(n^2)       空间复杂度:O(1)      稳定性:稳定

希尔排序

- 原理:对插入排序的一种优化,通过设置不同的步长序列,逐步对数据进行分组和局部排序,最终实现整体数据的有序。


- 使用场景:中等规模数据的排序。


- 与其他算法的联系:源于插入排序,通过改进插入排序的方式提高效率。在处理某些数据时,性能可能介于简单排序算法和高级排序算法之间。

代码:

    public void shell(int[] array){
        int gap=array.length/2;
        while (gap>0){
            shellsert(array,gap);
            gap=gap/2;
        }
    }

    private void shellsert(int[] array, int gap) {
        for (int i = gap; i < array.length; i++) {
            int j=i-gap;
            int tem=array[i];
            for ( ; j >=0; j-=gap) {
                if(array[j]>tem){
                    array[j+gap]=array[j];
                }else {
                    array[j+gap]=tem;
                    break;
                }
                array[j]=tem;
            }
        }
    }

 时间复杂度:O(n^1.3)       空间复杂度:O(1)      稳定性:不稳定

选择排序

- 原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。


- 使用场景:适用于数据量较小、对效率要求不高的情况。


- 与其他算法的联系:和冒泡排序一样是较为简单的算法。但选择排序在每一轮只进行一次交换,效率相对冒泡排序可能会高一些。与堆排序有一定联系,堆排序在选择最大(小)元素的过程中利用了堆这种数据结构,而选择排序是直接遍历寻找。

public static void selectSort(int[] array){                            //选择排序
        for (int i = 0; i < array.length; i++) {
            int minindex=i;
            int j=0;
            for ( j = i+1; j < array.length; j++) {     //每次找出最小值的下标,再换到i位置
                if(array[minindex]>array[j]){
                    minindex=j;
                }
            }
            swap(array,minindex,i);
        }
    }

 public static void swap(int[] array,int ret1,int ret2){
        int tem=array[ret1];
        array[ret1]=array[ret2];
        array[ret2]=tem;
 }

 时间复杂度:O(n^2)       空间复杂度:O(1)      稳定性:不稳定

堆排序

- 原理:利用堆这种数据结构进行排序。首先将待排序序列构建成一个大顶堆(或小顶堆),然后将堆顶元素与最后一个元素交换,再对剩余元素重新调整为堆,如此反复,直到序列有序。


- 使用场景:适用于需要高效排序且对空间要求不高的情况。


- 与其他算法的联系:在选择最大(小)元素方面与选择排序有相似之处,但利用堆的特殊性质可以更高效地进行选择。

代码:

 public static void  HeapSort(int[] array){//堆排序
        CreatHeap(array);          //建堆
        int end=array.length-1;
        while (end>0){                
            swap(array,0,end);     //把最大值和最后一个互换,
            siftdown(array,0,end); //除最后一个找出最大值
            end--;
        }
    }

    public static void CreatHeap(int[] array){
        for (int parent = (array.length-1-1)/2; parent >=0; parent--) {
            siftdown(array,parent,array.length);
        }
    }
    public static void siftdown(int[] array,int parent,int len){
        int child=2*parent+1;
        while (child<len){
            if(child+1<len&&array[child+1]>array[child]){//左右孩子中找出大的孩子
                child++;
            }
            if(array[parent]<array[child]){  //<是大根堆,>是小根堆
               swap(array,parent,child);
                parent=child;
                child=2*parent+1;
            }else {
                break   ;
            }
        }
    }
    public static void swap(int[] array,int i,int j){
        int tem=array[i];
        array[i]=array[j];
        array[j]=tem;
    }

 时间复杂度:O(nlogn)       空间复杂度:O(1)      稳定性:不稳定

冒泡排序

- 原理:重复地走访要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。


- 使用场景:数据量较小且对效率要求不高的情况。


- 与其他算法的联系:是一种较为简单直观的排序算法,效率较低。其他一些算法可以看作是对冒泡排序思想的改进和扩展。例如希尔排序可以看作是对插入排序的优化,而插入排序在某些方面又与冒泡排序有相似之处,都是通过不断比较和交换元素来实现排序。

代码:
 

    public static void bubbleSort(int[] array){
        for(int i=0;i<array.length;i++){
            for (int j = 0; j < array.length-1-i; j++) {
                if(array[j]>array[j+1]){
                    int tem=array[j]    ;
                    array[j]=array[j+1];
                    array[j+1]=tem;
                }
            }
        }
    }

    public static void bubbleSortPerfect(int[] array){//优化后的冒泡排序,有序可达到O(n)
        for(int i=0;i<array.length;i++){
            boolean flg=false;//设置标志位
            for (int j = 0; j < array.length-1-i; j++) {
                if(array[j]>array[j+1]){
                    int tem=array[j]    ;
                    array[j]=array[j+1];
                    array[j+1]=tem;
                    flg=true;
                }
            }
            if(!flg){
                break;
            }
        }
    }

 时间复杂度:O(n^2)       空间复杂度:O(1)      稳定性:稳定

快速排序

- 原理:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。


- 使用场景:数据量大且随机性较强的情况。


- 与其他算法的联系:采用分治思想,与归并排序类似。但快速排序是在原地进行划分,效率相对较高。在某些情况下会使用插入排序处理小规模数据,以提高整体效率。

代码:(挖坑法)

    public static void quickSort(int[] array){
        quick2(array,0,array.length-1);
        // write code  here
    }

    private static void quick(int[] array, int start, int end) {
        if(start>=end){
            return ;
        }
        int pivot = partition(array,start,end);
        quick(array,start,pivot-1);
        quick(array,pivot+1,end);
    }
    private static int partition(int[] array,int stact,int end){//挖坑法
        int tem=array[stact];
        int left=stact;
        int right=end;
        while (left<right){
            while (left<right&&array[right]>=tem){
                right--;
            }
            array[left]=array[right];
            while (left<right&&array[left]<=tem){
                left++;
            }
            array[right]=array[left];
        }
        array[right]=tem;
        return right;
    }

Hoare​​​​​​​​​​​​​​

private static int partition(int[] array, int left, int right) {
    int i = left;
    int j = right;
    int pivot = array[left];
    while (i < j) {
        while (i < j && array[j] >= pivot) {
        j--;
        }
        while (i < j && array[i] <= pivot) {
        i++;
        }    
        swap(array, i, j);
    }
    swap(array, i, left);
    return i;
}

 时间复杂度:O(nlogn)       空间复杂度:O(logn)      稳定性:不稳定 

归并排序

- 原理:采用分治策略,将待排序序列分成若干个子序列,分别进行排序,然后将已排序的子序列合并成一个有序的序列。


- 使用场景:对稳定性要求较高,数据量大的情况。


- 与其他算法的联系:和快速排序一样基于分治思想。归并排序是稳定的排序算法,在某些需要保证数据原有顺序的场景下有优势。快速排序在某些方面可以看作是归并排序的一种更高效但不稳定的变体。
代码(递归):

    public static void mergeSort(int[] array){
        mergeSort1(array,0,array.length-1);
    }

    private static void mergeSort1(int[] array, int left, int right) {
        if(left>=right){
            return;
        }
        int mid=(left+right)/2;
        mergeSort1(array,left,mid);          //分离
        mergeSort1(array,mid+1,right);  //分离
        merge(array,left,mid,right);        //合并
    }

    private static void merge(int[] array, int left, int mid, int right) {//数组有序合并
        int s1=left;
        int e1=mid;
        int s2=mid+1;
        int e2=right;
        int k=0;
        int[] num=new int[right-left+1];
        while (s1<=e1&&s2<=e2){
            if(array[s1]<=array[s2]){
                num[k++]=array[s1++];
            }
            if(array[s1]>array[s2]){
                num[k++]=array[s2++];
            }
        }
        while (s1<=e1){
            num[k++]=array[s1++];
        }
        while (s2<=e2){
            num[k++]=array[s2++];
        }
        for (int i = 0; i <k; i++) {
            array[left+i]=num[i];
        }
    }


 时间复杂度:O(nlogn)       空间复杂度:O(n)      稳定性:稳定 

代码(非递归):

// 归并排序---非递归
    public static void mergeSortNor(int[] array){
        int gap=1;
        while (gap<=array.length){
            for (int i = 0; i < array.length; i=i+2*gap) {
                int left=i;
                int mid=left+gap-1;
                if(mid>array.length){
                    mid=array.length;
                }
                int right=mid+gap;
                if(right>array.length-1) {
                    right = array.length - 1;
                }

                merge(array,left,mid,right);
            }
            gap=gap*2;
        }
    }


http://www.kler.cn/a/294946.html

相关文章:

  • 高效运维:构建全面监控与自动化管理体系
  • 力扣.15 三数之和 three-sum
  • 从0开始学docker (每日更新 24-11-7)
  • 国标GB28181视频平台EasyCVR私有化部署视频平台对接监控录像机NVR时,录像机“资源不足”是什么原因?
  • 小程序中引入下载到本地的iconfont字体图标加载不出来问题解决
  • 原生 JavaScript基本内容和常用特性详解
  • Leetcode 152. 乘积最大子数组(Medium)
  • 通信工程学习:什么是ARQ自动重传请求
  • 【计算机视觉】语义分割输入图像尺寸
  • 快速傅里叶变换(FFT)及其在多项式乘法中的应用 —— 深入分析与 Python 实现
  • android AccessibilityService合法合规采集大众点评app商店商品详情(2024-09-02)
  • 【Qt笔记】QListWidget控件详解
  • 经济管理专业数据库介绍
  • 算法学习:模拟
  • Unity Adressables 使用说明(三)构建内容(Build Content)
  • 85、 探针
  • Java基础 1. Java开发环境搭建
  • 数据处理与数据填充在Pandas中的应用
  • 基于 RocketMQ 的云原生 MQTT 消息引擎设计
  • 智能体叙事实验:MixlabNodes新增Her页面
  • Android --- observer和observerForever的区别
  • Ansible自动化运维入门:从基础到实践的全面指南
  • 福建聚鼎科技:开一家装饰画店铺需要投资多少钱
  • Java|Java 中 JSONPath 的使用
  • history增加时间显示
  • PostgreSQL的repmgr工具介绍