数据结构概述

138 阅读6分钟

数据结构的一些名词及概念

  • 数据:是信息的载体,是描述客观事物的数、字符及所有能输入到计算机中并被计算机程序识别和处理的符号的集合。
  • 数据对象:指具有相同性质的数据元素的集合,是数据的一个子集。例如,整数数据对象是指集合N={0, ±1, ±2, …}。
  • 数据元素:是数据的基本单位,通常作为一个整体处理。一个数据元素可由若干个数据项组成,也可只由一个数据项组成。例如:一个学生就是一个数据对象,他由学号、姓名、性别等数据项组成。
  • 数据项:是构成数据元素的不可分割的最小单位。
  • 数据类型:是一个值的集合和定义在此集合上的一组操作的总称,可分为下列三种数据类型:
    • 原子类型:其值不可再分的数据类型。如int、double等。
    • 结构类型:其值可以再分解为若干成分的数据类型。如:结构体、类等。
    • 抽象数据类型(ADT):指一个数学模型及定义在该模型上的一组操作,通常用数据对象、数据关系、基本操作集来表示抽象数据类型。
  • 数据结构:数据结构是相互之间存在的一种或多种特定关系的数据元素的集合。数据结构包括三个方面:逻辑结构、存储结构和数据的运算。一个算法的设计取决于所选定的逻辑结构,而算法的实现依赖于所采用的存储结构。
    • 逻辑结构:是指数据元素之间的逻辑关系。它与数据的存储无关,是独立于计算机的。
      • 线性结构:数据元素之间只存在一对一的关系。
        • 一般线性表
        • 受限线性表
          • 栈和队列
          • 串 -线性表推广
          • 数组
          • 广义表
      • 非线性结构:数据元素之间存在除一对一以外的关系。
        • 集合
        • 树形结构
          • 一般树
          • 二叉树
        • 图状结构
          • 有向图
          • 无向图
    • 存储结构:指数据结构在计算机种的表示(又称映像),也称物理结构。它包括数据元素的表示和关系的表示。数据的存储结构是用计算机语言实现的逻辑结构,依赖于计算机语言。数据的存储结构主要有顺序存储、链式存储、索引存储和散列存储。
      • 顺序存储:把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间的关系由存储单元的邻接关系来体现。优点:可以实现随机存取且每个元素占用最少的存储空间。缺点:只能使用相邻的一整块存储单元,因此有可能产生较多的外部碎片。
      • 链式存储:不要求逻辑上相邻的元素在物理位置上也相邻,借助指示元素存储地址的指针来表示元素之间的逻辑关系。有点:不会出现碎片现象,能充分利用所有存储单元。缺点:每个元素因存储指针而占用额外的存储空间且只能实现顺序存储。
      • 索引存储
      • 散列存储
    • 数据的运算:施加在数据上的运算包括运算的定义和实现。运算的定义是针对逻辑结构的,指出运算的功能。运算的实现是针对存储结构的,指出运算的具体操作步骤。

算法和算法的评价

1、算法的基本概念

算法:是对特定问题求解的描述,它是指令的有限序列,其中每条指令表示一个或多个操作。

算法的特性:

  • 有穷性:一个算法(对任何合法的输入)必须总是在执行又穷步之后结束,且每一步的时间都是合理的。
  • 确定性:算法中每条指令必须有确切的含有,不会产生二义性,即对于相同输入有相同输出。
  • 可行性:算法中描述的操作都可以通过已经实现的基本运算执行有限次来实现。
  • 输入:有零个或多个输入。
  • 输出:至少有一个输出。

一个“好”的算法应该达到以下目标:

  • 正确性:算法应能够正确地解决求解问题。
  • 可读性:算法应具有良好的可读性。
  • 健壮性:算法对于非法输入,能做出处理,而不会产生莫名其妙的输出结果。
  • 高效率与低存储量需求:最小时间复杂度和最小空间复杂度。

2、算法效率的量度

时间复杂度T(n):一个语句的频度是指该语句在算法中被重复执行的次数。算法中所有语句的频度之和记为T(n),它是该算法问题规模n的函数。算法中基本运算(最深层循环内的语句)的频度与T(n)同数量级,因此通常采用算法中基本运算的频度f(n)来分析算法的复杂度。因此算法的复杂度记为T(n)=O(f(n))

空间复杂度S(n):指该算法所耗费的存储空间,它也是问题规模n的函数,记为S(n)=O(g(n))。一个程序除需要存储空间来存放本身所用的指令、常数、变量和输入数据外,还需要一些对数据进行操作的工作单元和存储为实现计算所需的一些信息的辅助空间,若输入数据所占的空间只取决与问题本身而与算法无关,则只需分析除输入和程序外的额外空间。算法的原地工作是指算法所需的辅助空间为常量,即O(1)。

3、时间复杂度的计算

  • 循环主体中的变量(i)参与循环条件的判断。

设执行次数为t,建立执行次数 t 和 i 之间的关系,把 i 用 t 替换。求解t,即可求出时间复杂度。

int i = 1;
while(i <= n) {
    i = i * 2;
}
设执行次数为t,有2^t <= n,解得t = log2(n),故T(n)=O(log2(n)).
  • 循环主体中的变量与循环条件无关
    • 非递归程序

       int m = 0, i, j;
       for(i = 1;i <= n;i++)
         for(j = 1;j <= 2*i;j++)
            m++;
      m++的执行次数为ΣΣ1=Σ2i=n(n+1), 故m++的执行次数是n(n+1), 时间复杂度T(n)=n^2.
      
    • 递归程序

       一般使用公式递推
       int fact(int n) {
           if (n <= 1) return 1;
           return n * fact(n-1);
       }
       T(n)=1 + T(n-1)=1 + 1 + T(n-2)=...=n-1 + T(1), 即T(n)=O(n).