排序的概念
概念
排序是计算机内经常进行的一种操作,其目的是将一组无序的数据元素调整为有序的数据元素的过程。
操作
比较:任意两个数据元素通过比较操作确定先后次序。
//比较数组中两个数据 if (arr[i] > arr[j]) //arr[i]大于arr[j] else //arr[i]小于arr[j]
交换:数据元素之间需要交换才能得到预期结果。
//数据交换函数 void swap(int *a, int *b) { int tmp = *a; *a = *b; *b = tmp; }
数据量分析
内部排序:
若整个排序过程不需要访问外存,仅在内存中完成数据的调整,则称此类排序问题为内部排序。
外部排序:
若参加排序的记录数量很大,整个序列的排序过程不可能在内存中完成,则称此类排序问题为外部排序。
稳定性分析
前提:一组数据中出现多个相同的数据
//一组数据中出现多个相同的数据 int arr[]={9,1,5,6,4,10,5,8,7,3};
若在原始记录序列中, ai 和 aj 的关键字相同, ai 出现在 aj 之前,经过某种方法排序后,ai的位置仍在 aj之前,则称这种排序方法是稳定的;
反之,若经过该方法排序后, ai的位置在 aj 之后,即相同关键字记录的领先关系发生变化,则称这种排序方法是不稳定的。
算法复杂度
算法复杂度
指算法在编写成可执行程序后,运行时所需要的资源,资源包括时间资源和内存资源。应用于数学和计算机导论。
同一问题可用不同算法解决,而一个算法的质量优劣将影响到算法乃至程序的效率。算法分析的目的在于选择合适算法和改进算法。
一个算法的评价主要从[时间复杂度]和[空间复杂度]来考虑。
时间复杂度
一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)。
n称为问题的规模,当n不断变化时,时间频度T(n)也会不断变化。
算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数,记作T(n)=O(f(n)),它称为算法的渐进时间复杂度,简称时间复杂度。
大O表示法
用O( )来体现算法时间复杂度的记法,称为大O表示法。
算法复杂度可以从最理想情况、平均情况和最坏情况三个角度来评估。
由于平均情况大多和最坏情况持平,而且评估最坏情况也可以避免后顾之忧,因此一般情况下,设计算法时都要直接估算最坏情况的复杂度。
复杂度的阶
常数阶
void test() { //算法的时间复杂度是O(1),称为常数阶。 printf("hello");//执行1次 }
线性阶
void test(int n) { for(int i = 0;i < n; i++) { //时间复杂度为O(n)的算法,称为线性阶 printf("hello");//执行n次 } }
对数阶
void test(int n) { int num = 1; while(num < n) { //假设循环的次数为X,则由2^x=n得出x=log₂n,因此得出算法的时间复杂度为O(logn) num = num * 2; //时间复杂度为O(logn)的算法,称为对数阶 printf("hello");//执行logn次 } }
平方阶
void test(int n) { //嵌套循环,外层控制行,内层控制列,执行次数为 外层*内层(n*n)次 for(int i = 0; i < n; i++) { for(int j = 0; j < n; i++) { //时间复杂度为O(n^2)的算法,称为平方阶 printf("hello");//执行n^2次 } } }
算法效率的度量
只关注最高次项
时间复杂度是指最坏时间复杂度
只有常数项记做1
常见的时间复杂度
O(1) < O(logn) < O(n) < O(nlogn) <O(n²) < O(n³) < O(2ⁿ) < O(n!) < O(nⁿ)
执行次数函数 阶 非正式术语 12 O(1) 常数阶 2n+3 O(n) 线性阶 3n^2+2n+1 O(n²) 平方阶 5log2n+20 O(logn) 对数阶 2n+3nlog2^n+19 O(nlogn) nlogn阶 6n3+2n2+3n+1 O(n³) 立方阶 2^n O(2ⁿ) 指数阶
空间复杂度
空间复杂度是度量算法所需存储空间的大小。
算法的空间复杂度并不是计算实际占用的空间,而是计算整个算法的辅助空间单元的个数。记做S(n)=O(f(n))。
空间复杂度比较常用的有:O(1)、O(n)、O(n²)。
空间复杂度 O(1)
void test()
{
//创建一个数据大小的空间
//所分配的空间都不随着处理数据量变化,因此它的空间复杂度 S(n) = O(1)
int a = 1;
}
空间复杂度 O(n)
void test(int n)
{
//开辟n个数据的堆空间,因此它的空间复杂度 S(n) = O(n)
int* p = (int*)malloc(sizeof(int) * n);
}
空间复杂度 O(n²)
void test(int n)
{
//开辟二级指针对应的堆空间
int** p = (int**)malloc(sizeof(int*) * n);
//开辟一级指针对应的堆空间
for(int i = 0;i<n;i++)
{
p[i] = (int*)malloc(sizeof(int) * n);
}
//开辟堆空间的数据为n*n,因此它的空间复杂度 S(n) = O(n²)
}