数据结构之时间复杂度
数据结构
是计算机存储,组织数据的方式,指相互之间存在⼀种或多种特定关系的数据元素的集合。有线性表,树 ,图,哈希等
算法 : 就是定义良好的计算过程,他取⼀个或⼀组的值为输⼊,并产⽣出⼀个或⼀组值作为输出。简单来说算法就是⼀系列的计算步骤,用来将输⼊数据转化成输出结果。
算法效率
时间复杂度,空间复杂度------时间和空间衡量
时间复杂度主要衡量⼀个算法的运行快慢,而空间复杂度主要衡量⼀个算法运行所需要的额外空间。
时间复杂度
算法的时间复杂度是一个函数式T(N)
1. 因为程序运⾏时间和编译环境和运行机器的配置都有关系,比如同⼀个算法程序,用⼀个老编译 器进行编译和新编译器编译,在同样机器下运行时间不同。
2. 同⼀个算法程序,用⼀个老低配置机器和新高配置机器,运行时间也不同。
3. 并且时间只能程序写好后测试,不能写程序前通过理论思想计算评估。
程序执行的时间=二进制指令运行时间*执行次数(二进制指令运行时间差距微乎其微)
复杂度的表⽰通常使用大O的渐进表示法。
实例 1.
//求其时间复杂度
void test(int n)
{int count;for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){++count;}}//n^2for (int k = 0; k < 2 * n; ++k){++count;}2nint M = 10;while (M--){++count;}//10}
//复杂度是O(n^2)
实例2:
const char* strchr(const char* str, char character)
{char s;const char* p_begin = &s;while (*p_begin != character){if (*p_begin == '\0')return NULL;p_begin++;}return p_begin;
}
“hello........world\0"
strchr执⾏的基本操作次数:
(1)若要查找的字符在字符串第⼀个位置,则: T (N) = 1
(2)若要查找的字符在字符串最后的⼀个位置, 则: T (N) = N
(3)若要查找的字符在字符串中间位置,则: T (N) = 2\ N
因此:strchr的时间复杂度分为: 最好情况: O(1) 最坏情况: O(N) 平均情况: O(N)
实例3.
void BubbleSort(int* a, int n)
{assert(a);for (size_t end = n; end > 0; --end){int exchange = 0;for (size_t i = 1; i < end; ++i){if (a[i - 1] > a[i]){Swap(&a[i - 1], &a[i]);exchange = 1;}}if (exchange == 0)break;}
}
1)若数组有序,则: T (N) = N
2)若数组有序且为降序,则: T (N) = 2 \N ∗ (N + 1)
第一次:n-1
第二次:n-2
....
第n次:1 1+2+.......+n-1=2 \N ∗ (N + 1) 故为O(N*2)
3)若要查找的字符在字符串中间位置 因此:BubbleSort的时间复杂度取最差情况为: O(N^2 )
实例4.(对数)
void func5(int n)
{
int cnt = 1;
while (cnt < n)
{cnt *= 2;
}
}
log2 n 、 log n 、 lg n 的表示 当n接近无穷大时,底数的大小对结果影响不大。因此,⼀般情况下不管底数是多少都可以省略不写,即可以表示为 log n
实例5.(阶乘递归)
long long Fac(size_t N)
{if (0 == N)return 1;return Fac(N - 1) * N;
}
递归算法的时间复杂度=单次递归时间复杂度*递归次数
空间复杂度
空间复杂度也是⼀个数学表达式,是对⼀个算法在运⾏过程中因为算法的需要额外临时开辟的空间。
空间复杂度不是程序占用了多少bytes的空间,因为常规情况每个对象大小差异不会很大,所以空间复杂度算的是变量的个数。
空间复杂度计算规则基本跟实践复杂度类似,也使用大O渐进表示法。
函数运行时所需要的栈空间(存储参数、局部变量、⼀些寄存器信息等)在编译期间已经确定好了,因此空间复杂度主要通过函数在运行时候显示申请的额外空间来确定
实例1.
void BubbleSort(int* a, int n)
{assert(a);for (size_t end = n; end > 0; --end){int exchange = 0;//新建变量for (size_t i = 1; i < end; ++i)//新建变量{if (a[i - 1] > a[i]){Swap(&a[i - 1], &a[i]);exchange = 1;}}if (exchange == 0)break;}
}
//申请了有限个局部变量,使用了常数个额外空间,空间复杂度O(1)
各个函数增长趋势(越低越好)
解决本文开始留下的问题(时间复杂度过大)
思路1:创建新数组,然后挪动数据
时间复杂度:O(n) 空间复杂度:O(n) 空间换时间
思路2:3次逆置
逆置
//逆置
void reverse(int* num, int left, int right)
{while (left < right){int tmp = num[left];num[left] = num[right];num[right] = tmp;left++;right--;}
}
时间复杂度:O(n/2)即O(n) 空间复杂度:只有tmp,O(1)