Nothing to say~~
正文开始@Assassin
排序算法 | 平均时间复杂度 | 最差时间复杂度 | 空间复杂度 | 数据对象稳定性 |
---|---|---|---|---|
冒泡排序 | O(n2) | O(n2) | O(1) | 稳定 |
选择排序 | O(n2) | O(n2) | O(1) | 数组不稳定、链表稳定 |
插入排序 | O(n2) | O(n2) | O(1) | 稳定 |
快速排序 | O(n*log2n) | O(n2) | O(log2n) | 不稳定 |
堆排序 | O(n*log2n) | O(n*log2n) | O(1) | 不稳定 |
归并排序 | O(n*log2n) | O(n*log2n) | O(n) | 稳定 |
希尔排序 | O(n*log2n) | O(n2) | O(1) | 不稳定 |
计数排序 | O(n+m) | O(n+m) | O(n+m) | 稳定 |
桶排序 | O(n) | O(n) | O(m) | 稳定 |
基数排序 | O(k*n) | O(n2) | 稳定 |
均按从小到大排列
k:代表数值中的"数位"个数
n:代表数据规模
m:代表数据的最大值减最小值
(无序区,有序区)。从无序区通过交换找出最大元素放到有序区前端。
冒泡排序思路:
// 冒泡排序
void BubbleSort(vector<int> &v)
{
int len = v.size();
for (int i = 0; i < len - 1; ++i)
for (int j = 0; j < len - 1 - i; ++j)
if (v[j] > v[j + 1])
swap(v[j], v[j + 1]);
}
// 模板实现冒泡排序
template<typename T> //整数或浮点数皆可使用,若要使用class时必须设定大于(>)的运算子功能
void bubble_sort(T arr[], int len)
{
for (int i = 0; i < len - 1; i++)
{
for (int j = 0; j < len - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
swap(arr[j], arr[j + 1]);
}
}
}
}
// 冒泡排序(改进版)
void BubbleSort_orderly(vector<int>& v)
{
int len = v.size();
bool orderly = false;
for (int i = 0; i < len - 1 && !orderly; ++i)
{
orderly = true;
for (int j = 0; j < len - 1 - i; ++j)
{
if (v[j] > v[j + 1]) {
// 从小到大
orderly = false; // 发生交换则仍非有序
swap(v[j], v[j + 1]);
}
}
}
}
(有序区,无序区)。在无序区里找一个最小的元素跟在有序区的后面。对数组:比较得多,换得少。
选择排序思路:
// 选择排序
void SelectionSort(vector<int> &v)
{
int min, len = v.size();
for (int i = 0; i < len - 1; ++i)
{
min = i;
for (int j = i + 1; j < len; ++j)
{
if (v[j] < v[min])
{
// 标记最小的
min = j;
}
}
if (i != min) // 交换到前面
swap(v[i], v[min]);
}
}
// 模板实现
template <typename T>
void Selection_Sort(std::vector<T> &arr)
{
int len = arr.size();
for (int i = 0; i < len - 1; i++)
{
int min = i;
for (int j = i + 1; j < len; j++)
if (arr[j] < arr[min])
min = j;
if (i != min)
std::swap(arr[i], arr[min]);
}
}
(有序区,无序区)。把无序区的第一个元素插入到有序区的合适的位置。对数组:比较得少,换得多。
插入排序思路:
// 插入排序
void InsertSort(vector<int> &v)
{
int len = v.size();
for (int i = 1; i < len; ++i)
{
int temp = v[i];
for (int j = i - 1; j >= 0; --j)
{
if (v[j] > temp)
{
v[j + 1] = v[j];
v[j] = temp;
}
else
break;
}
}
}
(小数,基准元素,大数)。在区间中随机挑选一个元素作基准,将小于基准的元素放在基准之前,大于基准的元素放在基准之后,再分别对小数区与大数区进行排序。
快速排序思路:
// ----------------------------------------------------
// 快速排序(递归)
void QuickSort(vector<int> &v, int low, int high)
{
if (low >= high) // 结束标志
return;
int first = low; // 低位下标
int last = high; // 高位下标
int key = v[first]; // 设第一个为基准
while (first < last)
{
// 将比第一个小的移到前面
while (first < last && v[last] >= key)
last--;
if (first < last)
v[first++] = v[last];
// 将比第一个大的移到后面
while (first < last && v[first] <= key)
first++;
if (first < last)
v[last--] = v[first];
}
// 基准置位
v[first] = key;
// 前半递归
QuickSort(v, low, first - 1);
// 后半递归
QuickSort(v, first + 1, high);
}
// ----------------------------------------------------
// 模板实现快速排序(递归)
template <typename T>
void quick_sort_recursive(T arr[], int start, int end)
{
if (start >= end)
return;
T mid = arr[end];
int left = start, right = end - 1;
while (left < right)
{
while (arr[left] < mid && left < right)
left++;
while (arr[right] >= mid && left < right)
right--;
std::swap(arr[left], arr[right]);
}
if (arr[left] >= arr[end])
std::swap(arr[left], arr[end]);
else
left++;
quick_sort_recursive(arr, start, left - 1);
quick_sort_recursive(arr, left + 1, end);
}
template <typename T>
void quick_sort(T arr[], int len)
{
quick_sort_recursive(arr, 0, len - 1);
}
// ----------------------------------------------------
// 模板实现快速排序(迭代)
struct Range
{
int start, end;
Range(int s = 0, int e = 0)
{
start = s, end = e;
}
};
template <typename T>
void quick_sort(T arr[], const int len)
{
if (len <= 0)
return;
Range r[len];
int p = 0;
r[p++] = Range(0, len - 1);
while (p)
{
Range range = r[--p];
if (range.start >= range.end)
continue;
T mid = arr[range.end];
int left = range.start, right = range.end - 1;
while (left < right)
{
while (arr[left] < mid && left < right)
left++;
while (arr[right] >= mid && left < right)
right--;
std::swap(arr[left], arr[right]);
}
if (arr[left] >= arr[range.end])
std::swap(arr[left], arr[range.end]);
else
left++;
r[p++] = Range(range.start, left - 1);
r[p++] = Range(left + 1, range.end);
}
}
#include
#include
using namespace std;
// 堆排序:(最大堆,有序区)。从堆顶把根卸出来放在有序区之前,再恢复堆。
void max_heapify(int arr[], int start, int end)
{
int dad = start;
int son = dad * 2 + 1;
while (son <= end)
{
if (son + 1 <= end && arr[son] < arr[son + 1])
son++;
if (arr[dad] > arr[son])
return;
else
{
swap(arr[dad], arr[son]);
dad = son;
son = dad * 2 + 1;
}
}
}
void heap_sort(int arr[], int len)
{
for (int i = len / 2 - 1; i >= 0; i--)
max_heapify(arr, i, len - 1);
for (int i = len - 1; i > 0; i--)
{
swap(arr[0], arr[i]);
max_heapify(arr, 0, i - 1);
}
}
int main()
{
int arr[] = {
3, 5, 3, 0, 8, 6, 1, 5, 8, 6, 2, 4, 9, 4, 7, 0, 1, 8, 9, 7, 3, 1, 2, 5, 9, 7, 4, 0, 2, 6};
int len = (int)sizeof(arr) / sizeof(*arr);
heap_sort(arr, len);
for (int i = 0; i < len; i++)
cout << arr[i] << ' ';
cout << endl;
return 0;
}
归并排序:把数据分为两段,从两段中逐个选最小的元素移入新数据段的末尾。可从上到下或从下到上进行。
template <typename T>
void merge_sort(T arr[], int len)
{
T *a = arr;
T *b = new T[len];
for (int seg = 1; seg < len; seg += seg)
{
for (int start = 0; start < len; start += seg + seg)
{
int low = start, mid = min(start + seg, len), high = min(start + seg + seg, len);
int k = low;
int start1 = low, end1 = mid;
int start2 = mid, end2 = high;
while (start1 < end1 && start2 < end2)
b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
while (start1 < end1)
b[k++] = a[start1++];
while (start2 < end2)
b[k++] = a[start2++];
}
T *temp = a;
a = b;
b = temp;
}
if (a != arr)
{
for (int i = 0; i < len; i++)
b[i] = a[i];
b = a;
}
delete[] b;
}
/*****************
递归版
*****************/
template <typename T>
void merge_sort_recursive(T arr[], T reg[], int start, int end)
{
if (start >= end)
return;
int len = end - start, mid = (len >> 1) + start;
int start1 = start, end1 = mid;
int start2 = mid + 1, end2 = end;
merge_sort_recursive(arr, reg, start1, end1);
merge_sort_recursive(arr, reg, start2, end2);
int k = start;
while (start1 <= end1 && start2 <= end2)
reg[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];
while (start1 <= end1)
reg[k++] = arr[start1++];
while (start2 <= end2)
reg[k++] = arr[start2++];
for (k = start; k <= end; k++)
arr[k] = reg[k];
}
template <typename T>
void merge_sort(T arr[], const int len)
{
T *reg = new T[len];
merge_sort_recursive(arr, reg, 0, len - 1);
delete[] reg;
希尔排序:每一轮按照事先决定的间隔进行插入排序,间隔会依次缩小,最后一次一定要是1。
template <typename T>
void shell_sort(T array[], int length)
{
int h = 1;
while (h < length / 3)
{
h = 3 * h + 1;
}
while (h >= 1)
{
for (int i = h; i < length; i++)
{
for (int j = i; j >= h && array[j] < array[j - h]; j -= h)
{
std::swap(array[j], array[j - h]);
}
}
h = h / 3;
}
}
计数排序:
统计小于等于该元素值的元素的个数i,于是该元素就放在目标数组的索引i位(i≥0)。 计数排序基于一个假设,待排序数列的所有数均为整数,且出现在(0,k)的区间之内。 如果 k(待排数组的最大值) 过大则会引起较大的空间复杂度,一般是用来排序 0 到 100 之间的数字的最好的算法,但是它不适合按字母顺序排序人名。 计数排序不是比较排序,排序的速度快于任何比较排序算法。
时间复杂度为O(n+k),空间复杂度为O(n+k)
算法的步骤如下:
#include
#include
#include
using namespace std;
// 计数排序
void CountSort(vector<int> &vecRaw, vector<int> &vecObj)
{
// 确保待排序容器非空
if (vecRaw.size() == 0)
return;
// 使用 vecRaw 的最大值 + 1 作为计数容器 countVec 的大小
int vecCountLength = (*max_element(begin(vecRaw), end(vecRaw))) + 1;
vector<int> vecCount(vecCountLength, 0);
// 统计每个键值出现的次数
for (int i = 0; i < vecRaw.size(); i++)
vecCount[vecRaw[i]]++;
// 后面的键值出现的位置为前面所有键值出现的次数之和
for (int i = 1; i < vecCountLength; i++)
vecCount[i] += vecCount[i - 1];
// 将键值放到目标位置
for (int i = vecRaw.size(); i > 0; i--) // 此处逆序是为了保持相同键值的稳定性
vecObj[--vecCount[vecRaw[i - 1]]] = vecRaw[i - 1];
}
int main()
{
vector<int> vecRaw = {
0, 5, 7, 9, 6, 3, 4, 5, 2, 8, 6, 9, 2, 1};
vector<int> vecObj(vecRaw.size(), 0);
CountSort(vecRaw, vecObj);
for (int i = 0; i < vecObj.size(); ++i)
cout << vecObj[i] << " ";
cout << endl;
return 0;
}
桶排序: 将值为i的元素放入i号桶,最后依次把桶里的元素倒出来。
桶排序序思路:
#include
#include
#include
using std::vector;
const int BUCKET_NUM = 10;
struct ListNode
{
explicit ListNode(int i = 0) : mData(i), mNext(NULL) {
}
ListNode *mNext;
int mData;
};
ListNode *insert(ListNode *head, int val)
{
ListNode dummyNode;
ListNode *newNode = new ListNode(val);
ListNode *pre, *curr;
dummyNode.mNext = head;
pre = &dummyNode;
curr = head;
while (NULL != curr && curr->mData <= val)
{
pre = curr;
curr = curr->mNext;
}
newNode->mNext = curr;
pre->mNext = newNode;
return dummyNode.mNext;
}
ListNode *Merge(ListNode *head1, ListNode *head2)
{
ListNode dummyNode;
ListNode *dummy = &dummyNode;
while (NULL != head1 && NULL != head2)
{
if (head1->mData <= head2->mData)
{
dummy->mNext = head1;
head1 = head1->mNext;
}
else
{
dummy->mNext = head2;
head2 = head2->mNext;
}
dummy = dummy->mNext;
}
if (NULL != head1)
dummy->mNext = head1;
if (NULL != head2)
dummy->mNext = head2;
return dummyNode.mNext;
}
void BucketSort(int n, int arr[])
{
vector<ListNode *> buckets(BUCKET_NUM, (ListNode *)(0));
for (int i = 0; i < n; ++i)
{
int index = arr[i] / BUCKET_NUM;
ListNode *head = buckets.at(index);
buckets.at(index) = insert(head, arr[i]);
}
ListNode *head = buckets.at(0);
for (int i = 1; i < BUCKET_NUM; ++i)
{
head = Merge(head, buckets.at(i));
}
for (int i = 0; i < n; ++i)
{
arr[i] = head->mData;
head = head->mNext;
}
}
基数排序: 一种多关键字的排序算法,可用桶排序实现。
int maxbit(int data[], int n) //辅助函数,求数据的最大位数
{
int maxData = data[0]; ///< 最大数
/// 先求出最大数,再求其位数,这样有原先依次每个数判断其位数,稍微优化点。
for (int i = 1; i < n; ++i)
{
if (maxData < data[i])
maxData = data[i];
}
int d = 1;
int p = 10;
while (maxData >= p)
{
//p *= 10; // 可能溢出
maxData /= 10;
++d;
}
return d;
/* int d = 1; //保存最大的位数
int p = 10;
for(int i = 0; i < n; ++i)
{
while(data[i] >= p)
{
p *= 10;
++d;
}
}
return d;*/
}
void radixsort(int data[], int n) //基数排序
{
int d = maxbit(data, n);
int *tmp = new int[n];
int *count = new int[10]; //计数器
int i, j, k;
int radix = 1;
for (i = 1; i <= d; i++) //进行d次排序
{
for (j = 0; j < 10; j++)
count[j] = 0; //每次分配前清空计数器
for (j = 0; j < n; j++)
{
k = (data[j] / radix) % 10; //统计每个桶中的记录数
count[k]++;
}
for (j = 1; j < 10; j++)
count[j] = count[j - 1] + count[j]; //将tmp中的位置依次分配给每个桶
for (j = n - 1; j >= 0; j--) //将所有桶中记录依次收集到tmp中
{
k = (data[j] / radix) % 10;
tmp[count[k] - 1] = data[j];
count[k]--;
}
for (j = 0; j < n; j++) //将临时数组的内容复制到data中
data[j] = tmp[j];
radix = radix * 10;
}
delete[] tmp;
delete[] count;
}