排序算法

一、内部排序

1、冒泡排序(交换排序)

 

    public void maopaosort(int[] nums) {
        int len = nums.length;
        if(len<=1) {
            return;
        }
        boolean flag = true;
        for(int i=0;i<len-1;i++) {
            flag = true;
            for(int j=0;j<len-1-i;j++) {
                if(nums[j]>nums[j+1]) {
                    flag = false;
                    nums[j] = nums[j]^nums[j+1];
                    nums[j+1] = nums[j]^nums[j+1];
                    nums[j] = nums[j]^nums[j+1];
                }
            }
            if(flag) {
                break;
            }
        }
    }

2、简单选择排序(选择排序)

 

    public void choosesort(int[] nums) {
        int len = nums.length;
        if(len<=1) {
            return;
        }
        int k = 0;
        int item = 0;
        for(int i=0;i<len-1;i++) {
            item = nums[i];
            k = i;
            for(int j=i+1;j<len;j++) {
                if(nums[j]<item) {
                    item = nums[j];
                    k = j;
                }
            }
            if(k!=i) {
                nums[i] = nums[i]^nums[k];
                nums[k] = nums[i]^nums[k];
                nums[i] = nums[i]^nums[k];
            }
        }
    }

 

3、快速排序(交换排序)

解题思路:递归,自顶向下,分冶法

经典的快速排序:

    public static void sort(int[] nums,int start,int end) {
        if(nums==null||start>=end) {
            return;
        }
        int temp = nums[start];
        int begin = start;
        int last = end;
        while(begin<last) {
            while(begin<last&&nums[last]>=temp) --last;
            nums[begin] = nums[last];
            while(begin<last&&nums[begin]<=temp) ++begin;
            nums[last] = nums[begin];
        }
        nums[begin] = temp;
        sort(nums,start,begin-1);
        sort(nums,begin+1,end);
    }

 

 快排另一思路(个人觉得效率会高一些):

public void quicksort(int[] nums,int start,int end) {
        if(start>=end) {
            return;
        }
        int low = start;
        int high = end;
        int t = nums[start];
        while(low<high) {
            while(low<high&&nums[high]>=t) high--;
            if(low==high) {
                break;
            }
            nums[low] = nums[high];
            ++low;
            while(low<high&&nums[low]<=t) low++;
            if(low==high) {
                break;
            }
            nums[high] = nums[low];
            --high;
        }
        //最后循环出来的结局是low==high
        nums[low] = t;
        quicksort(nums,start,low-1);
        quicksort(nums,low+1,end);
    }

 快速排序总结:

1、终止条件

2、while循环

3、两边递归

public void sortImpl(int[] nums, int begin, int last) {
        if(begin>=last) {
            return;
        }
        int start = begin;
        int end = last;
        int temp = nums[start];
        while(start<end) {
            while(start<end&&nums[end]>=temp) {
                --end;
            }
            nums[start] = nums[end];
            while(start<end&&nums[start]<=temp) {
                ++start;
            }
            nums[end]=nums[start];
        }
        nums[start] = temp;
        sortImpl(nums, begin,start-1);
        sortImpl(nums, start+1,last);
    }

 

4、堆排序(选择排序)

 构造堆:采用筛选法;一般升序采用大顶堆,降序采用小顶堆。

解题思路:二叉树+递归

    public void heapsort(int[] nums) {
        int len = nums.length;
        if(len<=1) {
            return;
        }
        for(int i=len/2-1;i>=0;i--) {
            createheap(nums,len,i);
        }
        for(int i=len-1;i>0;i--) {
            nums[i] = nums[i]^nums[0];
            nums[0] = nums[i]^nums[0];
            nums[i] = nums[i]^nums[0];
            createheap(nums,i,0);
        }
    }
    public void createheap(int[] nums, int len, int parent) {
        if(2*parent+2<=len-1&&nums[parent]<nums[2*parent+2]) {
            nums[parent] = nums[parent]^nums[2*parent+2];
            nums[2*parent+2] = nums[parent]^nums[2*parent+2];
            nums[parent] = nums[parent]^nums[2*parent+2];
            createheap(nums,len,2*parent+2);
        }
        if(2*parent+1<=len-1&&nums[parent]<nums[2*parent+1]) {
            nums[parent] = nums[parent]^nums[2*parent+1];
            nums[2*parent+1] = nums[parent]^nums[2*parent+1];
            nums[parent] = nums[parent]^nums[2*parent+1];
            createheap(nums,len,2*parent+1);
        }
    }

 堆排序总结:

