数据结构与算法———简介

什么叫数据结构 ?

直白来说,就是研究数据的存储方式。数据存储的目的是为了方便后期对数据的再利用。因此数据在计算机存储空间的存放,绝不是胡乱的。需要我们选择一种好的方式来存储数据,这也是数据结构的核心内容。
一般我们可以认为数据结构指的是一组数据的存储结构。

算法 ?

算法就是操作数据的方法,即如何操作数据效率更高,更节省资源。
举一个例子,你有一批货物需要运走,你是找小轿车来运还是找卡车来运?这就是数据结构的范畴,选取什么样的结构来存储;
至于你货物装车的时候是把货物堆放在一起还是分开放这就是算法放到范畴了,如何放置货物更有效率更节省空间。

举例说明:

类似存储 1、{a,b,c} 这种类型的数据,无疑是用变量或者数组对数据进行存储,即:
int a=1;
char str[3]={'a','b','c'};

如果要存储这样一组数据:{张亮,张平,张华,张群,张晶,张磊},数据之间的关系为:张亮是张平、张华和张群的父亲,同时张平还是张晶和张磊的父亲。
如果使用变量或数组存储数据没有问题,但是无法体现数据之间的逻辑关系,后期根本无法使用,显然不明智。针对此类数据,数据结构中提供“树”结构来存储这类数据。

导航软件,其导航功能的实现都需要大量地图数据的支持,针对此类数据,数据结构提供了图存储结构,专门用于存储这类数据。

总结:
因此,数据结构是什么? 我认为,数据结构是一门学科,它教会我们“如何存储具有复杂关系的数据更有助于后期对数据的再利用”。

数据结构的存储结构:

  • 线性结构,包括数组,单链表,双链表,栈,队列
  • 树结构,包括普通树,二叉树,哈夫曼树,红黑树等
  • 堆结构,包括二叉堆,斐波那契堆等
  • 图结构

下面对各种数据结构做介绍:

1. 线性结构

特点是:数据元素之间存在一对一的线性关系。就像小朋友手拉手。
线性结构拥有两种不同的存储结构:即顺序存储结构和链式存储结构。
      (1)顺序存储的线性表称为顺序表,顺序表中的存储元素是连续的,如数组;
      (2)链式存储的线性表称为链表,链表中的存储元素不一定是连续的,元素节点中存放数据元素以及相邻元素的地址信息。

* 栈:栈的操作只能在线性表的一端进行,就是我们常说的先进后出(FILO)
* 队列:队列的插入操作在线性表的一端进行而其他操作在线性表的另一端进行,先进先出(FIFO)
       由于线性结构存在两种存储结构,因此队列和栈各存在两个实现方式。

2. 树结构
树存储结构适合存储具有“一对多”关系的数据。

3. 堆结构
堆是一个数组,可以被看成一个近似的完全二叉树,树上的每一个节点对应数组的每个元素。除了最底层外,该树是完全充满的,而且是从左向右填充。

4. 图结构
图存储结构适合存储具有“多对多”关系的数据。

时间复杂度和空间复杂度

算法:解决问题的方法。同一个问题,使用不同的算法。虽然得到的结果相同,但是耗费的时间和资源却是不同的。
好算法的标准: 首先必须能解决问题(称为准确性);其次使用这个算法的程序在任何情况下都不能崩溃(称为健壮性)。在满足前两种条件下,必须考虑运行的效率。

运行效率体现在两方面:

  • 算法的运行时间。(称为“时间复杂度”)
  • 运行算法所需的内存空间大小。(称为“空间复杂度”)

1. 时间复杂度的计算:

   程序由三种结构构成:顺序结构、分支结构和循环结构。顺序结构和分支结构中的每段代码只运行一次;循环结构中的代码的运行时间要看循环的次数。相比而言,循环结构对算法的执行时间影响更大。所以,算法的时间复杂度,主要看算法中使用到的循环结构中代码循环的次数(称为“频度”)。次数越少,算法的时间复杂度越低。

举例说明:

a) ++x; s=0;
b) for (int i=1; i<=n; i++) { ++x; s+=x; }
c) for (int i=1; i<=n; i++) { for (int j=1; i<=n; j++) { ++x; s+=x; } }
// a 代码的运行了 1 次,b 代码的运行了 n 次,c 代码运行了 n*n 次。

算法的时间复杂度的表示方式为:O(频度),称为大“O”记法。
   对于上边的例子而言,a 的时间复杂度为O(1),b 的时间复杂度为O(n),c 的时间复杂度为为O(n2)。

   如果a、b、c组成一段程序,那么算法的时间复杂度为O(n2+n+1)。但这么表示是不对的,还需要对n2+n+1进行简化。
简化的过程总结为3步:

  • 去掉运行时间中的所有加法常数。(例如 n2+n+1,直接变为 n2+n)
  • 只保留最高项。(n2+n 变成 n2)
  • 如果最高项存在但是系数不是1,去掉系数。(n2 系数为 1)
    所以,最终a、b和c合并而成的代码的时间复杂度为O(n2)。

常用的时间复杂度的排序:

O(1)常数阶 < O(logn)对数阶 < O(n)线性阶 < O(n2)平方阶 < O(n3)(立方阶) < O(2n) (指数阶)

举例说明:

/**** 1. O(1)常数阶 ****/
int i = 1;

/**** 2. O(logn)对数阶 ****/
int i = 1;
while(i<n)
{
    i = i * 2;
}
// 假设循环x次之后,i 就大于 2 了,也就是说 2 的 x 次方等于 n,那么 x = logn

/**** 3. O(n)线性阶****/
for(i=1; i<=n; ++i)
{
   j = i;
   j++;
}

/**** 4. O(n2)平方阶/O(n3)(立方阶)****/
二次/三次嵌套循环

/**** 5. O(nlogN)线性对数阶****/
for(m=1; m<n; m++)
{
    i = 1;
    while(i<n)
    {
        i = i * 2;
    }
}

2. 空间复杂度:

算法的时间复杂度和空间复杂度是可以相互转化的。
谷歌浏览器相比于其他的浏览器,运行速度要快。是因为它占用了更多的内存空间,以空间换取了时间。

举例说明:

int[] m = new int[n]
for(i=1; i<=n; ++i)
{
   j = i;
   j++;
}
// 第一行new了一个数组出来,这个数据占用的大小为n,后面的代码,虽然有循环,但没有再分配新的空间,因此,这段代码的空间复杂度主要看第一行即可,即 S(n) = O(n)

参考网站
http://data.biancheng.net/view/153.html
https://baijiahao.baidu.com/s?id=1669543657044278427&wfr=spider&for=pc

posted on 2020-07-22 11:25  JJ_S  阅读(171)  评论(0编辑  收藏  举报