合并排序和堆排序的时间复杂度为O(nlgn),插入排序和冒泡排序的时间复杂度为O(n^2),快速排序的时间复杂度在平均情况下是O(nlgn),这些排序算法都是通过对元素进行相互比较从而确定顺序的,因此都叫比较排序。
比较排序可以看做是决策树(一个满二叉树),因为每一次比较都是一个分支。n个元素的序列,其排序的结果有 n! 种可能(n个元素的全排),所以这个决策树有 n! 个叶子结点,假设树的高度为h,则有:n! <= 2^h,所以h >= lg(n!) = Ω(nlgn)。一次比较排序就是从决策树的根节点走到叶节点,所以比较排序的时间复杂度为Ω(nlgn)。
而计数排序、基数排序和桶排序都是非比较排序,其时间复杂度为O(n),但是这三种排序算法都不是原地排序,占用内存空间较多,而比较排序算法大多都是原地排序。
/*
* 算法导论 第八章 线性时间排序
* 计数排序、基数排序和桶排序
*/
#include
#include
#include
#include
using namespace std;
void printArray(int arr[], int len, char *str)
{
cout << str << endl;
for (int i=0; i=0; i--)
{
result[numCount[arr[i]]-1] = arr[i];
numCount[arr[i]]--;
}
delete[] numCount;
return result;
}
/*
* 基数排序
* 是建立在计数排序的基础之上的,计数排序的稳定性很重要
* 否则基数排序就会出错,例如数组[27, 15, 43, 42],如果子排序过程不稳定
* 则结果就为[15, 27, 43, 42]
* 时间复杂度为O(d*(n+k)),在d为常数,k=O(n)时,时间复杂度为O(n)
*/
int* radixSort(int *arr, int len, int d)
{
int *A = new int[len];
for (int i=0; i=0; i--)
{
result[numCount[getDigit(A[i], j)]-1] = A[i];
numCount[getDigit(A[i], j)]--;
}
delete[] A;
delete[] numCount;
A = result;
}
return A;
}
int getDigit(int num, int d)
{
return (num % (int)pow(10.0, d+1)) / pow(10.0, d);
}
/*
* 桶排序
* 在输入符合均匀分布时,桶排序的效果较好
* 将各个元素分布在n个桶中,每个桶内再使用插入排序
* 只要各个桶的尺寸的平方和与总的元素数呈线性关系
* 则其时间复杂度就为O(n)
*/
int* bucketSort(int *arr, int len, int maxNum)
{
//建立n个桶
vector *result = new vector[len];
//将各个元素分布到各个桶内
for (int i=0; i=0 && result[i][k]>key)
{
result[i][k+1] = result[i][k];
k--;
}
result[i][k+1] = key;
}
}
//合并各个桶中的元素
for (int i=0, j=0; j
习题 8-3 排序不同长度的数据项
/*
* 算法导论 习题8-3.a
* 首先利用计数排序对数组按位数排序
* 然后再利用基数排序对各不同分组排序
* 时间复杂度为O(n)
*/
#include
#include
using namespace std;
typedef int (*getCountKey)(int, int);
void countSort(int *arr, int len, int k, getCountKey getCntKey, int arg=0);
void radixSort(int *arr, int p, int r, int digitCnt);
int getDigit(int num, int d);
int getDigitCnt(int num, int arg=0);
void printArray(int arr[], int len, char *str)
{
cout << str << endl;
for (int i=0; i k)
{
k = temp;
}
}
k++;
printArray(arr, len, "原数组");
countSort(arr, len, k, getDigitCnt);
printArray(arr, len, "计数排序后");
int digitCount = getDigitCnt(arr[0]);
int pos = 0;
for (int i=0; i=0; i--)
{
arr1[counts[getCntKey(arr[i], arg)]-1] = arr[i];
counts[getCntKey(arr[i], arg)]--;
}
for (int i=0; i
/*
* 算法导论 习题8-3.b
* 首先利用计数排序对数组按首位排序
* 然后数组根据字符串的首位不同而分组,
* 各不同分组再递归的根据次高位计数排序
* 但是必须注意在排序过程中不断去掉长度较小的字符串
* 时间复杂度为O(n)
*/
#include
#include
#include
using namespace std;
typedef int (*getCountKey)(char*, int);
void countSort(char **str, int start, int end, int k, getCountKey getKey, int arg);
int getLetterPos(char* str, int arg);
void stringSort(char **str, int start, int end, int index);
void printArray(char** arr, int len, char *str)
{
cout << str << endl;
for (int i=0; i=start; i--)
{
result[counts[getKey(str[i], arg)]-1] = str[i];
counts[getKey(str[i], arg)]--;
}
for (int i=0; i