数据结构概念解析

1. 什么是数据结构

  计算机软件是为了解决现实生活中的问题而存在的,生活中的不同个体体现在软件中即是“数据”。生活中的不同个体间势必存在某些联系,所以在软件设计中需要用某种逻辑来表现这些关系,这就是数据结构。

  计算机的“数据”有3个重要概念:
  数据元素:组成“数据”的基本单元
  数据项:一个数据元素由若干个数据组成
  数据对象:性质相同的数据元素的集合

  听起来比较抽象,可以用“人类”来类比理解。人类是由一个一个人组成,人即数据元素;人由四肢等等器官组成,这些器官即数据项;人类中有程序员、有医生等等群体,程序员即数据对象。数据结构指的时数据对象中的数据元素之间的关系,也就是“人类”中程序员之间的关系。

  常见的数据的结构有:
  集合结构:数据元素之间没什么特别的关系,仅属相同集合
  线性结构:数据元素间是一对一的关系
  树形结构:数据元素之间存在一对多的层次关系
  图形结构:数据元素间是多对多的关系

  上述的几种结构都是指逻辑结构,是程序设计中在程序员思维上对数据元素间关系的描述。与逻辑结构相对应的是物理结构,物理结构描述的是二进制数据在计算机内存中的存储形式:
  顺序存储结构:将二进制数据存储在地址连续的存储单元中
  链式存储结构:将二进制数据存储到任意的存储单元中,通过保存地址的方式找到相关联的数据元素

2. 算法及其效率度量方式

  对于一个高效的程序来说,除了对数据元素采用合理的数据结构加以描述之外,还需要在数据结构的基础上选择设计算法,算法是特定问题求解步骤的描述。除了正确描述求解步骤,效率是算法最受程序员关注的特性。度量算法的效率,一般有:

  (1) 执行后统计法:比较不同算法对同一组输入数据的运行处理时间,该方法的缺陷是运行时间严重依赖硬件以及运行时的环境因素,且算法的测试数据的选取存在困难。
  (2) 执行前分析法:依据(在程序执行前就可以)对算法的时间/空间复杂度的统计判断效率高低,用大O表示法表示。算法的时间复杂度依赖于程序操作数量,空间复杂度则依赖于程序的空间使用大小。一般大O表示法表示的是算法的时间复杂度(当然,若要表示空间的复杂度,统计办法和统计时间复杂度类似),这里所说的大O表示法也指时间复杂度。

  以下面代码为例,算法操作数为2n+4,空间复杂度为n。

int get_sum(int n)
{
    //执行2次,分配n个空间
    int ret = 0;
    int* arr = new int[n];

    //执行n次
    for (int i = 0; i < n; i++)
        arr[i] = i + 1;

    //执行n次
    for (int i = 0; i < n; i++)
        ret += arr[i];

    //执行2次
    delete[] arr;

    return ret;
}

  我们关注的是操作数最高阶项,其它次项忽略不计。用大O表示法表示其时间复杂度为O(n)(空间复杂度也为S(n))。

  常见的时间复杂度有:
  (1) 线性时间复杂度O(n)

for (int i = 0; i < n; i++)
{
    ret += i;
}
//循环n次

  (2) 对数阶时间复杂度O(logn)

int i = 1;
while (i < n)
{
    i *= 2;
}
//循环次数为log2n

  i用于累加有多少个2相乘后大于n,即2^x = n,x = log2n,用大O表示法为O(logn)

  (3) 平方阶时间复杂度O(n^2)

for (int i = 0; i < n; i++)
{
    for (int j = 0; j < n; j++)
    {
        ret += j;
    }
}
//循环n^2

  更多常见的空间复杂度如下表格:
这里写图片描述

  从上至下算法效率递减。一般而言,项目中使用的算法其时间复杂度应不超过O(n^3)。

  对于一个算法,可能有最坏情况和最好情况,例如:

bool array_find(int a[], int n, int v)
{
    bool ret = false;

    for (int i = 0; i < n; i++)
    {
        if (a[i] == v)
        {
            ret = true;
            break;
        }
    }

    return ret;
}

int main(void)
{
    int a[] = {1, 2, 3, 4, 5};

    array_find(a, 5, 1);    //最好情况,只执行1次循环
    array_find(a, 5, 5);    //最坏情况,执行n次
}

  一般,程序的时间复杂度指的是最坏情况下的,在这里即为O(n)。

3. 时间和与空间的策略

  在当下的软件设计中,算法的时间复杂度更令人关注,若有必要,会通过增加额外内存空间的策略来降低时间复杂度。
  下面代码记得我学校辅修Linux应用程序课程的时候,主讲老师讲过,它就是这样一个空间换时间的例子:

//在元素为1-10的数组中,设计一个算法找出出现次数最多的元素

#define MAX 10

void array_search(int a[], int len)
{
    int tmp[MAX] = {0};
    int max = 0;

    for (int i = 0; i < len; i++)
        tmp[a[i] - 1]++;

    for (int i = 0; i < MAX; i++)
    {
        if (tmp[i] > max)
            max = tmp[i];
    }

    for (int i = 0; i < MAX; i++)
    {
        if (max == tmp[i])
            std::cout << i + 1 << std::endl;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值