算法与数据结构介绍
1、数据结构概念
数据结构是计算机存储,组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合。
2、算法概念
算法指计算步骤,它取一个或一组值作为输入,并产生一个或一组值作为输出。
3、算法效率
算法效率包含两种:
1、时间效率
时间效率称为时间复杂度,时间复杂度是衡量一个算法执行速度的量
2、空间效率
空间效率称为空间复杂度,空间复杂度是衡量一个算法执行所需的额外空间的量
4、时间复杂度
时间复杂度的定义:
在计算机科学中,时间复杂性,又称时间复杂度,算法的时间复杂度是一个函数,它定性描述该算法的运行时间。这是一个代表算法输入值的字符串的长度的函数。时间复杂度常用大O符号表述,不包括这个函数的低阶项和首项系数。使用这种方式时,时间复杂度可被称为是渐近的,亦即考察输入值大小趋近无穷时的情况。时间复杂度指算法中的基本操作的执行次数。
如何计算时间复杂度:(只需要计算大概执行次数,采用大O渐进表示法)
大O符号:是用于描述函数渐进行为的数学符号
推导大O阶的方法
1、用常数1取代运行时间中的所有加法常数
2、在修改后的运行次数函数中,只保留最高阶项
3、如果最高阶项存在不是1,则去除与这个项目相乘的常数,得到的结果就是大O阶
时间复杂度在最好、平均和最坏的情况:
最坏情况:任意输入规模的最大运行次数(上界)
平均情况:任意输入规模的期望运行次数
最好情况:任意输入规模的最小运行次数(下界)
实际情况中我们只关注算法的最坏运行情况
实例1:
#include <stdio.h>
#include <stdlib.h>
void Func2(int N)
{
int count = 0;
for (int k = 0; k < 2 * N; k++)
{
count++;
}
int M = 10;
while (M--)
{
count++;
}
printf("%d\n", count);
}
int main()
{
Func2(1000);
system("pause");
return 0;
}
实例1基本操作执行了2N+10次,通过推导大O阶方法知道,时间复杂度为 O(N)
实例2:
#include <stdio.h>
#include <stdlib.h>
void Func3(int N, int M)
{
int count = 0;
for (int k = 0; k < M; k++)
{
count++;
}
for (int k = 0; k < N; k++)
{
count++;
}
printf("%d\n", count);
}
int main()
{
Func3(1000, 2000);
system("pause");
return 0;
}
实例2基本操作执行了M+N次,有两个未知数M和N,时间复杂度为 O(N+M)
实例3:
#include <stdio.h>
#include <stdlib.h>
void Func4(int N)
{
int count = 0;
for (int k = 0; k < N; k++)
{
count++;
}
printf("%d\n", count);
}
int main()
{
Func4(100);
system("pause");
return 0;
}
实例3基本操作执行了10次,通过推导大O阶方法,时间复杂度为 O(1)
实例4:
#include <stdio.h>
#include <stdlib.h>
const char *my_strchr(const char *str, int character)
{
int count = 0;
char *res = (char *)str;
while (*res != '\0')
{
if (*res == character)
{
printf("%d\n", count);
return res;
}
res++;
count++;
}
return NULL;
}
int main4()
{
char *str[] = { 0 };
my_strchr("Hello,World!", 'd');
system("pause");
return 0;
}
实例4基本操作执行最好1次,最坏N次,时间复杂度一般看最坏,时间复杂度为 O(N)
实例5:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void BubbleSort(int *arr, int n)
{
assert(arr);
for (size_t i = 0; i < n; i++)
{
for (size_t j = 0; j < n; j++)
{
if (arr[j - 1]>arr[j])
{
int tmp = arr[j - 1];
arr[j - 1] = arr[j];
arr[j] = tmp;
}
}
}
}
int main()
{
int arr[10] = { 2, 3, 5, 4, 1, 6, 7, 9, 8, 0 };
BubbleSort(arr, 10);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
system("pause");
return 0;
}
实例5基本操作执行最好N次,最坏执行了(N*(N+1)/2次,通过推导大O阶方法+时间复杂度一般看最坏,时间复杂度为 O(N^2)
实例6:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int BinarySearch(int *a, int n, int x)
{
assert(a);
int left = 0;
int right = n - 1;
while (left <= right)
{
int mid = (left + right) / 2;
if (a[mid] < x)
{
left = mid + 1;
}
else if (a[mid]> x)
{
right = mid - 1;
}
else
{
return mid;
}
}
}
int main()
{
int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int res = BinarySearch(arr, 10, 7);
printf("%d\n", res);
system("pause");
return 0;
}
实例6基本操作执行最好1次,最坏O(logN)次,时间复杂度为 O(logN)
实例7:
//计算阶乘的Factorial函数
#include <stdio.h>
#include <stdlib.h>
int Factorial(int n)
{
if (n == 1 || n == 0)
{
return 1;
}
return n * Factorial(n - 1);
}
int main()
{
printf("%d\n", Factorial(10));
system("pause");
return 0;
}
实例7通过计算分析发现基本操作递归了N次,时间复杂度为O(N)。
实例8:
//计算斐波那契数列的递归Fibonacci
#include <stdio.h>
#include <stdlib.h>
int Fibonacci(int n)
{
if (n == 1 || n == 2)
{
return 1;
}
return n + Fibonacci(n - 1);
}
int main()
{
printf("%d\n", Fibonacci(5));
system("pause");
return 0;
}
实例8通过计算分析发现基本操作递归了2N次,时间复杂度为O(2N)。
时间复杂度的排序:
时间复杂度从小到大排序: Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2)<Ο(n3)<…<Ο(2n)<Ο(n!)
5、空间复杂度
空间复杂度是对一个算法的在运行过程中临时占用存储空间大小的量度。空间复杂度不是程序占用了多少bytes空间,而是变量的个数。空间复杂度计算规则和时间复杂度类似,也用大O渐进表示法。
一个算法的空间复杂度只考虑在运行过程中为局部变量分配的存储空间的大小:形参、局部变量
实例1:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void BubbleSort(int *arr, int n)
{
assert(arr);
for (size_t i = 0; i < n; i++)
{
for (size_t j = 0; j < n; j++)
{
if (arr[j - 1]>arr[j])
{
int tmp = arr[j - 1];
arr[j - 1] = arr[j];
arr[j] = tmp;
}
}
}
}
int main()
{
int arr[10] = { 2, 3, 5, 4, 1, 6, 7, 9, 8, 0 };
BubbleSort(arr, 10);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
system("pause");
return 0;
}
实例1使用了常数个额外空间,所以空间复杂度为 O(1)
实例2:
//计算阶乘的Factorial函数
#include <stdio.h>
#include <stdlib.h>
int Factorial(int n)
{
if (n == 1 || n == 0)
{
return 1;
}
return n * Factorial(n - 1);
}
int main()
{
printf("%d\n", Factorial(10));
system("pause");
return 0;
}
实例2动态开辟了N个空间,空间复杂度为 O(N)
实例3:
//计算斐波那契数列的递归Fibonacci
#include <stdio.h>
#include <stdlib.h>
int Fibonacci(int n)
{
if (n == 1 || n == 2)
{
return 1;
}
return n + Fibonacci(n - 1);
}
int main()
{
printf("%d\n", Fibonacci(5));
system("pause");
return 0;
}
实例3递归调用了N次,开辟了N个栈帧,每个栈帧使用了常数个空间。空间复杂度为O(N)