您的位置:首页 > 编程语言 > Java开发

关于JAVA的几种排序算法研究

2015-08-07 17:08 423 查看
本文对当前主流排序算法原理和具体java实现,主要包括冒泡排序,插入排序,选择排序,希尔排序,堆排序,快速排序,归并排序进行讲解。算法功能基本测试通过,读者若有更好的算法实现请留评论里面,感激不尽。

一、冒泡排序(BubbleSortDemo),冒泡排序基本原理:打个简单的比方就如同我们烧开水时的气泡,大的气泡一个一个的往上冒,即冒泡排序的每一轮排序都选出最大的数拍在最后或者最前。冒泡排序的时间复杂度为O(n2)。

//parm score为输入排序数组,return排序后数组

public static int[] BubbleSortDemo(int [] score) {

    for (int i = 0; i < score.length -1; i++){    

             for(int j = 0 ;j < score.length - i - 1; j++){    

                 if(score[j] >score[j + 1]){    

                     int temp = score[j];

                     score[j] = score[j + 1];

                     score[j + 1] = temp;

               }

              } 
}
return score;

}

二、选择排序(selectionSort),选择排序的基本原理:用白话讲就是首先从一组数中选出一个最小的数或者最大的数,然后将这个最小的数或者最大的数与此轮排序第一个数进行交换。选择排序的时间复杂度为O(n*n)。

public static int[] selectionSort(int[] score){

        for(int i = 0; i < score.length-1; ++i){

            int k = i;

            for(int j = i; j < score.length; ++j){

                if(score[k] > score[j]){

                    k = j;

                }

            }

            if(k != i){

                int temp = score[i];

                score[i] = score[k];

                score[k] = temp;

            }

        }

        return score;

}

三、插入排序 (insertSort),插入排序的基本原理:用白话讲就是像我们打扑克牌,把从1到K的牌排好序,我们一般采用的方法时取出俩张牌排好大小,然后取第三张牌,插入这俩种中合适的位置,然后在取第四张牌插入,前三张已经排好序的位置,直到所有的牌都排好为止。用比较正式的话来讲就是把n个待排序的元素看成一个有序表和一个无序表,开始有序表只包含一个元素,无序表中包含n-1个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之成为新的有序表。

  public static int[] insertSort(int score[])

    {

        for(int i=1;i<score.length;i++)

        {

            int insertVal = score[i];

            // insertValue准备和前一个数比较

            int index=i-1;

              

            while(index>=0&&insertVal<score[index])

            {

                //  将把arr[index]向后移动

            score[index+1]=score[index];

                // 让index向前移动一位

                index--;

            }

              

            // 将insertValue插入到适当位置

            score[index+1]=insertVal;

        }

        return score;

    }
四、希尔排序(shellSort),在研究希尔排序之前一定要好好熟悉插入排序,有助于理解。希尔排序的基本原理:用白话来说,希尔排序实际上就是插入排序的一种改进算法,首先对数据进行分组,然后对分组的数据插入排序,最后对所有数据插入排序。本例中分割间隔长度为 
DataLength = DataLength / 2; 对半分。最好的时间复杂度为与分割增量有很大的关系。

 
 public static int []  ShellSort(int[] score) {  

        int i, j, k; // 循环计数变量  

        int Temp; // 暂存变量  

        boolean Change; // 数据是否改变  

        int DataLength; // 分割集合的间隔长度  

        int Pointer; // 进行处理的位置  

        int Index=score.length;

        DataLength = (int) Index / 2; // 初始集合间隔长度  

        while (DataLength != 0) // 数列仍可进行分割  

        {  

          // 对各个集合进行处理  

          for (j = DataLength; j < Index; j++) {  

            Change = false;  

            Temp = score[j]; // 暂存Data[j]的值,待交换值时用  

            Pointer = j - DataLength; // 计算进行处理的位置  

            // 进行集合内数值的比较与交换值  

            while (Temp < score[Pointer] && Pointer >= 0 && Pointer <= Index) {  

            score[Pointer + DataLength] = score[Pointer];  

              // 计算下一个欲进行处理的位置  

              Pointer = Pointer - DataLength;  

              Change = true;  

              if (Pointer < 0 || Pointer > Index)  

                break;  

            }  

            // 与最后的数值交换  

            score[Pointer
c074
+ DataLength] = Temp;  

          }  

          DataLength = DataLength / 2; // 计算下次分割的间隔长度  

        } 

        return score;

      } 

五、快速排序(Quik
Sort),快速排序基本原理:快速排序实际上就是采用递归分组方法,选出一个排序数中的数作为参考节点,小于参考节点的数放在左边,大于节点的数放在右边。采用递归一直到整个左右排序都执行完。

 public
static void swap1(int a[], int i, int j) {              // 通过临时变量,交换数据

        int tmp = a[i]; 

        a[i] = a[j]; 

        a[j] = tmp; 

      }                                                                  // 第一次交换分析

      public static void quicksort(int a[], int low, int high) {   // 假设传入low=0; high=a.length-1;

        if (low < high) {                                          // 条件判断

         int pivot, p_pos, i;                                    // 声明变量

            p_pos = low;                                         // p_pos指向low,即位索引为0位置 ;

            pivot = a[p_pos];                                   // 将0位置上的数值赋给pivot;

            for (i = low + 1; i <= high; i++) {             // 循环次数, i=1;

             if (a[i]<pivot) {                                      // 1位置的数与0位置数作比较: a[1]>a[0]

               p_pos++;                                           // 2位与1位比较,3位与2位比较......

               swap(a, p_pos, i);                              // 传参并调用swap      

              } 

            } 

          swap1(a, low, p_pos);                              // 将p_pos设为high再次调用swap

          quicksort(a, low, p_pos - 1);                  // 递归调用,排序左半区

          quicksort(a, p_pos + 1, high);                // 递归调用,排序右半区

        } 

      } 

    六、堆排序(Heap Sort),堆排序基本原理:堆排序采用二叉树的基本原理进行排序,java中可用数组表示二叉树。堆排序过程主要有俩部,第一部就是构建堆;第二部就是讲堆根节点与尾节点交换。

 public
