一、程序设计 = 数据结构 + 算法
二、数据结构
数据结构就是存在的一种或多种特定关系的数据元素的集合。
1.逻辑结构
逻辑结构:数据对象中数据元素之间的相互关系。
四大逻辑结构
- 集合结构:
- 线性结构
- 树形结构
- 图形结构
2.物理结构
物理结构:数据的逻辑结构在计算机中的存储形式。
数据元素的两种存储结构(物理结构)
- 顺序存储
把数据元素存放在地址连续的存储单元里,其数据间的逻辑关系和物理关系是一致的。 - 链式存储
把数据元素存放在任意的存储单元里,这组存储单元可以是连续的,也可以是不连续的。很显然这样的存储关系并不能反映其逻辑关系,因此需要指针存放与其相关联的数据元素的地址。
3.如何规范的使用数据结构
- 单独定义数据结构(结构体)
- 定义一些维护数据结构的接口(增、删、查、改等),使用时调用接口即可。
- 规范接口的命名风格(仿照STL):初始化init;尾插尾删pushback,popback;头插头删pushfront,popfront;中间插入删除insert,erase;创建和销毁creat,destroy;等等
- 动态内存的越界问题一般在释放内存时才会报错。
三、算法
1.大O渐进表示法(大O阶)
2.时间复杂度
算法中基本操作的执行次数,为算法的时间复杂度(不是算法执行所需的时间)
实例一:O(M+N)
实例二:O(1)
实例三:最坏情况
当一个算法随着输入不同时间复杂度也不同,时间复杂度做悲观的预期,看最坏的情况。所以函数strchr的时间复杂度为 O(N)
实例四:冒泡排序
//冒泡排序
void BubbleSort(int *arr, int n){
int i = 0;
int j = 0;
int tmp = 0;
for ( i = n - 1; i > 0; i--)
{
bool exchange = false;
for ( j = 0; j < i; j++)
{
if (arr[j] > arr[j + 1])
{
tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
exchange = true;
}
}
if (!exchange)
{
return;
}
}
}
冒泡排序的时间复杂度:O(n^2)
实例五:二分查找法(折半查找法)
//二分查找法
int BinarySearch(int *a, int arrsize, int k){
int left = 0;
int right = arrsize-1;
while (left <= right)
{
int mid = (right + left) / 2;
if (k < a[mid])
{
right = mid-1;
}
else if (k > a[mid])
{
left = mid+1;
}
else
{
return mid;
}
}
return -1;
}
二分查找法的时间复杂度:O(logN)
实例六:递归法求斐波那契数
//递归法求斐波那契数
int Fib(int k){
if (k < 3)
{
return 1;
}
else
{
return Fib(k - 1) + Fib(k - 2);
}
}
递归法求斐波那契数的时间复杂度:O(2^N)
3.空间复杂度
空间复杂度算的是算法运行额外需要的变量的个数(不是额外需要的字节数)
实例一:冒泡排序
实例二:递归法求斐波那契数
- 空间是可以重复利用,不累计的(函数执行完毕释放栈帧,循环中的变量出作用域被销毁)
- 递归函数的空间复杂度=递归调用的层数 * 每次递归需要的额外变量个数
- 时间是一去不复返,累计的
- 递归函数的时间复杂度=递归调用的次数 * 每次递归的执行次数
4.常见复杂度的对比
5.相关例题
例题一:消失的数字
//消失的数字
int func(int* arr, int arrsize){
int i = 0;
int num = 0;
for (i = 0; i < arrsize; i++)
{
num ^= i;
num ^= arr[i];
}
num ^= arrsize;
return num;
}
例题二:旋转字符串
int main(){
//旋转数组
int arr2[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int k = 3;
int arrsize = sizeof(arr2) / sizeof(arr2[0]);
printf("before:\n");
for (int i = 0; i < arrsize; i++)
{
printf("%d ", arr2[i]);
}
printf("\n");
k = k % arrsize;
Reverse(arr2, 0, arrsize - 1 - k);
Reverse(arr2, arrsize - k, arrsize - 1);
Reverse(arr2, 0, arrsize - 1);
printf("after:\n");
for (int i = 0; i < arrsize; i++)
{
printf("%d ", arr2[i]);
}
printf("\n\n");
system("pause");
return 0;
}
void Reverse(int* arr, int left, int right){
int tmp = 0;
while (left < right)
{
tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}