首先我们应该知道:

  • 程序 = 数据结构 + 算法

数据结构是静态的,算法是动态的,它们加起来就是程序

为编写出一个“好”的程序,必须分析待处理对象的特性及各处理对象之间存在的关系。这也就是研究数据结构的意义所在。

一.数据结构

基础概念
  • 数据:是对现实世界的事务采用计算机能够识别,储存和处理的形式进行描述的符号的集合。
  • 数据元素:是数据的基本单位。一个数据可以由若干个数据项组成。数据项包括两种:一种是初等数据项,是数据不可分割的最小单位。另一种是组合项,由若干个数据项组成。
  • 数据对象:是性质相同数据元素的集合,是数据集合的一个子集。
  • 数据结构:是相互之间存在一种或多种特定关系的数据元素的集合,换句话说,数据结构是带“结构”的数据元素的集合,“结构”就是指数据元素之间存在的关系。

数据结构可分为逻辑结构存储结构两个层次

1. 逻辑结构

定义:是指数据对象中数据元素之间的相互关系。它与数据的存储无关,是独立于计算机的。可以说是一种抽象的数学模型。

逻辑结构有两个要素:一是数据元素,二是关系。

关系指数据元素之间的逻辑关系。

根据数据关系之间的不同特性,逻辑结构具有四类基本结构。

(1) 集合结构:数据元素除了同属于一个集合外,它们之间没有其他关系。

.

数据结构与算法辛运帏_数据结构与算法辛运帏


(2) 线性结构:数据元素之间存在一对一的关系。

.

数据结构与算法辛运帏_算法_02


(3) 树结构:数据元素之间存在一对多的关系。

.

数据结构与算法辛运帏_算法_03


(4) 图结构或网状结构:数据元素之间存在一对多的关系。

.

数据结构与算法辛运帏_时间复杂度_04


其中集合结构、树结构和图结构都属于非线性结构。

线性结构包括线性表、栈和队列、字符串、数组、广义表等。非线性结构包括树、二叉树、有向图和无向图。下图就比较清晰的描述了数据结构中的逻辑结构。

数据结构与算法辛运帏_数据_05

2.存储结构

定义:是指数据的逻辑结构在计算机中的存储形式,因此也称为物理结构。

数据元素的存储结构形式有两种:顺序存储 和 链式存储。

(1) 顺序存储结构:是把数据元素存放在地址连续的存储单元里,其数据间的逻辑关系和物理关系是一致的。如下图所示:

数据结构与算法辛运帏_数据_06


(2) 链式存储结构:是把数据元素存放在任意的存储单元里,这组存储单元可以是连续的,也可以是不连续的。如下图所示:

数据结构与算法辛运帏_算法_07


注意:链式存储结构无需用一整块存储空间,但为了表示结点之间的关系,需要给每个指针附加指针字段,用于存放后继元素的存储地址,所以链式存储结构通常借助指针来描述。

二.算法和算法分析

  • 程序 = 数据结构 + 算法

算法是研究数据结构的重要途径。

1.算法的定义及特性

定义:是为了解决某类问题而规定的一个有限长的操作序列。

算法的特性

  • 有穷性:算法的有穷性是指算法必须能在执行有限个步骤之后终止。
  • 确定性:算法的每一步骤必须有确切的定义。
  • 可行性:算法中执行的任何计算步骤都是可以被分解为基本的可执行的操作步骤,即每个计算步骤都可以在有限时间内完成(也称之为有效性)。
  • 输入:一个算法有0个或多个输入,以刻画运算对象的初始情况,所谓0个输入是指算法本身定出了初始条件。
  • 输出:一个算法有一个或多个输出,以反映对输入数据加工后的结果。没有输出的算法是毫无意义的。
2.评价算法优劣的基本标准
  • 正确性:算法的正确性是评价一个算法优劣的最重要的标准。
  • 可读性:算法的可读性是指一个算法可供人们阅读的容易程度。
  • 健壮性:健壮性是指一个算法对不合理数据输入的反应能力和处理能力,也称为容错性。
  • 高效性:高效性包括时间和空间两个方面。时间复杂复度和空间复杂度是衡量算法的两个主要指标。
3.算法的时间复杂度

在计算机科学中,时间复杂性,又称时间复杂度,算法的时间复杂度是一个函数,它定性描述该算法的运行时间。时间复杂度常用大O符号表述,一般来说,计算机算法是问题规模n的函数f(n), 算法的时间复杂度也因此记做T(n)=O(f(n))

