typedef void (*SortFunc) (int*&, int);
inline void swap(int &a, int &b) {
int tmp = a;
a = b;
b = tmp;
}
inline void printArr(int* a, int n) {
for (int k = 0; k < n; ++k) {
std::cout << a[k] << ' ';
}
std::cout << std::endl;
}
void testSort(SortFunc func) {
srand(time(nullptr));
int n = rand() % 10 + 10;
int* a = new int[n];
for (int i = 0; i < n; ++i) {
a[i] = rand() % 100;
}
printArr(a, n);
(*func)(a, n);
printArr(a, n);
}
首先使用typedef将传参为(int*&, int),返回值为空的指向函数的指针类型命名为SortFunc。
其次,定义swap函数与printArr函数,swap函数会在冒泡排序、快速排序等排序算法中使用,而printArr用来输出数组。
最后,定义函数testSort,传参一个指向函数的指针,在函数体内,程序将生成一个长度取10~20之间的随机值,元素大小取0~100之间的随机值的一个数组。先对数组进行一次输出,然后调用参数func指向的函数对数组进行排序,再排序结果输出一次。
插入排序的思想是每次都将一个待排序的元素按关键字大小插入前面已排序好的子序列。插入排序主要分为:直接插入排序、折半插入排序、希尔排序。
在数组已基本有序的前提下,插入排序效率最高。
void straightInsertionSort(int* &a, int n) {
for (int i = 1; i < n; ++i) {
if (a[i] >= a[i-1]) continue;
int j;
int tmp = a[i];
for (j = i - 1; tmp < a[j] && j >= 0; --j) {
a[j+1] = a[j];
}
a[j+1] = tmp;
printArr(a, n);
}
}
空间复杂度:O(1)
时间复杂度:最好情况下为O(n),即数组已有序,只需进行一次遍历、最坏情况下为O(n2)、平均O(n2)
稳定性:具有稳定性
void binaryInsertionSort(int* &a, int n) {
for (int i = 1; i < n; ++i) {
if (a[i] >= a[i-1]) continue;
int tmp = a[i];
int low = 0;
int high = i-1;
int mid;
while (low <= high) {
mid = (low + high) / 2;
if (a[mid] > tmp) {
high = mid - 1;
} else {
low = mid + 1;
}
}
for (int j = i; j > high+1; --j) {
a[j] = a[j-1];
}
a[high+1] = tmp;
printArr(a, n);
}
}
空间复杂度:O(1)
时间复杂度:最好情况下为O(n),即数组已有序,只需进行一次遍历、最坏情况下为O(n2)、平均O(nn)
稳定性:具有稳定性
void shellSort(int* &a, int n) {
int gap = n >> 1;
int tmp, j;
while (gap) {
std::cout << "gap = " << gap << std::endl;
for (int i = gap; i < n; ++i) {
if (a[i] >= a[i-gap]) continue;
tmp = a[i];
for (j = i-gap; tmp < a[j] && j >= 0; j -= gap) {
a[j+gap] = a[j];
}
a[j+gap] = tmp;
printArr(a, n);
}
gap >>= 1;
}
}
空间复杂度:O(1)
时间复杂度:当n在某个特定范围内时,希尔排序的时间复杂度均为O(n1.3)。在最坏情况下希尔排序的时间复杂度为O(n2)。
稳定性:不具有稳定性
注意希尔排序仅适用于顺序存储的线性表
void bubbleSort(int* &a, int n) {
for (int i = 0; i < n - 1; ++i) {
bool flag = true;
for (int j = n - 1; j > i; --j) {
if (a[j - 1] > a[j]) {
swap(a[j-1], a[j]);
flag = false;
}
}
printArr(a, n);
if (flag) {
break;
}
}
}
空间复杂度:O(1)
时间复杂度:最好情况下为O(n),即数组已有序,只需进行一次遍历、最坏情况下为O(n2)、平均O(n2)
稳定性:具有稳定性
void quickSort(int* &a, int high, int low = 0) {
int i = low;
int j = high - 1;
if (i >= j) return;
int pivot = a[i];
while (i < j) {
while (i < j && pivot < a[j]) j--;
a[i] = a[j];
while (i < j && a[i] < pivot) i++;
a[j] = a[i];
}
a[i] = pivot;
std::cout << "pivot = " << pivot << std::endl;
quickSort(a, i, low);
quickSort(a, high, i + 1);
}
空间复杂度:由于快速排序是递归的,需要借助一个递归的工作栈来保存每层递归的必要信息,其容量与递归调用的最大深度保持一致。最好情况下为O(log2n);最坏情况下,即数组已有序,需要进行n-1次递归调用,空间复杂度为O(n)。平均空间复杂度为O(log2n)。
时间复杂度:最好情况下为O(nlog2n),最坏情况下为O(n2),平均为O(nlog2n)。
稳定性:不具有稳定性。
在大多数情况下,快速排序是平均性能最高的排序算法,但是排序算法并不适合对已基本接近有序的数组进行排序。
void selectionSort(int* &a, int n) {
int minIndex;
for (int i = 0; i < n - 1; i++) {
minIndex = i;
for (int j = i + 1; j < n; j++) {
if (a[j] < a[minIndex]) {
minIndex = j;
}
}
if (minIndex != i) {
swap(a[i], a[minIndex]);
}
printArr(a, n);
}
}
空间复杂度:O(1)
时间复杂度:最好情况、最坏情况、平均情况下都为O(n2)
稳定性:不具有稳定性
void heapAdjust(int* &heap, int root, int n) {
int tmp = heap[root]; // 暂存根节点
for (int i = 2 * root + 1; i < n; i = i * 2 + 1) {
if (i + 1 < n && heap[i] < heap[i+1]) {
i++; // 如果右子结点更大,让指针对准右子结点
}
if (tmp >= heap[i]) {
break;
} else {
heap[root] = heap[i];
root = i;
}
}
heap[root] = tmp;
}
void buildMaxHeap(int* &heap, int n) {
for (int i = n / 2 - 1; i >= 0; --i) {
heapAdjust(heap, i, n);
}
}
void heapSort(int* &a, int n) {
buildMaxHeap(a, n);
for (int i = n - 1; i > 0; --i) {
swap(a[i], a[0]);
heapAdjust(a, 0, i - 1);
}
}
空间复杂度:O(1)
时间复杂度:建堆的时间复杂度为O(n),之后有n-1次向下调整,每次向下调整复杂度为O(h),h为堆的深度,约为log2n,故最好情况、最坏情况、平均情况下时间复杂度都为O(nlog2n)
稳定性:不具有稳定性
static int* b;
void merge(int* &a, int low, int mid, int high) {
for (int i = low; i <= high; ++i) {
b[i] = a[i];
}
int i, j, k;
for (i = low, j = mid + 1, k = low; i <= mid && j <= high; k++) {
if (b[i] <= b[j]) {
a[k] = b[i++];
} else {
a[k] = b[j++];
}
}
while (i <= mid) {
a[k++] = b[i++];
}
while (j <= high) {
a[k++] = b[j++];
}
}
void mergeSort(int* &a, int low, int high) {
if (low >= high) return;
int mid = (low + high) / 2;
mergeSort(a, low, mid);
mergeSort(a, mid + 1, high);
merge(a, low, mid, high);
}
void mergeSort(int* &a, int n) {
b = new int[n];
mergeSort(a, 0, n-1);
}
空间复杂度:由于数组b的创建,空间复杂度为O(n)
时间复杂度:每趟归并复杂度为O(n)一共需要log2n次归并,所以复杂度为O(nlog2n)。
稳定性:具有稳定性。
class ListNode {
public:
int data;
ListNode* next;
friend std::ostream & operator<< (std::ostream &out, ListNode &l) {
ListNode* p = l.next;
while(p) {
out << p->data << ' ';
p = p->next;
}
return out;
}
};
void radixSort(ListNode* l, int d) {
ListNode *p, *q;
for (int i = 0; i < d; ++i) {
ListNode* start[16];
ListNode* end[16];
bool flags[16];
for (bool &flag : flags) {
flag = false;
}
while (l->next) {
p = l->next;
l->next = p->next;
p->next = nullptr;
int x = p->data;
int index = (x >> (4 * i)) & 0xf;
if (flags[index]) {
end[index]->next = p;
end[index] = p;
} else {
start[index] = p;
end[index] = p;
flags[index] = true;
}
}
q = l;
for (int j = 0; j < 16; ++j) {
if (flags[j]) {
q->next = start[j];
q = end[j];
}
}
std::cout << *l << std::endl;
}
}
设r个队头指针队尾指针(上述代码中是16个),共进行d趟分配与收集。
空间复杂度:O®
时间复杂度:进行d趟分配与收集,一趟分配O(n),一趟收集O(r),时间复杂度为O(d(n+r))
稳定性:具有稳定性