1. 希尔排序
1.1 希尔排序(ShellSort)的名字源于他的发现者Donald Shell,该算法是冲破二次时间屏障的第一批算法之一。希尔排序使用一个序列h1,h2,..,ht,叫做增量排序(increment sequence)。只要h1=1,任何增量序列都是可行的。一个重要性知识,一个h[k]-排序的数据(后面将是h[k-1]-排序)保持它的h[k]-排序性。h[k]排序的一般做法是,对h[k]个独立的子数组执行一次插入排序。
1.2 增量序列一般认为h1=1 ;h[i+1]=3h[i] +1比较合适
1.3 希尔排序的核心是利用h个分割位置将数组分为多个子数组。可以根据3个不同的特征改进。
(1)增量序列
(2)除最后一次外,其他各次都采用一种简单的排序算法
(3)仅应用于最后一次(h[1]排序)的简单排序算法
实现:
template<class T>
void shellSort(T a[], int n)
{
int i, j, k, leap;
int increment[20];
//Create an appropriate number of increments h
for (leap = 1, i = 0; leap < n; i++)
{
increment[i] = leap;
leap = 3 * leap + 1;
}
//loop on the number of different increments h
for (i--; i >= 0; i--)
{
leap = increment[i];
//loop on the subarrays h-sorted
for (j = leap; j < n; j++)
{
//insertion sort for subarray containing every
if (a[j - leap]>a[j])
{
T temp = a[j];
for (k = j; a[k - leap]>temp&&k >=leap; k -= leap)
a[k] = a[k - leap];
a[k] = temp;
}
}
}
}
2. 堆排序
2.1 堆是具有以下两个属性的二叉树:
(1)每个节点的值不会小于其子节点的值
(2)全是平衡的,最底层的叶子结点都位于最左边的位置上
实现:
template<class T>
void heapSort(T a[], int n)
{
for (int i = n / 2 - 1; i >= 0; --i) //create the heap
moveDown(a, i, n - 1);
for (int i = n - 1; i >= 1; --i)
{
swap(a[0], a[i]); //move the largest item to a[i]
moveDown(a, 0, i - 1); //restore the heap property
}
}
template<class T>
void moveDown(T a[], int first, int last)
{
int i = 2 * first + 1;
while (i < last)
{
if (i + 1 < last&& //first has two children(2*first+1 and 2*first+2)
a[i] < a[i + 1]) //and the second is larger than the first
i++;
if (a[i] <= a[first]) //the heap property isn't violated by data[first]
break;
swap(a[first], a[i]); //if necessary
first = i; //swap child and parent
i = 2 * first + 1; //and move down
}
}
3. 快速排序
3.1 分治策略(divide-and-conquer)
分:将问题分成一些小的问题然后递归求解
治:将分的各个阶段解得的各个答案修补到一起
实现:
template<class T>
void quickSort(T a[], int l,int r)
{
if (l < r)
{
swap(a[l], a[(l + r) / 2]);
int i = l, j = r;
T x = a[i];
while (i < j)
{
while (i < j&&a[j] > x) // 从右向左找第一个小于x的数
j--;
if (i < j)
a[i++] = a[j];
while (i < j&&a[i] < x) // 从左向右找第一个大于等于x的数
i++;
if (i < j)
a[j--] = a[i];
}
a[i] = x;
quickSort(a, l, i - 1); //递归调用
quickSort(a, i + 1, r);
}
}
4. 归并排序
4.1 归并排序的主要过程是将多个已经排好序的子数组合并成一个排好序的数组。然而,这个子数组必须先排好序,具体方法是合并更小的、已排好序的子数组。当子数组的元素少于两个时,将数组一分为二的过程就会停止。这个算法本身也是递归的。
实现:
template<class T>
void Merge(T a[], int first, int mid, int last, T temp[])
{
int i = first, j = mid + 1;
int m = mid, n = last;
int k = 0;
while (i <= m&&j <= n)
{
if (a[i] <= a[j])
temp[k++] = a[i++];
else
temp[k++] = a[j++];
}
while (i <= m)
temp[k++] = a[i++];
while (j <= n)
temp[k++] = a[j++];
for (i = 0; i < k; i++)
a[first + i] = temp[i];
}
template<class T>
void mSort(T a[], int first, int last, int temp[])
{
if (first < last)
{
int mid = (first + last) / 2;
mSort(a, first, mid, temp); //左边有序
mSort(a, mid + 1, last, temp); <span style="white-space:pre"> </span>//右边有序
Merge(a, first, mid, last, temp); //将两个合并
}
}
template<class T>
bool mergeSort(T a[], int n)
{
T *p = new T[n];
if (p == nullptr)
return false;
mSort(a, 0, n - 1, p);
delete[]p;
return true;
}