算法系列——排序算法

   

此表格转自此链接博客(http://www.cnblogs.com/nannanITeye/archive/2013/04/11/3013737.html)

1.插入排序

插入排序的方法:从第二个数字num[i]开始,依次与它前边的num[j]比较,如果num[i]>num[j],比较下一个num[j],如果num[i]<num[j],则将num[j]和之后的数字依次向后          移动一个位置,为num[i]腾出空间,将num[i]放在num[j]的位置上。

public static void main(String[] args) throws IOException {
    
        int[] num = {4,8,3,9,5,7,2};
         sort(num);
         for(int i =0;i<num.length;i++){
         System.out.println(num[i]);
         }
    }
    private static void sort(int[] num) {
         int temp = 0;
          
         for(int i = 1;i<num.length;i++){
             
             for(int j =0;j<i;j++){
                 if(num[i]>num[j]){
                     continue;
                 }
                 if(num[i]<num[j]){
                     temp = num[i];
                     for(int x=i;x>j;x--){                    //找到数字应该放置的位置后,将应在位置和实际位置之间的数字向后移一位,以便插入数字。
                        num[x] = num[x-1];
                     }
                     num[j] =temp;
                 }
             }
         }
        
    }

2.希尔排序

希尔排序的方法:第一步:选取增量序列的值,一般是按除2的方式选取,直至1 gap=num.length/2;gap=gap/2...

                      第二步:如果gap=num.leng/2=3,则将数列中的第0项,第3项,第6项...放在一起;第1项,第4项,第7项...放在一起,分别按插入排序的方法比较。

                      最后一步:gap=3/2=1;就将数列按照插入排序的方法排序一次,得出结果。

     public static void main(String[] args){
         int[] num = {3,3,5,2,7,0,1,4,9,6,8};
        sort(num);
         for(int i = 0;i<num.length;i++){
             System.out.println(num[i]);
         }
     }
     public static void sort(int[] num){
         int gap = num.length/2;
          
          for(int k = gap;k>0;k=k/2){
             
           for(int i=0;i<num.length;i++){
             for(int j = i+k;j<num.length;j+=k){
                 
                     if(num[i]>num[j]){
                     int temp = num[i];
                     num[i] = num[j];
                     num[j] = temp;
                 }
             }
          }          
     }
     }
     

 

3.冒泡排序

冒泡排序的方法:第一步:将num[0]与之后的num[i]依次比较,如果num[0]<num[i],继续比较下一个,如果num[0]>num[i],将num[0]和num[i]互换。第一步结束之              后,数组中的最小值就是num[0];

        第二步:将num[1]与之后的num[i]依次比较,重复第一步。第二小的数字便是num[1].

public static void main(String[] args){
          int[] num = {9,4,2,7,2,8,4,1};
          sort(num);
          for(int i =0;i<num.length;i++){
              System.out.println(num[i]);
          }
     }
      public static void sort(int[] num){
          int temp = 0;
          for(int i=0;i<num.length-1;i++){
              for(int j=i+1;j<num.length;j++){
                  if(num[i]<num[j]){
                      continue;
                  }
                  else{
                      temp = num[i];
                      num[i] = num[j];
                      num[j] = temp;
                  }
              }
          }
      }

4.快速排序

快速排序的方法:分治法+填坑法。

   第一步:首先取最右端(或最左端或随机都可以,但尽量在最左或最右,此次按最右端)的值num[num.length-1]赋给中间值middle,此时num.length-1处可以看作没有了,是一个坑,所以我们 就可以找一个值来填充它。

        那么把哪个位置上的值填充到这里呢?由于我们的目的是按照从小到大的顺序排列这个数列,所以当我们在数列的最后一位有空位置的时候,我们自然就要把比middle大的值放在空位置上。

        那么怎么来找这一个比middle大的值?我们就需要两个指针,一个low,一个high,low初始指向num[0],high初始指向num[num.length-2],由它们带领来查找合适的填坑值。

        当高位有空位时,就从低位找一个比middle大的值放过来,当低位有空位时,就从高位找一个比middle小的值来填充,同时low和high也在不断逼近,当low=high时,第一次排序完成。把middle的值放在low和high处。

   第二步:low和high在的位置就是中间值的位置,然后递归将middle左边的数列排序,middle右边的数列排序。

        注释掉的是自己写的时候犯的错误,包括对于方法参数的不明确。

        最坏情况:排一个已经排好序的数列,时间复杂度是O(n2);

public class Test {

     public static void main(String[] args){
         int[] num = {1,7,2,4,6,8,5};
         
              /*int middle = getMiddle(num,0,num.length-1);
              getMiddle(num,0,middle-1);
              getMiddle(num,middle+1,num.length-1);*/
         
           sort(num,0,num.length-1);
           for(int i = 0;i<num.length;i++){
               System.out.print(num[i]);
           }
           
            
     }
      
           public static int getMiddle(int[] num,int low,int high){
               
                  int middleValue = num[high];//int middleValue = num[num.length-1];
               while(low<high){
                   while(low<high&&num[low]<middleValue){
                       low++;
                   }
                   num[high] = num[low];
                   while(low<high&&num[high]>middleValue){
                       high--;
                   }
                   num[low] = num[high];
                }
                    
                   num[low] = middleValue;
                   return low;
                
     
               
           }
           
      public static void sort(int[] num,int low,int high){
          int middle;
          if(low<high){
              middle = getMiddle(num,low,high);
              getMiddle(num,low,middle-1);
              getMiddle(num,middle+1,high);
          }
      }

}

 

以下是一开始按照自己的理解写的代码,很复杂,而且最后出现了错误,如果不加注释掉的那三行,能获取正确的middle,加上之后返回的middle就不对了。

  public static int getMiddle(int[] num){
          int temp = 0;
          int middle = 0;
          int j =0;
          int value = num[num.length-1];
          for(int i =0;i<num.length-1;i++){
              if(num[i]<value){
                  if(i==0){
                  continue;
                  }else{if(j==0){
                      continue;
                  }else{
                      temp = num[i];
                      num[i]= num[j];
                      num[j] = temp;
                      j++;
                      }
                  }
              }else{
                  if(j==0){
                  j=i;
                  
                   }
                  else{
                     continue;
                  }
              }  
          }
           middle =j;
          //int emp = value;
          //num[num.length-1] = num[j];
          //num[j] = emp;
         return middle;
          
      }

 5.简单选择排序

选择排序的方法:和冒泡法类似,冒泡法是便利num[i]之后的数字,遇见小的就换;选择排序是将较小数字的角标记录,然后继续遍历,遇见更小的就更新存储角标的变量,最后将变量中角标对应的数字变换位置。

public static void sort(int[] num){
            for(int i=0;i<=num.length-2;i++){
                int temp = i;
                for(int j=i+1;j<=num.length-1;j++){
                    if(num[j]<num[temp]){
                        temp = j;
                    }
                    else{
                        continue;
                    }
                }
                if(temp!=i){
                    int cha = num[i];
                    num[i] = num[temp];
                    num[temp] = cha;
                }
            }
        }

 

6.堆排序(选择排序的改进)

完全二叉树:出最后一层之外,二叉树的每一层都是满的,在最后一层上只缺少右侧的结点。                                                                                              

最大最小堆:最大就是从上至下结点值是按降序排列的,越往上越大,越往左越大。

构造堆的时候,结点都是有规律的,如上图,左子结点的序号等于父结点的2倍(从0开始就是2倍加1),右子结点的序号等于父结点序号的2倍+1(从0开始就是2倍加2),在构造堆的时候可以利用这一点。

堆主要有两种操作:1.结点插入:将插入结点放到最后的位置,然后维护堆(依次与父结点比较大小)。2.结点删除:删除操作只能删除根节点,然后让最后一个结点成为根结点,之后维护堆。

 

排序方法是在构造堆后,输出num[0],然后将最后一个结点与根节点互换,然后重新构造长度减去1的堆,再输出num[0],重复以上操作。

            构造堆的过程就是将数列中最大值放到根节点。

 public static void main(String[] args){
         int[] num = {3,5,2,7,0,1,4,9};
         makeHeap(num,num.length-1,(num.length-2)/2);
         adjustHeap(num);
     }

    private static void makeHeap(int[] num,int heapSize,int index) {
             int left,right,large;
          
            for(int i = index;i>=0;i--){     
             left = i*2+1;
             right = i*2+2;
             large = i;
              
             if(left<=heapSize&&num[left]>num[i]){
                  
                 large = left;
             }
             if(right<=heapSize&&num[right]>num[i]){
                 if(num[right]>num[left]){
                 large = right;
                 }
             }
             if(large!=i){
                  
                 int temp =num[i];
                 num[i] = num[large];
                 num[large] = temp;
             }
           }

    }
    public static void adjustHeap(int[] num){
        int a;
        for(int i=0;i<=num.length-1;i++){
            a=num[0]; 
            System.out.println(a);
            int temp = num[num.length-1-i];
            num[0] = temp;
            num[num.length-1-i]=temp;
            makeHeap(num,num.length-2-i,(num.length-3-i)/2);
        }
    }

 7.归并排序

归并排序的方法:数列不断的被分割,当分到只有两个或一个不能再分的时候,就开始合并,合并的结果一开始临时存入到result数组中,每一次合并完成,就把result中的数放到num中对应位置(i+start)上。

 public static void main(String[] args){
         int[] num = {3,5,2,7,0,1,4};
         sort(num,0,num.length-1);
         for(int i = 0;i<num.length;i++){
             System.out.println(num[i]);
         }
     }
     public static void sort(int[] num,int start,int end){
          
         if(start<end){
         sort(num,start,(start+end)/2);
         sort(num,(start+end)/2+1,end);
         merge(num,start,(start+end)/2,end);
         }
         
     }
    private static void merge(int[] num, int start, int mid, int end) {
          int[] result= new int[end -start+1];
          int left = start;
          int right = mid+1;
          int index = 0;
          
          while(left<=mid&&right<=end){
              if(num[left]<num[right]){
                  result[index++] = num[left++];
              }
              else {
                  result[index++] = num[right++];
              }
          }
          while(left<=mid){
              result[index++]= num[left++];
          }
          while(right<=end){
              result[index++] = num[right++];
          }
          for(int i = 0;i<result.length;i++){
              num[i+start] = result[i];
          }
          
        
    }

     

 8.计数排序  O(n)

计数排序的方法:将数列遍历,在一个新的数列A里记录下每个数重复出现的次数,A的长度等于最大元素的值加一,然后将A中数列值累加,反向填充新数列。

 

 public static void main(String[] args){
         int[] num = {3,3,5,6,3,5,6};
         sort(num);
         
     }
     public static void sort(int[] num){
         int a =num[0];
         int sum = 0;
         for(int i = 0;i<num.length-1;i++){
             if(num[i]>a){
                 a=num[i];
             }
         }
         
         int[] num1 = new int[a+1]; 
         for(int j = 0;j<num.length;j++){
             num1[num[j]]+=1;
         }
int sum =0; for(int k=0;k<num1.length;k++){ num1[k]+=sum;
sum = num1[k];
}

int[] result = new int[num.length]; 反向填充for(int q = 0;q<result.length;q++){ System.out.println(result[q]); } }

 

9.基数排序  O(n)

类似于重新排好扑克牌,先把四组相同花色的放到一起,然后再按从小到大顺序排列。第一次的基数是花色,第二次是大小。或者是先把面值相同的放到一起,然后再按花色组合。

如果数列中数字是两位数,那么先取第二位为基数,将基数相同的放到一起,从小到大组成新的数列;然后将新数列以第一位为基数,重新把基数相同的放到一起,然后按照基数大小顺序组成新的数列就是排好的数列。

如果数的长度不一样,前面补0。

10.桶排序 O(n)

桶排序方法:把一定范围内的数放到一个桶中,然后将各个桶内的数据进行排序,然后将各个桶内的数据合并

 

posted @ 2015-04-14 11:11  HugoFly  阅读(300)  评论(0编辑  收藏  举报