1、建堆

2、排序

3、注意堆排序的精髓,减少交换次数很重要

public void sortImpl(int[] nums, int len) {
        // TODO Auto-generated method stub
        for(int i=len/2-1;i>=0;--i) {
            heapSort(nums, len, i);
        }
        int temp = 0;
        for(int i=len - 1;i>0;--i) {
            temp = nums[0];
            nums[0] = nums[i];
            nums[i] = temp;
            heapSort(nums, i, 0);
        }
    }
    public void heapSort(int[] nums, int len, int parent) {
        int child1 = 2*parent+1;
        int child2 = 2*parent+2;
        int temp = 0;
        if(child2<len) {
            if(nums[child1]>nums[child2]) {
                if(nums[child1]>nums[parent]) {
                    temp = nums[parent];
                    nums[parent] = nums[child1];
                    nums[child1] = temp;
                    heapSort(nums, len, child1);
                }
            }else {
                if(nums[child2]>nums[parent]) {
                    temp = nums[parent];
                    nums[parent] = nums[child2];
                    nums[child2] = temp;
                    heapSort(nums, len, child2);
                }
            }
        }else {
            if(child1<len&&nums[child1]>nums[parent]) {
                temp = nums[child1];
                nums[child1] = nums[parent];
                nums[parent] = temp;
                heapSort(nums, len, child1);
            }
        }
    }

 

5、直接插入排序

 

    public void directinsertsort(int[] nums){
        int len = nums.length;
        if(len<=1) {
            return;
        }
        int t = 0;
        int j=0;
        for(int i=1;i<len;i++) {
            t = nums[i];
            for(j=0;j<i;j++) {
                if(t<nums[j]) {
                    break;
                }
            }
//这里是折半插入排序的代码大家也可以看一下
//            int high = i-1;
//            int low = 0;
//            int temp = 0;
//            while(low<=high) {
//                temp = (low+high)/2;
//                if(nums[temp]<=nums[i]) {
//                    low=temp+1;
//                }else {
//                    high = temp-1;
//                }
//            }
//            j=low;
            for(int k=i;k>=j+1;k--) {
                nums[k]=nums[k-1];
            }
            nums[j] = t;
        }
    }

直接插入排序总结: 

1、正常的插入排序思想

2、不需要查找的过程才为最佳

3、处理结尾条件

 

public void sortImpl(int[] nums, int len) {
        // TODO Auto-generated method stub
        int temp = 0;
        int j = 0;
        for(int i = 1;i<len;++i) {
            if(nums[i]<nums[i-1]) {
                temp = nums[i];
                for(j=i;j>0;--j) {
                    if(temp<nums[j-1]) {
                        nums[j] = nums[j-1];
                    }else {
                        nums[j] = temp;
                        break;
                    }
                }
                if(j==0){
                    nums[j] = temp;
                }
            }
        }
    }

 

 

 

6、希尔排序(插入排序)

 

    public void shellsort(int[] nums) {
        int len = nums.length;
        if(len<2) {
            return;
        }
        for(int step=len/2;step>=1;step/=2) {
            unitdirectsort(nums, len, step);
        }
    }
    public static void unitdirectsort(int[] nums,int len, int step) {
        int t = 0;
        int j = 0;
        for(int k=0;k<step;k++) {
            for(int i=k+step;i<len;i+=step) {
                t = nums[i];
                for(j=k;j<i;j+=step) {
                    if(nums[i]<nums[j]) {
                        break;
                    }
                }
                for(int m=i;m>=j+step;m-=step) {
                    nums[m] = nums[m-step];
                }
                nums[j] = t;
            }
        }
    }

