算法-排序那些事

一、冒泡排序:

1、通过比较相邻两个元素,把大的元素放在索引大的位置上,这样比较n-1-i次后,就将最大的元素冒泡到最后面
2、这样的过程要找n-1次
时间复杂度:
最好情况已经排好序O(n)
最差情况反序O(n^2)

 private static void bubbling(int[] a,int n){
        int temp;
        for(int i = 0; i < n-1; i++){
            for(int j = 0; j < n-1-i; j++){
                if(a[j]>a[j+1]){
                    temp=a[j];
                    a[j]=a[j+1];
                    a[j+1]=temp;
                }
            }
        }
    }

冒泡排序改进1:
考虑到过程1存在不需要交换的数据,不需要交换的数据在过程2也不需要交换
记录最后一次交换的位置,下一次循环到这个位置就可以了

  private static void bubbling1(int[] a,int n){
        int temp;
        int posEnd = n-1;//一次循环中最后一次交换的位置
        int pos;
        while(posEnd>0){
            //当不需要交换的时候,自然也就排序完成
            pos=0;
            for(int j = 0; j < posEnd; j++){
                if(a[j]>a[j+1]){
                    pos = j;
                    temp=a[j];
                    a[j]=a[j+1];
                    a[j+1]=temp;
                }
            }
            posEnd = pos;
        }
    }

冒泡排序改进2:
考虑到每次循环只找到最大的值或者最小的值,可以每次找到最小和最大的值吗?

    private static void bubbling2(int[] a,int n){
        int temp,j;
        int low = 0;
        int high = n-1;
        while(low<high){
            for(j=low;j<high;j++){
                if(a[j]>a[j+1]){
                    temp=a[j];
                    a[j]=a[j+1];
                    a[j+1]=temp;
                }
            }
            high--;
            for(j=high;j>low;j--){
                if(a[j]<a[j-1]){
                    temp=a[j];
                    a[j]=a[j-1];
                    a[j-1]=temp;
                }
            }
            low++;
        }
    }

二、快速排序:

分治法的思想
1、取一个基数(这里取第一个元素)
2、让小于这个基数的数放在基数的左边,大于这个基数的数放在这个基数的右边
3、递归过程1、2
重要的是过程2,从数组的两端遍历,依次和基数进行判断,右端如果大于基数(右端一定要先判断,这样最后两端要相遇的时候,
保证了在数值小的地方相遇,然后相遇的地方与基数互换,当然,如果基数选择的是最后一个元素,那么就要从左端开始判断),
那么++,左端如果小于基数,那么–,当找到了右端的小于基数的值和左端的大于基数的值,如果左右两端没有遇到,交换这两
个值,然后再判断左右两端是否遇到,如果没遇到,那么继续这个过程,直到左右两端遇到。
例如:3,9,5,2,6,1;1与9交换3,1,5,2,6,9;2与5交换3,1,2,5,6,9;这时high==low,2与3交换2,1,3,5,6,9,
这样2,1在3的左边,而5,6,9在3的右边。
时间复杂度:
最好的情况是每次把上一次的数组平均分成两个子数组。设数组总数一共为n,如果把这n个数每次分成2半最后每个数组只
包含一个元素,假设要分k次,则2的k次方=n,解得k=log2n(log以2为底对n取对数).也就是说要分log2n次,而每次都
是处理n个数据。所以总的时间复杂度为O(nlog2n)。

  private static void quickSort(int[] a,int left,int right){
        if(left<right){
            int key = a[left];
            int low = left;
            int high=right;
            int temp;
            while(low!=high){
                while(low<high && a[high]>=key){
                    high--;
                }
                while(low<high && a[low]<=key){
                    low++;
                }
                if(low<high){
                    temp = a[low];
                    a[low]= a[high];
                    a[high]=temp;
                }
            }
            a[left]=a[low];
            a[low]=key;
            quickSort(a,left,low-1);
            quickSort(a,low+1,right);
        }
    }

三、插入排序:

从数组第二个元素开始(第一个元素已经排好序)当作插入值key,先判断key是否比它左边的哥们大,如果比它左边的哥们大,那么不需要插入,就在原位置就行了,
将key与排好序的从右到左依次作比较,如果key一直是小数,那么就将比较值往右移位,直到找到一个小于等于key或者找到最后一个,就在这个位置上将key插入。
时间复杂度:
最好的情况下数组已经排好序,线性复杂度O(n)
最差的情况下逆序O(n^2)

 private static void insertSort(int[] a,int n){
        int key;
        int j;
        for(int i=1;i<n;i++){
            if(a[i]<a[i-1]){
                j=i;
                key = a[i];
                while(j>0 && key<a[j-1]){
                    a[j]=a[j-1];
                    j--;
                }
                a[j]=key;
            }
        }
    }

