整数排序

来源:互联网 发布:linux如何创建文件夹 编辑:程序博客网 时间:2024/05/23 14:34

给一组整数,按照升序排序。使用归并排序,快速排序,堆排序或者任何其他 O(n log n) 的排序算法。

若从空间复杂度来考虑:首选堆排序,其次是快速排序,最后是归并排序。

若从稳定性来考虑,应选取归并排序,因为堆排序和快速排序都是不稳定的。

若从平均情况下的排序速度考虑,应该选择快速排序。 

1.归并排序:分治法(Divide and Conquer的一个非常典型的应用

将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并

算法思想:将待排序序列A[0...n-1]看成是n个长度为1的有序序列,将相邻的有序表成对归并,得到n/2个长度为2的有序表;将这些有序序列再次归并,得到n/4个长度为4的有序序列......如此反复进行下去,直到最后得到一个长度为n的有序序列。

public class Sort {
    /**
     * @param A an integer array
     * @return void
     */
    public void sortIntegers2(int[] A) {
        // Write your code here
     for (int size = 1; size < A.length; size = 2 * size) {
          MergeSort(A, size, A.length);
       }
    }
    /*.................归并排序.......................*/
    //合并
    public void Merge(int[] array,int low, int mid, int high) {
        int i = low; // i是第一段序列的下标
        int j = mid + 1; // j是第二段序列的下标
        int k = 0; // k是临时存放合并序列的下标
        int[] array2 = new int[high - low + 1]; // array2是临时合并序列
       // 扫描第一段和第二段序列,直到有一个扫描结束
        while (i <= mid && j <= high) {
       // 判断第一段和第二段取出的数哪个更小,将其存入合并序列,并继续向下扫描
          if (array[i] <= array[j]) {
               array2[k] = array[i];
               i++;
               k++;
          } else {
               array2[k] = array[j];
               j++;
               k++;
          }
      }
    // 若第一段序列还没扫描完,将其全部复制到合并序列
    while (i <= mid) {
       array2[k] = array[i];
       i++;
       k++;
    }
   // 若第二段序列还没扫描完,将其全部复制到合并序列
    while (j <= high) {
       array2[k] = array[j];
       j++;
       k++;
    }

    // 将合并序列复制到原始序列中
   for (k = 0, i = low; i <= high; i++, k++) {
      array[i] = array2[k];
   } 
 }


//分解 size为子表长度,length为数组长度
public void MergeSort(int[] array, int size, int length) {
  int i = 0;
  // 归并长度为size的两个相邻子表
  for (i = 0; i + 2 * size - 1 < length; i = i + 2 * size) {
      Merge(array, i, i + size - 1, i + 2 * size - 1);
  }
  // 当最后余下两个子表,后者长度小于size
  if (i + size - 1 < length) {
      Merge(array, i, i + size - 1, length - 1);
  }
  for(int k =0;k<length;k++)
  System.out.print(array[k]+"  ");
  System.out.println("  ");

}

2.快速排序:冒泡排序的一种改进

它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。不稳定,较复杂。

 public int division(int[] list, int low, int high) {
        // 以最左边的数为基准
        int  standard = list[low];
        while (low < high) {
            // 从序列右端开始,向左遍历,直到找到小于基准的数
            while (low < high && list[high] >= standard)
                high--;
            // 找到了比standard小的元素,将这个元素放到最左边的位置
            list[low] = list[high];
            // 从序列左端开始,向右遍历,直到找到大于standard的数
            while (low < high && list[low] <= standard)
            low++;
            // 找到了比standard大的元素,将这个元素放到最右边的位置
            list[high] = list[low];
        }
        // 最后将standard放到low位置。此时,low位置的左侧数值应该都比low小,右侧数值应该都比low大。
        list[low] = standard;
        return low;
    }
    private void quickSort(int[] list, int low, int high) {
        // 左下标一定小于右下标,否则就越界了
        if (low < high) {
            // 对数组进行分割,取出下次分割的基准标号
            int standard = division(list, low, high);
            System.out.format("low = %d high = %d:\t", low,high);
            System.out.format("standand = %d:\t", list[standard]);
            for(int i =0;i<list.length;i++)
            System.out.print(list[i]+" ");
            System.out.println("");
            // 对“基准标号“左侧的一组数值进行递归的切割,以至于将这些数值完整的排序
            quickSort(list, low, standard - 1);
            // 对“基准标号“右侧的一组数值进行递归的切割
            quickSort(list, standard + 1, high);
        }
    }

3.堆排序:利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种

是一棵顺序存储完全二叉树

(1) Ri <= R2i+1  Ri <= R2i+2 (小根堆)

(2) Ri >= R2i+1  Ri >= R2i+2 (大根堆)

其中i=1,2,…,n/2向下取整; 

public class Solution {
    /**
     * @param A an integer array
     * @return void
     */
    public void sortIntegers2(int[] A) {
         if (A == null || A.length <= 1) {  //要先判断,不然后面会报数组越界的错误
                return;  
            }  
     heapSort(A);
    }
    public void HeapAdjust(int[] array, int parent, int length) {//parent为当前节点,length为数组长度
              int temp = array[parent]; // temp保存当前父节点
              int child = 2 * parent + 1; // 先获得左孩子     
              while (child < length) {
               // 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点
                 if (child + 1 < length && array[child] < array[child + 1]) {
                     child++;
                 }
   
                 // 如果父结点的值已经大于孩子结点的值,则直接结束
                 if (temp >= array[child])
                    break;
      
                 // 把孩子结点的值赋给父结点
                 array[parent] = array[child];
      
                 // 选取孩子结点的左孩子结点,继续向下筛选,!!!!相当于递归函数很重要,要确保左右子树的大小保证
                 parent = child;
                 child = 2 * child + 1;
             }
              array[parent] = temp;
         }
      
         public void heapSort(int[] list) {
             // 循环建立初始堆
             for (int i = list.length / 2; i >= 0; i--) {//length/2是可能存在的最大父节点
                 HeapAdjust(list, i, list.length);
             }
             
              // 进行n-1次循环,完成排序
             for (int i = list.length - 1; i > 0; i--) {
                  // 最后一个元素和第一元素进行交换
                 int temp = list[i];
                 list[i] = list[0];
                 list[0] = temp;
                 // 筛选 R[0] 结点,得到i-1个结点的堆
                  HeapAdjust(list, 0, i);
             }
         }
}




0 0
原创粉丝点击