希尔排序总结: 

    public void sortImpl(int[] nums, int len) {
        // TODO Auto-generated method stub
        if(len==1) {
            return;
        }
        int step=1;
        while(step<=len/3) {
            step = step*3+1;
        }
        for(int i = step;i>=1;i=(i-1)/3) {
            shellSort(nums, len, i);
        }
    }
    public void shellSort(int[] nums, int len, int step) {
        int temp = 0;
        int k = 0;
        for(int i=step;i<len;++i) {
            if(nums[i]<nums[i-step]) {
                temp = nums[i];
                for(k=i;k>=step;k-=step) {
                    if(temp<nums[k-step]) {
                        nums[k] = nums[k-step];
                    }else {
                        nums[k] = temp;
                        break;
                    }
                }
                if(k<step) {
                    nums[k] = temp;
                }
            }
        }
    }

希尔排序(并行算法):

public class CurrentShellSort extends AbstractSort {
    private static Executor pool = Executors.newFixedThreadPool(8);
    public CurrentShellSort() {
        // TODO Auto-generated constructor stub
    }

    @Override
    public void sortImpl(int[] nums, int start, int end) {
        // TODO Auto-generated method stub

    }

    @Override
    public void sortImpl(int[] nums, int len) {
        // TODO Auto-generated method stub
        if(len<=1) {
            return;
        }
        int h = 1;
        while(h<=len/3) {
            h = h*3 + 1;
        }
        for(int step = h;step>=1;step=(step-1)/3) {
            shellSort(nums, len, step);
        }
    }
    public void shellSort(int[] nums, int len, int step) {
        int temp = 0;
        int k = 0;
        CountDownLatch latch = null;
        if(len>step) {
            latch = new CountDownLatch(Math.min(2*step, len)-step);
        }
        for(int i=step;i<Math.min(2*step, len);++i) {
            pool.execute(new ShellSortTask(nums, i, step, len, latch));
        }
        try {
            latch.await();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

class ShellSortTask implements Runnable{
    private int[] nums = null;
    private int start = 0;
    private int step = 0;
    private int len = 0;
    private CountDownLatch latch = null;
    public ShellSortTask(int[] nums, int start, int step, int len,CountDownLatch latch) {
        // TODO Auto-generated constructor stub
        this.nums = nums;
        this.start = start;
        this.step  = step;
        this.len = len;
        this.latch = latch;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        int temp = 0;
        int k = 0;
        for(int i = start;i<len;i+=step) {
            if(nums[i]<nums[i-step]) {
                temp = nums[i];
                for(k = i;k>=step;k-=step) {
                    if(temp<nums[k-step]) {
                        nums[k] = nums[k-step];
                    }else {
                        nums[k] = temp;
                        break;
                    }
                }
                if(k<step) {
                    nums[k] = temp;
                }
            }
        }
        latch.countDown();
    }
    
}

 

7、归并排序(非递归)

 解题思路:分冶法+自底向上

    public void mergesort(int[] nums) {
        int len = nums.length;
        if(len<=1) {
            return;
        }
        int[] nums2 = new int[len]; 
        boolean flag = true;
        for(int step = 1;step<len;step*=2) {
            if(flag) {
                unitmergesort(nums, nums2,len, step);
                flag = false;
            }else {
                unitmergesort(nums2, nums,len, step);
                flag = true;
            }
        }
        //注意这里最后的处理结果要放到nums里面
        if(!flag) {
            for(int i=0;i<len;i++) {
                nums[i] = nums2[i];
            }
        }
    }
    public static void unitmergesort(int[] nums,int[] nums2,int len,int step) {
        int m = 0;
        int n = 0;
        int k=0;
        int i=0;
        for(i=0;i<len-2*step+1;i+=2*step) {
            m=i;
            n=i+step;
            for(k=i;k<i+2*step&&m<i+step&&n<i+2*step;k++) {
                if(nums[m]<nums[n]) {
                    nums2[k] = nums[m++];
                }else {
                    nums2[k] = nums[n++];
                }
            }
            while(m<i+step) nums2[k++] = nums[m++];
            while(n<i+2*step) nums2[k++] = nums[n++];
        }
        //注意多余元素的处理,这里的处理非常重要
        if(i<len-step) {
            m=i;
            n=i+step;
            for(k=i;k<len&&m<i+step&&n<len;k++) {
                if(nums[m]<nums[n]) {
                    nums2[k] = nums[m++];
                }else {
                    nums2[k] = nums[n++];
                }
            }
            while(m<i+step) nums2[k++] = nums[m++];
            while(n<len) nums2[k++] = nums[n++];
        }
    }

第二种比较简单的思路:

    public void sortImpl(int[] nums, int start, int end) {
        // TODO Auto-generated method stub
        int len = end - start + 1;
        int[] nums2 = new int[len];
        boolean flag = true;
        for(int step = 1; step < len; step *= 2) {
            if(flag) {
                unitSortImpl(nums,nums2,len,step);
                flag = false; 
            }else {
                unitSortImpl(nums2,nums,len,step);
                flag = true;
            }
        }
        if(!flag) {
            System.arraycopy(nums2, 0, nums, 0, len);
        }
    }
    public void unitSortImpl(int[] nums, int[] nums2,int len, int step) {
        int m = 0 ;
        int n = 0;
        int s = 0;
        int t = 0;
        int j = 0;
        for(int i = 0;i+step<len;i+=2*step) {
            m = i;
            s = i+step;
            n = s;
            t = i+2*step>len?len:i+2*step;
            while(m<s&&n<t) {
                if(nums[m]<=nums[n]) {
                    nums2[j++] = nums[m++];
                }else {
                    nums2[j++] = nums[n++];
                }
            }
            while(m<s) {
                nums2[j++] = nums[m++];
            }
            while(n<t) {
                nums2[j++] = nums[n++];
            }
        }
    }

 归并排序总结:

1、创建另外一个数组nums2

2、从step等于1开始~step<len归并

3、归并的方法,注意结尾的处理

4、如果结果在nums2中,需要拷贝到nums里面

public void sortImpl(int[] nums, int len) {
        // TODO Auto-generated method stub
        int[] nums2 = new int[len];
        boolean flag = true;
        for(int step = 1; step < len; step *= 2) {
            if(flag) {
                unitSortImpl(nums,nums2,len,step);
                flag = false; 
            }else {
                unitSortImpl(nums2,nums,len,step);
                flag = true;
            }
        }
        if(!flag) {
            System.arraycopy(nums2, 0, nums, 0, len);
        }
    }
    public void unitSortImpl(int[] nums, int[] nums2,int len, int step) {
        int m = 0 ;
        int n = 0;
        int s = 0;
        int t = 0;
        int j = 0;
        for(int i = 0;i+step<len;i+=2*step) {
            m = i;
            j = m;
            s = i+step;
            n = s;
            t = i+2*step>len?len:i+2*step;
            while(m<s&&n<t) {
                if(nums[m]<=nums[n]) {
                    nums2[j++] = nums[m++];
                }else {
                    nums2[j++] = nums[n++];
                }
            }
            while(m<s) {
                nums2[j++] = nums[m++];
            }
            while(n<t) {
                nums2[j++] = nums[n++];
            }
        }
        while(j<len) {
            nums2[j]=nums[j];
            ++j;
        }
    }

 

8、归并排序(递归)

解题思路:分冶法+自顶向下

最后所有的分支都递归到了len==1而截止。

注意:这里的nums和nums2最开始里面必须有相同的元素,最开使nums2的元素不能是其他值,也就是排序前要把nums的值全部复制到nums2里面;还有就是最后的结果是放在nums2里面了。

    public void mergesort(int[] nums,int[] nums2,int len,int start) {
        if(len==1) {
            nums2[0]=nums[0];
            return;
        }
        int mid = 0;
        mid = len/2;
        mergesort(nums2, nums, mid, start);
        mergesort(nums2, nums, len-mid,start+mid);
        unitmergesort(nums, nums2, len,start,mid);
    }
    public static void unitmergesort(int[] nums,int[] nums2,int len,int start,int step) {
        int m =start;
        int n = start+step;
        int i = 0;
        for(i=start;i<start+len&&m<start+step&&n<start+len;i++) {
            if(nums[m]<nums[n]) {
                nums2[i]=nums[m++];
            }else {
                nums2[i]=nums[n++];
            }
        }
        while(m<start+step) nums2[i++] = nums[m++];
        while(n<start+len) nums2[i++] = nums[n++];
    }

第二种思路:

    public void sortImpl(int[] nums, int start, int end) {
        // TODO Auto-generated method stub
        int len = end - start + 1;
        int[] nums2 = new int[len];
        System.arraycopy(nums, 0, nums2, 0, len);
        mergeSort(nums,nums2,0,end);
    }
    public void mergeSort(int[] nums, int[] nums2, int start, int end) {
        if(end-start<=0) {
            return;
        }
        int mid  =  (start+end)/2;
        mergeSort(nums, nums2, start, mid);
        mergeSort(nums, nums2, mid+1, end);
        combineMergeSort(nums2, nums, start, mid, end);
    }
    public void combineMergeSort(int[] nums, int[] nums2, int start, int mid, int end) {
        int m = start;
        int n = mid + 1;
        int s = n;
        int t = end + 1;
        int j = start;
        while(m<s&&n<t) {
            if(nums[m]<=nums[n]) {
                nums2[j++] = nums[m++];
            }else {
                nums2[j++] = nums[n++];
            }
        }
        while(m<s) {
            nums2[j++] = nums[m++];
        }
        while(n<t) {
            nums2[j++] = nums[n++];
        }
    }

 归并排序总结:

1、创建nums2并且要把nums的元素复制到nums2当中

2、终止条件

3、从中分两份分别归并

4、合并这两份

5、注意nums与nums2的方向问题

public void sortImpl(int[] nums, int start, int end) {
        // TODO Auto-generated method stub
        int len = end - start + 1;
        int[] nums2 = new int[len];
        System.arraycopy(nums, start, nums2, start, len);
        mergeSort(nums2,nums,start,end);
    }
    public void mergeSort(int[] nums, int[] nums2, int start, int end) {
        if(end==start) {
            //nums2[start]=nums[start];
            return;
        }
        int mid  =  (start+end)/2;
        mergeSort(nums2, nums, start, mid);
        mergeSort(nums2, nums, mid+1, end);
        combineMergeSort(nums, nums2, start, mid, end);
    }
    public void combineMergeSort(int[] nums, int[] nums2, int start, int mid, int end) {
        int m = start;
        int n = mid + 1;
        int s = n;
        int t = end + 1;
        int j = m;
        while(m<s&&n<t) {
            if(nums[m]<=nums[n]) {
                nums2[j++] = nums[m++];
            }else {
                nums2[j++] = nums[n++];
            }
        }
        while(m<s) {
            nums2[j++] = nums[m++];
        }
        while(n<t) {
            nums2[j++] = nums[n++];
        }
    }

 

 9、树形选择排序(锦标赛排序)(选择排序)

 

    public void treechoosesort(int[] nums) {
        int len = nums.length;
        if(len<=1) {
            return;
        }
        //需要构造的二叉树的高度
        int h = (int)Math.ceil(Math.log(len)/Math.log(2))+1;
        int k = (int)Math.pow(2, h)-1;//需要构造的数组的大小
        int[] temps = new int[k];
        int m = (int)Math.pow(2, h-1)-1;//1~h-1层的元素的个数总和
        int m1=m;
        for(int i=0;i<len;i++) {
            temps[m1++] = nums[i];
        }
        for(int i=m1;i<k;i++) {
            temps[i] = Integer.MAX_VALUE;
        }
        for(int n=0;n<len;n++) {
            m1=m;
            while(m1!=0) {
                for(int i=m1;i<k;i+=2) {
                    temps[i/2] = temps[i]>temps[i+1]?temps[i+1]:temps[i];
                }
                m1/=2;
            }
            nums[n] = temps[0];
            m1=0;
            for(int i=1;i<h;i++) {
                if(temps[2*m1+1]==temps[0]) {
                    m1 = 2*m1+1;
                }else {
                    m1 = 2*m1+2;
                }
            }    
            temps[m1]=Integer.MAX_VALUE;
        }
    }

 10、表插入排序

    public void biaoinsertsort(int[] nums) {
        int len = nums.length;
        if(len<=1) {
            return;
        }
        int[] temps = new int[len];
        int[] nums2 = new int[len];
        for(int i=0;i<len-1;i++) {
            temps[i] = i+1;
        }
        temps[len-1]=-1;//记录链表尾
        int head=0;//记录链表头
        int prev = 0;//记录已排序链表的最后一个元素的下标
        int j =0;//用来遍历已排序的链表
        int t=0;
        for(int i=1;i<len;i++) {
            j=head;
            while(j!=i) {
                if(nums[j]>nums[i]) {
                    temps[i] = j;
                    if(j==head) {
                        head=i;
                    }else {
                        temps[t] = i;
                    }
                    if(i+1!=len) {
                        temps[prev]=i+1;
                    }else {
                        temps[prev]=-1;
                    }
                    break;
                }
                t=j;
                j=temps[j];
            }
            if(i==j) {
                prev=i;
            }
        }
        //已经形成列表,下面就是把它按顺序放置在数组中
        t=head;
        j=0;
        while(t!=-1) {
            nums2[j++]=nums[t];
            t=temps[t];
        }
        for(int i=0;i<len;i++) {
            nums[i]=nums2[i];
        }
    }

11、计数排序

    public void jishusort(int[] nums) {
        int len = nums.length;
        int k = 100;
        int[] temps = new int[k+1];
        for(int i=0;i<len;i++) {
            temps[nums[i]]+=1;
        }
        int sum=0;
        int t=0;
        for(int j=0;j<k;j++) {
            if(temps[j]!=0) {
                for(int i=0;i<temps[j];i++) {
                    nums[t++] = j;
                }
            }
        }
    }

 

12、基数排序

(2)、LSD从个位开始,n为数组中数的最大位数

    public void cnsort(int[] nums,int n) {
        int len = nums.length;
        if(len<=1) {
            return;
        }
        int t = 0;
        int m = 1;
        List<Integer>[] buckets = new List[10];
        for(int i=0;i<10;i++) {
            buckets[i] = new ArrayList<Integer>();
        }
        for(int k=0;k<n;k++) {
            for(int i=0;i<len;i++) {
                buckets[nums[i]/m%10].add(nums[i]);
            }
            t=0;
            for(int i=0;i<10;i++) {
                for(Integer j:buckets[i]) {
                    nums[t++] = j;
                }
                buckets[i].clear();
            }
            m *=10;
        }
    }

 (2)、MSD从高位开始,需要用到递归

13、桶排序

桶中数组采用插入法排序

基数排序就是基于桶排序的,只是基数排序只需要10个桶

算法总结:

 

参考文献

算法总结:https://blog.csdn.net/hellozhxy/article/details/79911867

堆排序:https://www.cnblogs.com/chengxiao/p/6129630.html

归并排序:https://www.cnblogs.com/chengxiao/p/6194356.html

快速排序:https://www.cnblogs.com/chengxiao/p/6262208.html

表插入排序:https://www.cnblogs.com/ciyeer/p/9075303.html

计数排序:https://www.cnblogs.com/zfdd/p/8034485.html

基数排序:https://blog.csdn.net/u011948899/article/details/78027838

桶排序漫画:https://yq.aliyun.com/articles/652774

桶排序:https://www.cnblogs.com/Unicron/p/9461075.html

posted @ 2019-07-03 14:09  海平面下的我们  阅读(256)  评论(0编辑  收藏  举报