冒泡排序
void bubbleSort(vector<int>& vec)
{
if (vec.size() == 0)
return;
for (int i = 0; i < vec.size(); i++) {
bool flag = false;
for (int j = vec.size()-1; j > i; j--) {
if (vec[j] < vec[j - 1]) {
swap(vec[j], vec[j - 1]);
flag = true;
}
}
if (!flag)
return;
}
}
冒泡排序算法性能分析如下:
空间复杂度O(1),最坏的情况下时间复杂度为O(n2),最坏情况下(表中元素基本有序)时间复杂度为O(n),其平均时间复杂度为O(n2)
稳定性:冒泡排序是稳定的排序方法
快速排序
int partion(vector<int>& vec, int left, int right)
{
swap(vec[left], vec[right]);
int pivot = left - 1;
int index = left;
while (index < right) {
if (vec[index] < vec[right])
swap(vec[++pivot], vec[index++]);
else
++index;
}
swap(vec[++pivot], vec[right]);
return pivot;
}
void quickSortCore(vector<int>& vec, int left, int right)
{
if (left > right)
return;
int index = partion(vec, left, right);
quickSortCore(vec, left, index - 1);
quickSortCore(vec, index + 1, right);
}
void quickSort(vector<int>& vec)
{
quickSortCore(vec, 0, vec.size()-1);
}
注意:这里partion函数有两种划分方法
int partion2(vector<int>&vec, int left, int right)
{
int pivot = vec[left];
while (left < right) {
while (left < right && vec[right] >= pivot) --right;
vec[left] = vec[right];
while (left < right && vec[left] <= pivot) ++left;
vec[right] = vec[left];
}
vec[left] = pivot;
return left;
}
第一种有一个特点,即一次划分后,枢纽左边的元素相对顺序不变
空间效率:
由于快速排序是递归的,需要借助一个递归工作栈来保存每一层递归调用的必要信息,其容量应与递归调用的最大深度一致。最好情况下为(log2(n+1));最坏的情况下因为要进行n-1次递归调用,所以栈的深度为O(n);平均情况下,栈的深度为O(log2n)
时间效率:
快速排序的最坏情况发生在两个区域分别包含n-1个元素和0个元素时, 而后者又与具体使用的划分算法有关。这种最大程度的不对称性发生在每一层递归上,即对应于初始排序表基本有序或基本逆序时,就得到最坏下的时间复杂度(O(n2)),平均时间复杂度为(nlog2n)
快速排序是所有内部排序算法中平均性能最优的排序算法。
稳定性:
在划分算法中,若右端区间存在量个关键字相同,且均小于基准值的记录,则在交换到左端区间后,它们的相对位置会发生变化,快速排序是一个不稳定的排序算法。
选择排序
void chooseSort(vector<int>& vec)
{
for (int i = 0; i < vec.size(); i++) {
int min = i;
for (int j = i; j < vec.size(); j++) {
if (vec[j] < vec[min])
min = j;
}
swap(vec[i], vec[min]);
}
}
性能分析:
空间复杂度O(1)
时间复杂度:元素间的比较次数与序列的初始状态无关,始终是n(n-1)/2次,时间复杂度始终为O(n2)
堆排序
int inline leftChild(int num)
{
return 2 * num + 1;
}
void CreateHeap(vector<int>& vec, int index, int n)
{
int child;
int tmp = vec[index];
for (; leftChild(index) < n; index = child) {
child = leftChild(index);
if (child + 1 < n && vec[child] < vec[child + 1])
child++;
if (vec[child] > vec[index])
swap(vec[index] , vec[child]);
else
break;
}
vec[index] = tmp;
}
void heapSort(vector<int>& vec)
{
for (int i = vec.size() / 2 - 1; i >= 0; i--) {
CreateHeap(vec, i, vec.size());
}
for (int j = vec.size() - 1; j >= 0; j--) {
swap(vec[0], vec[j]);
CreateHeap(vec, 0, j);
}
}
堆排序的性能分析:
空间效率:仅使用了常数个辅助单元,所以空间复杂度O(1)
时间效率:在最好、最坏和平均情况下,堆排序的时间复杂度为O(nlog2n)
稳定性:不稳定
归并排序
void merge(vector<int>&vec, int left, int mid, int right)
{
int low = left;
int high = mid + 1;
vector<int> tmpArray(right - left + 1);
int index = 0;
while (low <= mid && high <= right) {
if (vec[low] < vec[high])
tmpArray[index++] = vec[low++];
else
tmpArray[index++] = vec[high++];
}
while (low <= mid)
tmpArray[index++] = vec[low++];
while (high <= right)
tmpArray[index++] = vec[high++];
index = 0;
for (int i = left; i <= right; i++) {
vec[i] = tmpArray[index++];
}
}
void mergeSortCore(vector<int>&vec, int left, int right)
{
if (left >= right)
return;
int mid = (left + right) / 2;
mergeSortCore(vec, left, mid);
mergeSortCore(vec, mid + 1, right);
merge(vec, left, mid, right);
}
void mergeSort(vector<int>& vec)
{
mergeSortCore(vec, 0, vec.size()-1);
}
归并排序的性能分析
空间效率:辅助空间刚好占用n个单元,空间复杂度为O(n)
时间效率:每一趟归并的时间复杂度O(n),共需进行(log2n)趟归并,所以算法时间复杂度为O(nlog2n).
稳定性:由于Merge()操作不会改变相同关键字记录的相对次序,所以二路归并排序算法是一个稳定的而排序方法。