• 算法系列——排序算法


       

    此表格转自此链接博客(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)

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

  • 相关阅读:
    codeforces 540D Bad Luck Island (概率DP)
    Codevs 1205 单词反转(Vector以及如何输出string)
    Codeforces 977D Divide by three, multiply by two(拓扑排序)
    Codeforces 977B Two-gram(stl之string掉进坑)
    HDU 6186 CS Course (连续位运算)
    HDU 1005 Number Sequence(矩阵快速幂,快速幂模板)
    HDU 1004 Let the Balloon Rise(STL初体验之map)
    2018天梯赛、蓝桥杯、(CCPC省赛、邀请赛、ICPC邀请赛)校内选拔赛反思总结!
    Newcoder Wannafly13 B Jxy军训(费马小定理、分数在模意义下的值)
    TCP的可靠传输(依赖流量控制、拥塞控制、连续ARQ)
  • 原文地址:https://www.cnblogs.com/hugofly/p/4424374.html
Copyright © 2020-2023  润新知