zoukankan      html  css  js  c++  java
  • 排序算法

    一、内部排序

    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

  • 相关阅读:
    【BZOJ】3052: [wc2013]糖果公园
    【BZOJ】3757: 苹果树
    【BZOJ】1086: [SCOI2005]王室联邦
    【POJ】3648 Wedding
    【POJ】3678 Katu Puzzle
    【POJ】2296 Map Labeler
    【POJ】3207 Ikki's Story IV
    【HDU】1814 Peaceful Commission
    【HDU】2829 Lawrence
    【HDU】3480 Division
  • 原文地址:https://www.cnblogs.com/erdanyang/p/11126060.html
Copyright © 2011-2022 走看看