四、选择排序:

每次从待排序的数组中找到最小值,然后放在固定的位置
首先设置第一个元素是最小值,然后遍历后面的元素与之比较,找出最小值min,记录最小值的索引index(用于存放被最小值替换下来的值)
时间复杂度:
O(n^2)

    private static void selectSort(int[] a,int n){
        int min;
        int index;
        int temp;
        for(int i = 0;i<n;i++){
            min = a[i]; 
            index = i;
            for(int j=i+1;j<n;j++){
                if(a[j]<min){
                    min=a[j];
                    index=j;
                }
            }
            temp = a[i];
            a[i] = min;
            a[index] = temp;
        }
    }

五、堆排序:

1、建堆
2、将堆顶的元素和最后一个元素替换,替换完,剩下的元素需要再次调整为堆
3、重复过程2,,直到替换了n-1次,完成排序

    private static void heapSort(int[] a,int n){
        int temp;
        buildHeap(a,n);
        for(int i=n-1;i>0;i--){
            //堆顶和最后一个节点交换
            temp = a[i];
            a[i] = a[0];
            a[0] = temp;
            //交换之后再把没排序的堆进行调整
//          buildHeap(a,i);
            adjustHeap(a,i,0);
        }
    }

初始化堆
从最后一个父节点开始,到堆顶,从下到上调整堆。

    private static void buildHeap(int[] a, int n) {
        for(int i = n/2;i>=0;i--){
            adjustHeap(a,n,i);
        }
    }

调整堆:
@parama数组,n数组的长度,i要调整的父节点
假设父节点是最大值,如果子节点不超出n(也就是子节点存在),那么将子节点与父节点比较,将最大值设为父节点,
如果最大值是在子节点中,那么将子节点的值与父节点的值替换后,被替换的子节点可能就不再是堆,需要调整以子节点为父节点成为堆。
直到子节点是叶子节点为止

    private static void adjustHeap(int[] a, int n, int i) {
        int lchild = 2*i+1;//左子节点
        int rchild = 2*i+2;//右子节点
        int max = i;
        int temp;
        if(i<n/2){
            if(lchild<n && a[max]<a[lchild]){
                max = lchild;
            }
            if(rchild<n && a[max]<a[rchild]){
                max = rchild;
            }
            if(i!=max){
                //将最大值放在父节点
                temp = a[max];
                a[max] = a[i];
                a[i] = temp;
                adjustHeap(a,n,max);
            }
        }
    }

六、归并排序

    /**
     * 归并排序:
     * 将数组用递归进行二分分开,直到高位和低位相邻的时候,分开结束,进行归并排序
     * @param a 待排序的数组
     * @param low 低位
     * @param high 高位
     */
    private static void mergeSort(int[] a, int low, int high){
        if(low<high){
            int mid = (low+high)/2;
            mergeSort(a,low,mid);
            mergeSort(a,mid+1,high);
            merge(a,low,mid,high);
        }
    }
/**
     * 将数组a[low,mid]和a[mid+1,high]归并排序到一个新数组,这个过程是这样的:
     * 1、取a[low]和a[mid+1]进行比较,然后将小者放进新数组,新数组位置+1,low+1,
     * 大者也放进新数组中,新数组位置+1,mid+1+1,这个过程直到两个数组有一个到达尽头
     * 2、将两个数组剩下的部分也放进新数组中
     * 3、这样这个新数据就是两个待排序的数据的归并排序数组,将这个新数组复制到最终要排序的数组a中,排序结束。
     * @param a 带排序
     * @param low 低位
     * @param mid 中位
     * @param high 高位
     */
    private static void merge(int[] a, int low, int mid, int high) {
        int i = low;
        int j = mid+1;
        int k = 0;
        int[] b = new int[high-low+1];
        while(i<=mid && j<=high){
            if(a[i]<a[j]){
                b[k++]=a[i++];
            }else{
                b[k++]=a[j++];
            }
        }
        while(i<=mid){
            b[k++]=a[i++];
        }
        while(j<=high){
            b[k++]=a[j++];
        }
        for(i=0;i<k;i++){
            a[low+i] = b[i];
        }
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值