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

    一、冒泡排序

    //基本算法
    for(i=1;i<list.length;k++){
        //perform the kth pass
        for(j=0;list.length-i;j++){ 
            if(list[j]<list[j+1]){
                swap list[j] with list[j];
            }
        }
    }
    
    //改进算法
    //如果在某次遍历时没有发生交换,那么就不用进行下一次遍历
    for(i=1;i<list.length;k++){
        needNextPass=false;
        for(j=0;j<list.length-i;j++){ 
            if(list[j]<list[j+1]){
                swap list[j] with list[j];
                needNextPass=true;//need next pass
            }
        }
    }

    对于改进算法的排序时间,最佳情况:O(n);最坏情况:O(n2)

    二、归并排序

    (1)算法描述:将数组分为两半,对每部分递归地应用归并排序。在两部分都排好序后,对他们进行归并。

     public static void mergeSort(int[] list){
         if(list.lenght>1){
             mergeSort(list[0~list.length/2]);
             mergeSort(list[list.length/2+1~list.length-1]);
             
             merge list[0~list.length/2] with list[list.length/2+1~list.length-1];
         }
     }

    (2)算法实现:

    public  class MergeSort{
        public static void mergeSort(int[] list){
            if(list.length>1){
                int[] firstHalf=new int[list.length/2];
                System.arraycopy(list,0,firstHalf,0,list.length/2);
                mergeSort(firstHalf);
                
                int[] secondHalf=new int[list.length-list.length/2];
                System.arraycopy(list,list.length/2,secondHalf,0,secondHalf.length);
                mergeSort(secondHalf);
             
                int[] temp=merge(firstHalf,secondHalf);
                System.arraycopy(temp,0,list,0,temp.length);
            }
        }
        private static int[] merge(int[] list1,int[] list2){
            int[] temp=new int[list1.length+list2.length];
            
            int current1=0,current2=0,current3=0;
            
            while(current1<list1.length&&current2<list2.length){
                if(list1[current1]<list2[current2])
                  temp[current3++]=list1[current1++];
                else
                  temp[current3++]=list2[current2++];            
            }
            while(current1<list1.length){
                temp[current3++]=list1[current1++];
            }
            while(current2<list2.length){
                temp[current3++]=list2[current2++];
            }
            
            return temp;
        }
        public static void main(String[] args){
            int[] list={2,3,2,5,6,1,-1,3,14,12};
            mergeSort(list);
            for(int e:list)
            System.out.print(e+" ");
        }
    }

    (3)总结:归并排序时间O(nlogn)。该算法优于选择排序,插入排序和冒泡排序。java.util.Arrays类中的sort方法是使用归并排序算法的变体实现的。

    三、快速排序

    (1)算法描述:在数组中选择一个称为主元(pivot)的元素,将数组分为两部分使得第一部分中的所有元素都小于或等于主元,而第二部分都大于或等于主元。依次对两部分递归地应用快速排序算法。

    public static void quicksort(int[] list){
        if(list.length>1){
            select a pivot;
            patition list into list1 an list2 such that
               all elements in list1 <= pivot and
               all elements in list2 > pivot
            quicksort(list1);
            quicksort(list2);
        }
    }

    (2)算法实现:

    package Algorithm;
    
    public class QuickSort{
        public static void quicksort(int[] list){
            quicksort(list,0,list.length-1);
        }
        public static void quicksort(int[] list,int left,int right){
            if(right>left){
                int temp=list[left];
                int i=left;
                int j=right;
    
                while(i!=j){
                    //顺序很重要,要先从右边开始找 
                    while(list[j]>=temp && i<j){
                        j--; 
                    }               
                    //再找左边的 
                    while(list[i]<=temp && i<j){
                        i++; 
                    }                  
                    //交换两个数在数组中的位置 
                    if(i<j){
                      int t=list[i]; 
                      list[i]=list[j]; 
                      list[j]=t;                  
                    } 
                }
                //最终将基准数归位 
                list[left]=list[i]; 
                list[i]=temp;
    
                quicksort(list,left,i-1);
                quicksort(list,i+1,right);
            }
        } 
                
        public static void main(String[] args) {
            int[] list={6,5,3,8,4,9,7};
            quicksort(list);
            for(int u:list)
                System.out.print(u+",");
        }
    
    }

    (3)总结:在平均状况下,排序 n 个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实作出来。

    四、堆排序

    (1)堆的定义:n个元素序列{k1,k2,...,kn}当且仅当满足以下关系时,称之为堆。

    ki<=k2i且ki<=k2i+1 (小根堆) 或 ki>=k2i且ki>=k2i+1  (大根堆)。

         可将其对应为完全二叉树。堆顶元素为n个数中的最小/大值。若在输出堆顶的最小/大值之后,使得剩余n-1个元素又建成一个堆,则得到n个元素中的次小/大值。依次类推,便可得到一个有序序列,这个过程称为堆排序

    (2)算法描述:

    由堆排序的定义可知,该算法的关键在于建堆和删除堆顶元素后的调整

    //建堆
    Let the last node be current node;
    while(the current node > its parent){
         Swap current node with its parent;
    }
    //删除堆顶元素后的调整
    Move the last node to replace the root;
    Let the root be the current node;

    (3)算法实现

    //Heap类
    class Heap<E extends Comparable>{
        private java.util.ArrayList<E> list=new java.util.ArrayList<E>();
    
        public Heap(){
    
        }
    
        public Heap(E[] objects){
            for(int i=0;i<objects.length;i++){
                add(objects[i]);
            }
        }
        //建堆
        public void add(E newObject){
            list.add(newObject);
            int currentIndex=list.size()-1;
    
            while(currentIndex>1){
                int parrentIndex=(currentIndex-1)/2;
                if(list.get(currentIndex).compareTo(list.get(parrentIndex))>0){
                    E temp=list.get(currentIndex);
                    list.set(currentIndex,list.get(parrentIndex));
                    list.set(parrentIndex,temp);
                }
                else
                    break;
                currentIndex=parrentIndex;
            }
        }
    
        //删除堆顶元素后的调整
        public E remove(){
            if(list.size()==0)
                return null;
            E removedObject=list.get(0);
            list.set(0,list.get(list.size()-1));
            list.remove(list.size()-1);
    
            int currentIndex=0;
            while(currentIndex<list.size()){
                int leftChildIndex=2*currentIndex+1;
                int rightChildIndex=2*currentIndex+2;
                //找出左右子树中较大的
                if(leftChildIndex>=list.size()) break;//已经是堆了
                int maxIndex=leftChildIndex;
                if(rightChildIndex<list.size()){//若有又子树
                    if(list.get(maxIndex).compareTo(list.get(rightChildIndex))<0){
                        maxIndex=rightChildIndex;
                    }
                }
    
                //比较目前节点与左右子树中的最大值,若目前节点小,则交换
                if(list.get(currentIndex).compareTo(list.get(maxIndex))<0){
                    E temp=list.get(currentIndex);
                    list.set(currentIndex,list.get(maxIndex));
                    list.set(maxIndex,temp);
                    currentIndex=maxIndex;
                }
                else
                    break;
            }
            return removedObject;
    
        }
        public int getSize(){
            return list.size();
        }
    }
    
    //使用Heap类进行排序
    public class HeapSort{
        public static <E extends Comparable> void heapSort(E[] list){
            Heap<E> heap=new Heap<E>();
    
            for(int i=0;i<list.length;i++){
                heap.add(list[i]);
            }
    
            for(int i=list.length-1;i>=0;i--){
                list[i]= heap.remove();
            }
        }
    
        public static void main(String[] args){
            Integer[] list={5,4,3,2,1};
            heapSort(list);
            for (Integer u:list)
                System.out.print(u+",");
        }
        
    }

    (4)总结:和归并排序一样,时间都为O(nlogn)。为了归并两个子数组,归并需要一个临时数组,而堆排序不需要临时的数组空间,因此,堆排序的空间效率高于归并排序。

  • 相关阅读:
    Ubuntu的防火墙UFW
    使用Xshell连接Ubuntu
    Markdown 11种基本语法
    Git Push 避免用户名和密码方法
    "git rm" 和 "rm" 的区别
    无限级分类实现思路
    1. Git 克隆代码
    Git 笔记
    git 远程分支创建与推送
    ci 笔记
  • 原文地址:https://www.cnblogs.com/bukekangli/p/3982698.html
Copyright © 2011-2022 走看看