本文简单介绍几种面试中常用的排序算法,并对每个算法的时间复杂度、空间复杂度、稳定性进行分析。
(1) 冒泡排序
void swap(int& num1, int& num2)
{
num1 = num1 ^ num2;
num2 = num2 ^ num1;
num1 = num1 ^ num2;
}
void bubbleSort(int array[], int size)
{
int i, j;
for (i = 0; i < size-1; i++) {
for (j = 0; j < size - i - 1; j++) {
if (array[j] > array[j+1]) {
swap(array[j], array[j+1]);
}
}
}
}
int main(int argc, const char* argv[])
{
/* test example */
int a[10] = {5, 10, 8, 2, 4, 13, 15, 9, 1, 3};
bubbleSort(a, 10);
for (int i=0; i<sizeof(a)/sizeof(*a); i++) {
cout << a[i]<< ',';
}
cout<<endl;
return 0;
}
时间复杂度O(n^2),空间复杂度O(1)。
(2) 选择排序
(3) 插入排序
(4) 快速排序
void quicksort(int* num, int start, int endend)
{
int i = start;
int j = end;
int value = num[end]; // 以value为标准进行比较
if (end <= start) return;
while (i < j) {
/* 从前往后找比value大的数 */
for (; i < j; i++) {
if (num[i] > value) {
num[j--] = num[i];
break;
}
}
/* 从后往前找比value小的数 */
for (; i < j; j--) {
if (num[j] < value) {
num[i++] = num[j];
break;
}
}
}
num[i] = value;
quicksort(num, start, i-1);
quicksort(num, i+1, end);
}
void printArray(int* num, int start, int end)
{
for (int i = start; i < end; i++) {
cout << num[i] << ",";
}
cout << endl;
}
int main(int argc, char* argv[])
{
/* test example */
int array[10] = {5, 10, 8, 2, 4, 13, 15, 9, 1, 3};
quicksort(array, 0, 9);
printArray(array, 10);
return 0;
}
(5) 堆排序
堆排序是指利用堆积树(堆)这种数据结构所设计的一种排序算法。
堆分为大根堆和小根堆,两者都是完全二叉树(完全二叉树的知识请自行学习)。大根堆的要求就是每个节点的值都不大于其父节点的值,即 node->parent->value >= node->value。小根堆则于此相反,每个节点的值都不小于其父节点的值。因为大根堆和小根堆的性质相似,本文仅以大根堆为例进行讨论。
由大根堆的性质可知,一组数列如果为大根堆的话,那数列的最大值肯定在堆顶。堆排序就是利用此性质,不断构建大根堆,不断选取最大值以进行数列排序。具体过程如下:
(1) 将一组长度为n的无序数列K0, K1, K2, ..., Kn-1构建成大根堆。
一言以敝之,就是将无序的待排序数列转换成
/* 交换两个数 */
void swap (int* a, int *b)
{
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
/* 构建最大堆 */
void buildHeap(int array[], int size)
{
int i = size - 1;
/* 最后一个叶节点为单叶节点时的处理 */
if (0 == size % 2) {
if (array[(i-1)/2] < array[i]) {
swap(array[(i-1)/2], array[i]);
}
i--;
}
for (; i > 0; i-=2) {
int p = (i-2)/2;
int j = array[i - 1] >= array[i] ? i-1 : i;
if (array[p] < array[j]) {
swap(array[p], array[j]);
}
}
}
/* 最大堆排序 */
void heapSort(int array[], int size)
{
if (size > 0) {
buildHeap(array, size);
heapSort(array+1, size-1);
}
}
int main(int argc, const char* argv[])
{
/* test example */
int a[10] = {5, 10, 8, 2, 4, 13, 15, 9, 1, 3};
heapSort(a, 10);
for (int i=0; i<sizeof(a)/sizeof(*a); i++) {
cout << a[i]<< ',';
}
cout<<endl;
return 0;
}
(6) 归并排序
先把代码贴上来,有时间再将此帖写完
/* 将有序数组 source[start, ..., mid] 和 有序数组 source[mid+1, ..., end]
* 合并成一个有序数组,并将合并的有序数组写回source中 */
void merge(int source[], int target[], int start, int mid, int end)
{
int i, j, k;
/* i: [start, ..., mid]部分遍历下标,j: [mid+1, ..., end]遍历下标 */
for (i = start, j = mid+1, k = start; i <= mid && j <= end; k++) {
if (source[i] <= source[j]) {
target[k] = source[i++];
} else {
target[k] = source[j++];
}
}
while (i <= mid) {
target[k++] = source[i++];
}
while (j <= end) {
target[k++] = source[j++];
}
for (i = start; i < k; i++) {
source[i] = target[i];
}
}
/* 归并排序 */
void mergeSort(int source[], int target[], int start, int end)
{
if (start < end) {
int mid = (start + end) / 2;
/* 对[start, ..., mid]部分进行递归排序 */
mergeSort(source, target, start, mid);
/* 对[mid+1, ..., end]部分进行递归排序 */
mergeSort(source, target, mid+1, end);
/* [start, ..., mid] 和 [mid+1, ..., end] 分别排序完成后
* 再将两部分合并成一个有序数组 */
merge(source, target, start, mid, end);
}
}
int main(int argc, char* argv[])
{
/* test example */
int a[10] = {5, 10, 8, 2, 4, 13, 15, 9, 1, 3};
int* b = new int[10];
mergeSort(a, b, 0, 9);
for (int i=0; i<sizeof(a)/sizeof(*a); i++) {
cout << b[i]<< ',';
}
cout<<endl;
return 0;
}