一个算法的执行时间大致上等于其所有语句执行时间的总和,而语句的执行时间则为该条语句的重复次数和执行一次所需时间的乘积。

其他概念

最坏时间复杂度:算法在最好情况下的时间复杂度;
最坏时间复杂度:算法在最坏情况下的时间复杂度;
平均时间复杂度:算法在所有可能情况下,按照输入实例以等概率出现时,算法计算量的加权平均值。

时间复杂度:大 O 阶推导方法
 1.用常数 1 取代运行时间中的所有加法常数。
 2.在修改后的运行次数函数中,只保留最高阶项。
 3.如果最高阶项存在且不是 1,则去除与这个项相乘的常数(即
  O(2n2)=O(n2) ,得到的结果就是大 O 阶。

举个栗子,请用大 O 推导式求出函数的时间复杂度:

int i,j;
for ( i = 0; i < n; ++i){
    for(j = i; j < n; ++j){
       printf("Hello, World!\n");
    }
}

分析:对于外循环,其时间复杂度为 O(n);对于内循环环,当 i=0 时,内循环执行了 n 次,当 i=1 时,执行了 n-1 次,······当 i=n-1 时,执行了 1 次。因此内循环总的执行次数为:

T(n) = n + (n - 1) + (n - 2)……+ 1 = n(n + 1) / 2 = n^2 / 2 + n / 2。

根据大O推导法可以知道,此时时间复杂度为 O(n^2)。
类似的有:O(2n² +n+1)=O(n²);O(3n³+2n²+n)= O(n³)

具体计算数量级时,可以遵循以下定理:

> f(n)=amnm+am-1nm-1+…+a1n+a0是一个m次多项式,则T(n)=O(nm)

例如
T(n) = n^3 + n^2 + 29,此时时间复杂度为 O(n^3)。

下面用几个简单的代码进一步理解时间复杂度

#include<stdio.h>
int main()
{
    for(int i = 0; i<n; i++){        // 执行 (n + 1) 次
       printf("Hello, World!\n");      // 执行 n 次
    }
    return 0;          // 执行 1 次
}

此时间复杂度为O (n + 1 + n + 1) ,即 O(n)

for(i = 1; i <= n; i++)   // 执行(n+1)次 
  for(j = 1; j<= n; j++)   //执行 n *(n+1)次 
  {
  	c[i][j] = 0;           // 执行 n²
  	for(k = 1; k <= n; k++)   //执行 n² * (n+1)次
  	c[i][j] = c[i][j]+a[i][k]*b[k][j];   //执行 n³ 次
  }

此时间复杂度为O(2n3+3n2+2n+1),即 O(n3)

常见的几种时间复杂度:

这里就不衣衣用代码示例了,可自行百度和查阅书籍,下面两张图片图片很直观清晰!!为了省事

数据结构与算法辛运帏_数据_08


#####时间复杂度所耗费时间(效率):O(1) > O(log2n)> o(n)> o(nlog2n) > o(n^2) > o(n^3) > o(2^n) > o(n!) > o(n^n)

数据结构与算法辛运帏_数据结构_09


如若不懂,点击下方链接

一篇简书文章《十分钟搞定时间复杂度》

4.算法的空间复杂度

空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大小的量度,记做S(n)=O(f(n))。比如直接插入排序的时间复杂度是O(n^2),空间复杂度是O(1) 。而一般的递归算法就要有O(n)的空间复杂度了,因为每次递归都要存储返回信息。

注意:对于空间复杂度O(1),它是说数据规模临时变量数目无关,并不是说仅仅定义一个临时变量。举例:无论数据规模多大,我都定义100个变量,这就叫做数据规模和临时变量数目无关。就是说空间复杂度是O(1)。

下面用一个例子说明一下如何求算法的空间复杂度。

数组逆序

算法1:
for(i=0;i<n/2;i++)
{    t=a[i];
     a[i]=a[n-i-1];
     a[n-i-1]=t

算法2:
for(i=0;i<n;i++)
    b[i]=a[n-i-1];
for(i= 0; i<n; i++)
    a[i]=b[i];

算法1仅需要借助一个变量t与问题规模n大小无关,所以空间复杂度为O(1)。
算法2需要另外借助一个大小为n的辅助数组b,所以空间复杂度为O(n)。
空间复杂度简单理解就行啦

常见的几种排序方法相关比较

数据结构与算法辛运帏_数据_10