数据结构基础系列 - 数据结构和算法初探

642 阅读7分钟

数据结构系列篇章-可以参照如下顺序阅读

一、数据结构的基本单位

我们都知道程序由数据结构和算法构成,那么数据结构具体又是指的什么呢,它的基本单位如下图:

  • 数据: 程序的操作对象,用于描述客观事物;
    • 1、可以输入到计算机
    • 2、可以被计算机处理
  • 数据项: 一个数据元素由若干数据项组成;
  • 数据元素: 组成数据的对象的基本单位;
  • 数据对象: 性质相同的数据元素的集合(类似于数组);
  • 结构: 数据元素之间不是独立的,存在特定的关系.这些关系即是结构;
  • 数据结构:指的数据对象中的数据元素之间的关系
// 代码说明
// 声明一个结构体类型
struct Person{     //一种数据结构
    char *name;     //数据项--名字
    char *title;    //数据项--职业
    int  age;       //数据项--年龄
};

    struct Person p1;     //数据元素;
    struct Person pArray[10]; //数据对象;
    
    p1.age = 18;       //数据项
    p1.name = "SN";    //数据项
    p1.title = "Coder";  //数据项

二、数据结构的逻辑结构与物理结构

数据结构按照一般划分,可以分为逻辑结构和物理结构

2.1、逻辑结构,逻辑结构指的是数据之间的逻辑关系,一般由四种逻辑结构如下,这四种逻辑结构又可以划分为:线性结构和非线性结构

2.1.1 线性结构

线性结构:结构关系是一对一的,并且是一种先后的次序

  • 主要特征为存在唯一的被叫做第一个和最后一个数据
  • 除第一个元素之外每个数据元素均有⼀个前驱
  • 除最后一个元素之外每个数据元素均有一个后继
  • 表现形式为:线性表、栈和队列、字符串(特殊的线性结构)

2.1.2 非线形结构(集合结构、树形结构、图形结构)

2.1.2.1 集合结构,集合中任何两个数据元素之间都没有逻辑关系,组织形式松散

2.1.2.2 树形结构,树形结构具有分支、层次特性,其形态有点象自然界中的树,元素结构关系是一对多,比如公司的人员架构图( CEO)

2.1.2.3 图形结构,图状结构百中的结点按逻辑关系互相缠绕,任何两个结点都可以邻接,结构关系是多对多的,比如铁路网

2.2、物理结构

物理结构指的是数据之前的物理地址关系,一般来讲有两种物理结构,即顺序存储结构和链式存储结构

2.2.1 顺序存储结构

顺序存储结构:把数据元素存放在地址连续的存储单元里,其数据间的逻辑关系和物理关系是一致的

2.2.2 链式存储结构

链式存储结构:把数据元素存放在任意的存储单元中,可以连续可以不连续,并不能反映其逻辑关系,因此需要一个指针存放其他数据元素的地址,这样通过地址找到相关联数据元素的位置

三、算法概念

算法就是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列, 并且每个指令表示一个或多个操作.

  • 算法可以脱离了数据结构存在,每一个数据加工过程都是算法。
  • 数据包含了可计算的和标识存在的两类数据。
  • 好的算法是让计算机用最少的计算实现整个计算过程的算法。
  • 设计算法要考虑的是最少的计算完成最大的功能,计算结果的保存是最重要的。
  • 一个过程中的中间结构的保存和利用是优化算法的一个手动。
  • 算法都有适应条件。在一定条件下最优,也是算法的一个特点。

四、算法特性和效率

4.1 算法特性

  • 有穷行: 算法可以在某一个条件下自动结束而不是出现无限循环
  • 确定性: 算法执行的每一步骤在一定条件下只有一条执行路径,一个相同的输入对应相同的一个输出
  • 可行性: 算法每一步骤都必须可行,能够通过有限的执行次数完成
  • 输入: 算法具有零个或多个输入
  • 输出: 算法至少有一个或多个输出

4.2 算法效率衡量方法

  • 正确性
  • 可读性
  • 健壮性
  • 时间效率高和储存量低

五、算法的复杂度

算法复杂度分为时间复杂度和空间复杂度。

  • 时间复杂度是指执行算法所需要的计算工作量
  • 空间复杂度是指执行这个算法所需要的内存空间

算法的复杂性体现在运行该算法时的计算机所需资源的多少上,计算机资源最重要的是时间和空间(即寄存器)资源,因此复杂度分为时间和空间复杂度。

5.1 时间复杂度

5.1.1 大O表示法

算法的时间复杂度,用来度量算法的运行时间,记作: T(n) = O(f(n))。它表示随着输入大小n的增大,算法执行需要的时间的增长速度可以用f(n)来描述,一般我们用大O表示法来表示算法的时间复杂度。

5.1.2 大O表示法的规则

  1. 用常数1取代运行时间中所有常数 3->1 O(1)
  2. 在修改运行次数函数中,只保留最高阶项 n^3+2n^2+5 -> O(n^3)
  3. 如果在最高阶存在且不等于1,则去除这个项目相乘的常数 2n^3 -> n^3

5.1.3 常见的时间复杂度计算

5.1.3.1 常数阶时间复杂度计算 O(1)
//1+1+1 = 3 O(1)
void testSum1(int n){
    int sum = 0;                //执行1次
    sum = (1+n)*n/2;            //执行1次
    printf("testSum1:%d\n",sum);//执行1次
}
5.1.3.2 线性阶时间复杂度计算 O(n)
//1+(n+1)+n+1 = 3+2n -> O(n)
void testSum3(int n){
    int i, sum = 0;               //执行1次
    for (i = 1; i <= n; i++) {   //执行n+1次
        sum += i;                //执行n次
    }
    printf("testSum3:%d\n",sum);  //执行1次
}
5.1.3.3 对数阶时间复杂度计算 O(logn)
/*2的x次方等于n x = log2n  ->O(logn)*/
void testA(int n){
    int count = 1;         //执行1次
    //n = 10
    while (count < n) {
        count = count * 2;
    }
    
}
5.1.3.4 平方阶时间复杂度计算 O(n^2)
//x=x+1; 执行n*n次 ->O(n^2)
void add3(int x, int n){
    for (int i = 0; i< n; i++) {
        for (int j = 0; j < n ; j++) {
            x=x+1;
        }
    }
}
5.1.3.5 立方阶时间复杂度计算 O(n^3)
void testB(int n){
    int sum = 1;                         //执行1次
    for (int i = 0; i < n; i++) {        //执行n次
        for (int j = 0 ; j < n; j++) {   //执行n*n次
            for (int k = 0; k < n; k++) {//执行n*n*n次
                sum = sum * 2;          //执行n*n*n次
            }
        }
    }
}
5.1.3.6 复杂度的比较

5.2 空间复杂度

空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度,记做S(n)=O(f(n)),其中,n为问题的规模,f(n)为语句关于n所占存储空间的函数。

// 数组逆序
// 问题: 数组逆序,将一维数组a中的n个数逆序存放在原数组中.
int n = 5;
int a[10] = {1,2,3,4,5,6,7,8,9,10};
    
//算法实现(1) 空间复杂度为O(1)
int temp;
for(int i = 0; i < n/2 ; i++){
temp = a[i];
a[i] = a[n-i-1];
a[n-i-1] = temp;
}

//算法实现(2) 空间复杂度为O(n)
int b[10] = {0};
for(int i = 0; i < n;i++){
b[i] = a[n-i-1];
}
for(int i = 0; i < n; i++){
a[i] = b[i];
}