选择排序(常见排序)【直接选择+双向选择+堆排】

目录

一、直接选择排序

1.思路

 2.代码

1.一个公共代码swap:交换数组两个下标对应的值

2.代码实现

3.复杂度分析

①时间复杂度:0(N^2)

②空间复杂度:0(1)

4.稳定性:不稳定

二、双向选择排序 

​编辑1. 思路

2.代码

1.易错点分析

2.代码实现

3.时间复杂度:0(N^2) 

4.稳定性:不稳定

三、堆排序

1.思路

1.总思路

2.每个步骤的具体思路 (从小到大为例)

2.代码实现(详细)

 3.复杂度:

①时间复杂度:0(N*logN)

②空间复杂度:   0(1)

4.稳定性:不稳定


以下例子均为 从小到大 排序 

一、直接选择排序

1.思路

选择选择——> 选择最小的是数据与当前位置交换

每一次从无序区间选出最小(或最大)的一个元素,存放在无序区间的最前(或最后),直到全部待排序的数据元素排完 。
有序区间:[0,i)      无序区间: [ i,arr.lenth)

从第个1元素i开始,往后找出一个最小的数据,把该元素与第一个元素i交换;

从第二个,往后找。。。。。。;从第三个往后找。。。。。。

(即i++,从i处继续往后找一个最小的数据,交换)

 2.代码

1.一个公共代码swap:交换数组两个下标对应的值

/**
     * 交换
     * @param arr
     * @param i 下标
     * @param j 下标
     */
    private void swap(int[] arr,int i,int j){
        int tmp=arr[i];
        arr[i]=arr[j];
        arr[j]=tmp;
    }

2.代码实现

public void selectSort(int[] arr){
        for(int i=0;i<arr.length;i++){
            int j=i+1;
            //记住最小值所在的下标,待会儿好交换
            int minIndex=i;
            for(;j< arr.length;j++){
                if(arr[j]<arr[minIndex]){
                    minIndex=j;
                }
            }
            //交换i和minIndex下标对应的值
            swap(arr,i,minIndex);

        }
    }

3.复杂度分析

①时间复杂度:0(N^2)

N-1 + N-2 +N-3 +........+1=等差数列求和 ——> N^2

【不论有序还是无序,都是0(N^2):因为要一直往后找最小的,要全部找了,才能知道是不是最小的】

②空间复杂度:0(1)

4.稳定性:不稳定

二、双向选择排序 

1. 思路

最左边一个数据下标L,最右边一个数据下标R,从L后第一个数据开始往后依次遍历,把找到的最大数的下标存入maxIndex,把找到的最小数的下标存入maxIndex

2.代码

1.易错点分析

第一行为排序前,第2行为排序后

错误原因分析

如图,此时L==maxIndex。根据代码,L和minIndex的值交换后,maxIndex的值到minIndex去了,所以此时下一行代码不应该是R和maxIndex的值交换,而应是R和minIndex的值交换(因为maxIndex的值到minIndex去了)。

更改后代码:

2.代码实现

/**
     * 交换
     * @param arr
     * @param i 下标
     * @param j 下标
     */
    private void swap(int[] arr,int i,int j){
        int tmp=arr[i];
        arr[i]=arr[j];
        arr[j]=tmp;
    }

    /**
     * 双向选择排序
     */
    public void selectSort2(int[] arr){
        int L=0;
        int R=arr.length-1;

        while(L<R){
            int minIndex=L;
            int maxIndex=L;
            for(int i=L+1;i<=R;i++){
                if(arr[i]<arr[minIndex]){
                    minIndex=i;
                }
                if(arr[i]>arr[maxIndex]){
                    maxIndex=i;
                }
            }
            //交换
            swap(arr,L,minIndex);  //minIndex和L换(指对应下标的数)
            if(maxIndex==L){
                maxIndex=minIndex;
            }
            swap(arr,R,maxIndex);  //maxIndex和R换(指对应下标的数)
            //迭代
            L++;
            R--;
        }
    }

3.时间复杂度:0(N^2) 

4.稳定性:不稳定

从易错点分析第3个图可看出,minIndex和L下标对应的值交换后,两个6的相对位置发生了变化

三、堆排序

1.思路

1.总思路

以“从小到大”排序为例:

1.建立大根堆

2.每次和堆顶元素进行交换 [swap ( top , end )]   

3.向下调整

4. 直到全部交换完成 

总结:大根堆+交换+调整  

2.每个步骤的具体思路 (从小到大为例)

①调整:(向下调整)

获取根节点(parent节点),判断是否有右子树。

若是有右子数节点,右子数和左子树哪个大,大的那个为child。

根节点parent和child比较,哪个大?若child大,则[parent]和[child]交换(总之使parent大)。

若是发生交换,则继续向下调整,迭代:parent=child,child=2*child+1。

循环以上操作,若是不发生交换,则break;

child<=end(end表示逻辑上的最后一个节点的下标)

②建立大根堆:

从最后一个子树开始调整,依次往前一个树调整,直到整棵树都调整完

即获取最后一个子树的树根节点parent : parent=(child-1)/2,向下调整,parent--,循环直到parent=0

③交换:

堆顶值和最后一个元素end值交换,end--, 向下调整数组(该数组逻辑上从堆顶到end),循环该操作,直到end=0,此时堆顶和end相等

2.代码实现(详细)

/**
     *
     * @param arr
     * @param parent
     * @param end 表最后一个节点的下标
     */
    public void shiftDown(int[] arr,int parent ,int end){
        //child此时是左子树节点
        int child=parent*2+1;
        while(child<=end){
            //是否存在右子树? child+1<=end 则存在
            //右子树树和左子树谁大?
            if(child+1<=end && arr[child]<arr[child+1]){
                //有右子树且右子树比左子树大,则child改为右子树节点
                child=child+1;
            }
            //若子树child大于根节点parent,则交换
            if(arr[child]>arr[parent]){
                swap(arr,parent,child);
            }else{
                break;
            }
            //迭代
            parent=child;
            child=2*child+1; //child此时是左子树节点
        }
    }

    /**
     * 创建一个大根堆
     */
    public void createHeap(int[] arr){
        //最后一个节点end
        int end=arr.length-1;
        //最后一颗树的父母节点
        int parent=(end-1)/2;
        //从最后一颗子树开始调整,依次往前一个树调整,直到所有树都调整完
        while(parent>=0){
            shiftDown(arr,parent,end);
            parent--;
        }
    }

    public void heapSort(int[] arr){
        //获取一个大根堆
        createHeap(arr);

        int end=arr.length-1;
        //交换
        while(end>0){
            //交换操作
            swap(arr,0,end);
            end--;
            //向下调整
            shiftDown(arr,0,end);
        }
    }

 3.复杂度:

①时间复杂度:0(N*logN)

②空间复杂度:   0(1)

4.稳定性:不稳定

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值