数据结构--第一章,第二章

  ===数据结构===

  数据结构:直白的讲,就是研究数据的存储方式。

  数据存储只有一个目的,就是为了方便后期对数据的再利用。

  对于存储之间具有复杂关系的数据,如果还是用变量或数组来存储,数据存储是没有问题的,但是无法体现数据之间的逻辑关系,后期无法使用。

  数据结构是为了解决如何存储具有复杂关系的数据更有助于后期对数据的再利用。

===

  数据结构包括:线性表,树结构,图结构。

  线性表包括: 顺序表、链表、栈、队列

  树结构包括:普通树、二叉树、线索二叉树等

  图结构包括:图存储结构。

===线性表

  线性表结构存储的数据往往是可以依次排列的,前面和后面都仅有一个数据,具备这种一对一关系的数据就可以使用线性表来存储。

  线性表分为顺序表和 链表。

  顺序表:常用的数组。 顺序表结构的底层实现借助的就是数组,对于初学者而言,可以把顺序表完全等价为数组,但实际不是这样。

  链表:我们知道,使用顺序表(底层实现靠数组)时,需要提前申请一定大小的存储空间,这块存储空间的物理地址是连续的。链表则完全不同,使用链表存储数据时,是随用随申请,因此数据的存储位置是相互分离的,换句话说,数据的存储位置是随机的。

  为了给各个数据块建立“依次排列”的关系,链表给各数据块增设一个指针,每个数据块的指针都指向下一个数据块(最后一个数据块的指针指向NULL),这样,看似毫无关系的数据块就建立了“依次排列”的关系,也就形成了链表。

===栈和队列===

  栈和队列隶属于线性表,是特殊的线性表,因为他们对线性表中元素的进出做了明确的要求。

  栈中的元素只能从线性表的一端进出,另一端封死。且要遵循“先入后出”的原则,即先进栈的元素后出栈。

  队列:队列中的元素只能从线性表的一端进,从另一端出,且要遵循“先入后出”的特点,即先进队列的元素也要先出队列。

=====树存储结构===

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

=====图存储结构===

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

===算法的时间复杂度和空间复杂度===

  算法,即解决问题的办法。同一个问题,使用不同的算法,虽然得到的结果相同,但是耗费的时间和资源是不同的。

  算法的要求:

    准确性:必须能够解决这个问题。

    健壮性:在任何情况下不能奔溃。

    效率性: 时间复杂度和空间复杂度。【算法运行时间和运行算法所需的内存空间大小。】

====时间复杂度的排序: O(1) < O(logN) < O(n) < O(n方) < O (2的N次方,指数阶)

=====线性表详解====

 线性表:数据结构中最简单的一种存储结构,专门用来存储逻辑关系为:一对一的数据。

  线性表,基于数据在实际物理空间中的存储状态,又可细分为顺序表和链表。

  数据存储的成功与否,取决于是否能将数据完整地复原成它本来的样子。

  将具有“一对一”关系的数据线性地存储到物理空间中,这种存储结构就称为线性存储结构。

  使用线性表存储的结构,如同向数组中存储数据那样,要求数据类型必须一致。

===前驱和后继===

  在数据结构中,一组数据中的每个个体被称为:数据元素。

  某一元素的左侧相邻元素称为:直接前驱,位于此元素左侧的所有元素都统称为:前驱元素。

  某一元素右侧相邻元素称为:直接后继,位于此元素右侧的所有元素都统称为:后继元素。

===顺序表的初始化===

  使用顺序表存储数据之前,除了要申请足够大小的物理空间之外,为了方便后期使用表中的数据,顺序表还需要实时记录以下两项数据:
  1. 顺序表申请的存储容量。

  2. 顺序表的长度,也就是表中存储数据元素的个数。

==因此,我们需要自定义顺序表,C语言实现代码如下:

  typedef struct Table {

    int *head: // 声明了一个名为head 的长度不确定的数组,也叫:动态数组。

    int length; // 记录当前顺序表的长度

    int size; // 记录顺序表分配的存储容量

  }table;

注意: head 是我们声明的一个未初始化的动态数组。

====建立一个顺序表===

  1. 给head 动态数据申请足够大小的物理空间;

  2. 给size 和length 赋初始值;

===示例代码===

  #define Size 5  // 对size 进行宏定义,表示顺序表申请空间的大小

  table initTable() {

    table t;

    t.head = (int*) malloc();

  }

 ===备用链表===

  在静态链表中,除了数据本身通过游标组成的链表外,还需要有一条连接各个空闲位置的链表,称为备用链表。

  备用链表的作用是回收数组中未使用或之前使用过,目前还未使用的存储空间,留待后期使用。也就是说,静态链表使用数组申请的物理空间中,存在两个链表,一条连接数据,另外一条连接数组中未使用的空间。

  通常,备用链表的表头位于数组下标为0(a[0])的位置,而数据链表的表头位于数组下标为1的位置。

  静态链表中设置备用链表的好处是,可以清楚的知道数组中是否有空闲位置,以便数据链表添加新数据时使用。比如,若静态链表中数组下标为0的位置上存有数据,则证明数组已满。

  静态链表的实现

  假设使用静态链表,数组长度为6,存储1,2,3,则需经历以下几个阶段。

  在数据链表未初始化之前,数组中所有位置都处于空闲状态,因此都被连接在备用链表上。当向静态链表中添加数据时,需提前从备用链表中摘除节点,以供新数据使用。

   备用链表摘除节点最简单的方法是摘除a[0]的直接后继节点,同样,向备用链表中添加空闲节点也是添加作为a[0]新的直接后继节点。因为a[0]是备用链表的第一个节点,我们知道它的位置,操作它的直接后继节点相对比较容易,无需遍历备用链表,耗费的时间复杂度为O(1)。

=====循环链表(约瑟夫环)的建立以及C语言实现===

  无论是静态链表还是动态链表,有时在解决具体问题时,需要我们对其结构进行稍微的调整。比如,可以把链表的两头连接,使其称为一个环状链表,通常称为循环链表。

===循环链表实现约瑟夫环===

  约瑟夫环问题,是一个经典的循环链表问题,题意是:已知n 个人围坐在一张圆桌周围,从编号为k 的人开始顺时针报数,数到m 的那个人出列,他的下一个人又从1开始,还是顺时针报数,数到m 的那个人又出列,依次循环下去,直到圆桌上剩余一个人。

===双向链表===

  双向链表中各个节点包含以下3部分信息:

    1. 指针域、数据域、指针域。

  

  

  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

  

 

 

 

 

 

 

 

 

 

 

 

 

    

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

  

  

posted on 2020-02-25 14:43  萧橘子  阅读(147)  评论(0编辑  收藏  举报

导航