八大排序2——不稳定排序

不稳定排序有四种:

  1. 快速排序(quick):每次在一个数组的空间中选择一个基准值,一般选择第一个。以升序为例,从后开始找第一个比基准值小的数,用j来标记。从头开始找第一个比基准值大的数,用i来标记。找的过程中要始终保证i<j。直到某一次i==j。如果是先从后向前找,那么在i==j之前一定是j在跑,所以i和j所指向的数字一定是小于等于基准值的,这也是为什么先从后向前找的原因。然后再将基准值和该数进行交换,基准值左边的都比基准值小,右边的都比基准值大。因此,基准值在数组中的位置已经排好。在用递归对左边的数组和右边的数组进行同样的操作,直到某一次递归传过去的i>j时返回。
 public static void quickSort(int[] a,int start,int end)
    {
        int i=start,j=end;
        if(i>=j){//递归结束条件
            return;
        }
        while(i<j) {
            for (; j > i && a[j] >= a[start]; j--);//从后向前找第一个小于基准的数的下标
            for (; i < j && a[i] <= a[start]; i++);//从前向后找第一个大于基准的数的下标
            if (i < j) {
                int t = a[i] + a[j];
                a[i] = a[j];
                a[j] = t - a[j];
            }
        }
        int t=a[start]+a[j];//基准值和i==j时的下标进行交
        a[start]=a[j];
        a[j]=t-a[j];
        quickSort(a,start,j);
        quickSort(a,j+1,end);
    }
    public static void main(String[] args) {
        int[] a={43,5,-2,19,35,6,100,-8,365,78,1121};
        quickSort(a,0,a.length-1);
        for(int i=0;i<a.length;i++)
        {
            System.out.println(a[i]);
        }
    }

对数组num={5,4,5,2,1,6,7,8,9,10}进行排序,从发先前找到1,从前向后也找到1,第一个5和1进行交换,两个5的相对位置发生变化,因此排序不稳定。
快排采用了二分的思想,因此时间复杂度为O(nlog2n),每一次递归中申请两个变量,空间复杂度也为O(nlog2n)。

  1. 堆排序(stack):在数组上利用堆的数据结构,以升序为例,每次将最大值调整到堆顶,然后和最后一个元素交换,无序空间长度减一。在剩下的数组中再次进行调整。再找到剩下数里面的最值。然后交换。直到剩余一个元素。堆结构的特点:从堆顶元素向下对每一个位置进行编号,节点i如果有左子女,左子女的编号一定是2i,如果有右子女,右子女的编号一定是2i+1。叶子节点j的双亲节点的下标一定是i/2。通过这种关系,在一组父子节点体系中,将最值调整到父节点位置。
 public static void stackSort(int[] a)
    {
        for(int end=a.length-1;end>0;end--) {
            for (int parent = end / 2; parent > 0; parent--) {
                //判断左子女
                if (a[parent * 2] > a[parent]) {
                    int t = a[parent * 2] + a[parent];
                    a[parent * 2] = a[parent];
                    a[parent] = t - a[parent];
                }
                //判断右子女
                if (parent * 2 + 1 <= end && a[parent * 2 + 1] > a[parent]) {
                    int t = a[parent * 2 + 1] + a[parent];
                    a[parent * 2 + 1] = a[parent];
                    a[parent] = t - a[parent];
                }
            }
            //交换a[end]和a[1]
            int t = a[end] + a[1];
            a[1] = a[end];
            a[end] = t - a[end];
        }
    }
    public static void main(String[] args) {
        int[] a={0,45,9,-1,4567,892,-34,0,357,15,6,45,5,94,31,26,78};
        stackSort(a);
        for(int i=1;i<a.length;i++)
        {
            System.out.println(a[i]);
        }
    }
  1. 选择排序(select):将一个数组分为有序和无序区间,以升序为例,每次在无序区间中选择最小的数和无序空间中的第一个数进行交换。然后无序空间的长度从前面减去一位。继续在无序空间中找最小值。也可以一次找到最小和次小,分别和无序空间中的第一个和第二个进行交换。这样可以提高速度。
 public static void selectSort(int[] a)
    {
        for(int i=0;i<a.length-1;i++)
        {
            //寻找区间i~length-1中的最小值
            int min=i;
            for(int j=i;j<a.length;j++)
            {
                if(a[j]<a[min])
                    min=j;
            }
            int t=a[i]+a[min];
            a[i]=a[min];
            a[min]=t-a[i];
        }

    }
    public static void main(String[] args) {
        int[] a={12,-5,90,3,64,52,31,29,45};
        selectSort(a);
        for(int i=0;i<a.length;i++)
        {
            System.out.println(a[i]);
        }
    }

对数组num={5,2,3,4,5,1,6,7,8,9};进行排序时,第一次找到的最小值为1,1和5进行交换,两个5的相对位置发生相对变化。因此排序不稳定。时间复杂度为O(N2),空间复杂度为O(1)。

  1. 希尔排序(Shell):希尔排序是对插入排序的一种改进。插入排序操作的时相邻的两个数,希尔排序操作的时有一定间隔的,并且这个间隔在一致缩小(每次除2)。最终缩小到1。假设数组长度为n,第一次选的间隔为n/2。对相邻为n/2的每组数进行插入排序。
 public static void shellSort(int[] a)
    {
        for(int d=a.length/2;d!=0;d/=2)//控制间隔
        {
            //a[i]是当前要进行插入排序的元素
            for(int i=d;i<a.length;i++)
            {
                int t=a[i];
                int j;
                for(j=i-d;j>-1&&a[j]>t;a[j+d]=a[j],j-=d);//向前找第一个不大于a[i]的数的小标。
                a[j+d]=t;//将a[i]插入到该数的后面。
            }
        }
    }
    public static void main(String[] args) {
        int[] a={40,-2,-6,48,3,10000,-56,78,25,34,-100,94,6};
        shellSort(a);
        for(int i=0;i<a.length;i++)
        {
            System.out.println(a[i]);
        }
    }

时间复杂度最坏为O(N2)。最好O(N),空间复杂度为O(1)。

猜你喜欢

转载自blog.csdn.net/Hello_1024/article/details/83099317