数据结构(复杂度)

很多时候,咨询的人心里已经有了答案,来咨询只是想确认自己的决定是对的。   -- 东野圭吾 《解忧杂货店》

数据结构含义

1. 通过数据结构,有利于把杂乱无章的数据,进行管理操作。

2. 数据结构有很多种,例如:数组等。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
	int a = 1;//直接赋值给变量
	int arr[1000];
	arr[0] = 55;//通过数组这种数据结构,从而对数组里面的变量进行赋值
}

 算法的含义

1. 通过一系列的计算步骤,将输入的数据转化成结果。

复杂度

复杂度的含义 

1. 复杂度用来衡量一个算法的好坏。

2. 复杂度分为时间复杂度和空间复杂度。

3. 时间复杂度(主要):算法运行的快慢。

4. 空间复杂度:算法运行所需要的额外空间。

时间复杂度

可以表示为一个函数式:T(N) 。

计算时间复杂度的公式

n=a*b

1. n:程序运行时间效率。

2. a:每条语句的运行时间(注:a不是一个确定的值,与编译环境有关。)

3. b:每条语句的运行次数(注:b是一个确定的值。)

计算程序运行时间

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <time.h>
int main()
{
	int begin=clock();//记录程序刚开始的时间
	int count = 0;
	for (int i = 0; i < 10000000; i++)
	{
		count++;
	}
	int end = clock();//记录程序刚结束的时间
	printf("%d", end - begin);//需要在debug模式下
	return 0;
}
//多运行几次都不同,没有精确值

大O的渐进表示法 

1. 大O符号:用于描述函数渐进行为的符号。例如:O(N^2) 

2. 我们通过大O的渐进表示法,来计算运行的次数。

3. 大O的渐进表示法的规则:

  1.         只看最高阶项。
  2.         如果存在最高阶项,则忽略其系数和其他常数项。
  3.         如果只有常数项,则直接视为1。
  4.         重点看循环或递归次数。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <time.h>
void Func1(int N) 
{
    int count = 0;
    // 第一个循环:N * N 次迭代
    for (int i = 0; i < N; ++i) 
    {
        for (int j = 0; j < N; ++j) 
        {
            ++count;
        }
    }
    // 第二个循环:2 * N 次迭代
    for (int k = 0; k < 2 * N; ++k) 
    {
        ++count;
    }
    // while 循环:10 次迭代
    int M = 10;
    while (M--) 
    {
        ++count;
    }
}
    //T(N)=N^2+2N+10
    //复杂度为:O(N^2)
void Func2(int N)
{
    int count = 0;
    // 这个循环将执行 2 * N 次
    for (int k = 0; k < 2 * N; ++k)
    {
        ++count;
    }
    // 这个循环将执行 10 次
    int M = 10;
    while (M--)
    {
        ++count;
    }
    printf("%d\n", count);
}
    //T(N)=2*N+10
    //复杂度为:O(N)
void Func3(int N, int M)
 {
    int count = 0;
    // 这个循环将执行 M 次
    for (int k = 0; k < M; ++k)
    {
            ++count;
    }
    // 这个循环将执行 N 次
    for (int k = 0; k < N; ++k)
    {
        ++count;
    }
    printf("%d\n", count);
}
    //T(N)=M+N
    //复杂度为:O(M+N)
void Func4(int N) 
{
    int count = 0;
    // 这个循环将执行 100 次
    for (int k = 0; k < 100; ++k) 
    {
        ++count;
    }
    printf("%d\n", count);
}
    //T(N)=100
    //复杂度为:O(1)
const char * strchr ( const char* str, int character)
{
    const char* p_begin = s;
    while (*p_begin != character)
    {
        if (*p_begin == '\0')
        {
                return NULL;
         }
        p_begin++;
    }
    return p_begin;
}

    //上界:最坏的情况O(N),若要查找的字符在字符串第⼀个位置。
    //下界:最好的情况O(1),若要查找的字符在字符串最后的⼀个位置。
    //主要关注上界最差的情况
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define N
int main()
{
	int arr[N] = { 0 };
	int i = 0;
	for (i = 0; i < N; i++)
	{
		scanf("%d", &arr[i]);
	}
	int a = 0, b = 0;
	for (a = 0; a < N-1; a++)
	{
		for (b = 0 ; b < N-1-a; b++)
		{
			if (arr[b] > arr[b + 1])
			{
				int mid = 0;
				mid = arr[b + 1];
				arr[b + 1] = arr[b];
				arr[b] = mid;
			}
		}
	}
	for (i = 0; i < N; i++)
	{
		printf("%d\n", arr[i]);
	}
	return 0;
}
    //T(N)=N(N-1)/2
    //复杂度为:O(N^2)
void func5(int n) 
{
    int cnt = 1;
    while (cnt < N) 
    {
        cnt *= 2;
    }
}
    //T(N)=log(N),不管底数。
long long Fac(size_t N) 
{
    if (0 == N)
    {
        return 1;
    }
    return Fac(N - 1) * N;
}
    //T(N)=N
    //复杂度为:O(N)

 上下界

最坏情况:任意输⼊规模的最⼤运⾏次数(上界)

平均情况:任意输⼊规模的期望运⾏次数

最好情况:任意输⼊规模的最⼩运⾏次数(下界)

空间复杂度

计算空间复杂度

1. 专指函数在运行时所额外占用的空间。

2. 规则与时间复杂度相同。

3. 重点看定义的变量个数。

void BubbleSort(int* a, int n) 
{
    assert(a);
    for (size_t end = n; end > 0; --end) //第一个end
    {
        int exchange = 0;//第二个exchange
        for (size_t i = 1; i < end; ++i) //第三个i
        {
            if (a[i - 1] > a[i])
            {
                Swap(&a[i - 1], &a[i]);
                exchange = 1;
            }
        }
        if (exchange == 0)
            break;
    }
}
    //空间复杂度为:O(1)
long long Fac(size_t N) 
{
    if (N == 0)
        return 1;
    return Fac(N - 1) * N;//第一个Fac(N - 1) * N
}
    //空间复杂度为:O(N),每一次递归,空间复杂度增加一次。

复杂度的大小 

 

 总结

若在算法题型中,如果时间复杂度超过要求,则可以提高空间复杂度来降低时间复杂度。

例题:轮转数组

将一个数组的元素向后移k位。
void rotate(int* nums, int numsSize, int k)
{
    while(k--)
    {
        int end = nums[numsSize-1];
        for(int i = numsSize - 1;i > 0 ;i--)
        {    
            nums[i] = nums[i-1];
        }
        nums[0] = end;
    }
}
//通过两个内外层循环从而达到目标

改进后:
void rotate(int* nums, int numsSize, int k)
{
    int newArr[numsSize];
    for (int i = 0; i < numsSize; ++i)
    {
        newArr[(i + k) % numsSize] = nums[i];
    }
    for (int i = 0; i < numsSize; ++i)
    {
        nums[i] = newArr[i];
    }
}
//通过创建一个新的数组从而达到目标

致谢

 感谢您花时间阅读这篇文章!如果您对本文有任何疑问、建议或是想要分享您的看法,请不要犹豫,在评论区留下您的宝贵意见。每一次互动都是我前进的动力,您的支持是我最大的鼓励。期待与您的交流,让我们共同成长,探索技术世界的无限可能!
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值