static int[] heapSort(int[] data){

        

        int arrayLength=data.length;

        //循环建堆

        for(int i=0;i<arrayLength-1;i++){

            //建堆

            buildMaxHeap(data,arrayLength-1-i);

            //交换堆顶和最后一个元素

            swap(data,0,arrayLength-1-i);

         

        }

        return data;

    }

    private static void swap(int[] data, int i, int j) {

        // TODO Auto-generated method stub

    int tmp=data[i];

        data[i]=data[j];

        data[j]=tmp;

    }

    //对data数组从0到lastIndex建大顶堆

    private static void buildMaxHeap(int[] data, int lastIndex) {

        // TODO Auto-generated method stub

        //从lastIndex处节点(最后一个节点)的父节点开始

        for(int i=(lastIndex-1)/2;i>=0;i--){

            //k保存正在判断的节点

            int k=i;

            //如果当前k节点的子节点存在

            while(k*2+1<=lastIndex){

                //k节点的左子节点的索引

                int biggerIndex=2*k+1;

                //如果biggerIndex小于lastIndex,即biggerIndex+1代表的k节点的右子节点存在

                if(biggerIndex<lastIndex){

                    //若果右子节点的值较大

                    if(data[biggerIndex]<data[biggerIndex+1]){

                        //biggerIndex总是记录较大子节点的索引

                        biggerIndex++;

                    }

                }

                //如果k节点的值小于其较大的子节点的值

                if(data[k]<data[biggerIndex]){

                    //交换他们

                    swap(data,k,biggerIndex);

                    //将biggerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值大于其左右子节点的值

                    k=biggerIndex;

                }else{

                    break;

                }

            }

        }

    }

    七、归并排序(Merge Sort),归并排序基本原来:归并排序采用递归算法,分治策略等方法排序。基本流程为分割,在子分割,子合并,大合并。整个流程就是分割和合并,采用递归算法实现。

 
 public static void mergeSort(int[] data) {  

          sort(data, 0, data.length - 1);  

      }  

    

      public static void sort(int[] data, int left, int right) {  

          if (left >= right)  

              return;  

          // 找出中间索引  

          int center = (left + right) / 2;  

          // 对左边数组进行递归  

          sort(data, left, center);  

          // 对右边数组进行递归  

          sort(data, center + 1, right);  

          // 合并  

          merge(data, left, center, right);  

           

      }  

      public static void merge(int[] data, int left, int center, int right) {  

          // 临时数组  

          int[] tmpArr = new int[data.length];  

          // 右数组第一个元素索引  

          int mid = center + 1;  

          // third 记录临时数组的索引  

          int third = left;  

          // 缓存左数组第一个元素的索引  

          int tmp = left;  

          while (left <= center && mid <= right) {  

              // 从两个数组中取出最小的放入临时数组  

              if (data[left] <= data[mid]) {  

                  tmpArr[third++] = data[left++];  

              } else {  

                  tmpArr[third++] = data[mid++];  

              }  

          }  

          // 剩余部分依次放入临时数组(实际上两个while只会执行其中一个)  

          while (mid <= right) {  

              tmpArr[third++] = data[mid++];  

          }  

          while (left <= center) {  

              tmpArr[third++] = data[left++];  

          }  

          // 将临时数组中的内容拷贝回原数组中  

          // (原left-right范围的内容被复制回原数组)  

          while (tmp <= right) {  

              data[tmp] = tmpArr[tmp++];  

          }  

      }  

    八、基数排序,基数排序的基本原理:基数排序就是从对数字的个位,十位,百位等待,进行装桶。具体过程先将个位装桶,然后组合,在讲十位装桶,然后组合,以此类推,知道组合完了,排序也就完了。

   //基于计数排序的基数排序算法
 

      private static void radixSort(int[] array,int radix, int distance) {  

          //array为待排序数组  

          //radix,代表基数  

          //代表排序元素的位数  

            

          int length = array.length;  

          int[] temp = new int[length];//用于暂存元素  

          int[] count = new int[radix];//用于计数排序  

          int divide = 1;  

            

          for (int i = 0; i < distance; i++) {  

                

              System.arraycopy(array, 0,temp, 0, length);  

              Arrays.fill(count, 0);  

                

              for (int j = 0; j < length; j++) {  

                  int tempKey = (temp[j]/divide)%radix;  

                  count[tempKey]++;  

              }  

                

              for (int j = 1; j < radix; j++) {  

                  count [j] = count[j] + count[j-1];  

              }  

                

              //个人觉的运用计数排序实现计数排序的重点在下面这个方法              

              for (int j = length - 1; j >= 0; j--) {  

                  int tempKey = (temp[j]/divide)%radix;  

                  count[tempKey]--;  

                  array[count[tempKey]] = temp[j];  

              }  

                

              divide = divide * radix;                  

                

          }  

                    

      }  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 算法