排序算法总结二

shell排序

  shell排序本身也是一种插入排序,但是是一个分组插入排序,shell排序的过程可以在这一个链接找到shell排序的演示示例,其思路如下:

  1. 将数据按照步长分组,对于分组的数据依次进行插入排序;
  2. 缩小步长,再次进行上面的步骤1;
  3. 直到歩长等于1,程序终止

      shell排序是不稳定的,空间复杂度是常数空间。这个排序方法在数据量比较大的情况下,平均复杂度可以到 O(n1.3) . 但本人感觉这种排序算法比较鸡肋,暂时并没有找到合适的应用场景。
    shell排序的C++版本的代码如下所示:

template <typename T>
void shellSortHelper(vector &nums, int incr) {
    for(size_t i = incr; i < nums.size(); i++) {
        T key = nums[i];
        int j = i - incr;
        while(j >= 0 && key < nums[j]) {
            nums[j+incr] = nums[j];//插入排序式的元素后移
            j -= incr;
        }
        nums[j+incr] = key;
    }
}

template <typename T>
void shellSort(vector &nums) {
    int incr = nums.size() / 2;
    while(incr >=1 ) {
        shellSortHelper(nums,incr);
        incr /= 2;
    }
}

归并排序

  归并排序是一种很有效的排序算法。该算法是分治法(devide and conquer)的一个典型应用。在归并排序这里可以看到归并排序的演示示例。归并排序的思路如下:
  
  1. 分解:将n个元素分成各有n/2个元素的子序列
  2. 解决:用合并排序法递归对两个子序列递归地排序
  3. 合并:合并两个已排序的子序列以得到最终排序结果

  归并排序可以用来理解分治算法(递归算法)。归并排序是稳定的,如果在需要稳定排序又不需要考虑内存的情况下,可以优先选择归并排序。归并排序的时间复杂度 nlogn ,空间复杂度 O(n)
代码实现如下:  

void merge(vector<int> &nums, int low, int mid, int high) {
    vector<int> left(nums.begin()+low, nums.begin()+mid+1);
    vector<int> right(nums.begin()+mid+1, nums.begin()+high+1);
    left.push_back(INT_MAX);//用作哨兵
    right.push_back(INT_MAX);//用作哨兵
    int i = 0, j = 0;
    for(int k = low; k <= high; k++) {
        if(left[i] <= right[j]) nums[k] = left[i++];
        else nums[k] = right[j++];
    }
}

/* merge Sort */
template <typename T>
void mergeSort(vector &nums, int low, int high) {
    if(low < high) {
        int mid = low + (high - low) /2 ;
        mergeSort(nums, low, mid);
        mergeSort(nums, mid+1, high);
        merge(nums, low, mid, high);
    }
}

快速排序

  快速排序是平均性能最快的排序算法,可以原地排序。在快速排序这里可以找到快排的程序演示过程。其思路主要如下:
   1. 分解:将数组A[p..r]分解成子数组A[p..q-1]和子数组A[q+1..r],使得前者的每一个元素都小于A[q],后一个数组元素都大于A[q];
   2. 解决:通过递归调用快速排序算法,对两个子数组分别排序
   3. 合并:子数组就地排序的,不再需要合并

  代码实现如下:

template <typename T>
void quickSort(vector &nums, int low, int high) {
    if(low < high) {
        int index = partition(nums, low, high);
        quickSort(nums,low,index-1);
        quickSort(nums,index+1,high);
    }
}

/*quick sort*/
template <typename T>
int partition(vector&nums, size_t low, size_t high) {
    T key = nums[high];
    int i = low, j = high;
    while(i < j) {
        while(nums[i] <= key && i < j)    i++;
        nums[j] = nums[i];
        while(key <= nums[j] && i < j)    j--;
        nums[i] = nums[j];
    }
    nums[i] = key;
    return i;
}

template <typename T>
int stablePartition(vector &nums, int low, int high) {
    T key = nums[high] ;
    int i = low - 1;
    for(int j = low; j < high; j++) {
        if(nums[j] <= key) {
            i = i+1;
            swap(nums[i],nums[j]);
        }
    }
    swap(nums[i+1],nums[high]);
    return i+1;
}

网上大多文献说快排是不稳定的,大概实现的时候一般都是以partition方式实现的,如果以stablePartition的方式实现,则可以是稳定的。 如有疑问,欢迎来讨论。
     

你可能感兴趣的:(算法)