shell排序本身也是一种插入排序,但是是一个分组插入排序,shell排序的过程可以在这一个链接找到shell排序的演示示例,其思路如下:
直到歩长等于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. 合并:合并两个已排序的子序列以得到最终排序结果
归并排序可以用来理解分治算法(递归算法)。归并排序是稳定的,如果在需要稳定排序又不需要考虑内存的情况下,可以优先选择归并排序。归并排序的时间复杂度 O(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
的方式实现,则可以是稳定的。 如有疑问,欢迎来讨论。