常见数据结构

先激励激励自己

数据结构是指组织数据的方式,它是算法的基础。

线性结构和非线性结构

线性结构:是一个有序数据元素的集合。它应该满足下面的特征:

  • 集合中必存在唯一的一个“第一个元素”
  • 集合中必存在唯一的一个“最后的元素”
  • 除最后一元素之外,其它数据元素均有唯一的“后继
  • 除第一个元素之外,其它数据元素均有唯一的“前驱”

非线性结构:其逻辑特征是一个节点元素可以有多个直接前驱或多个直接后继。


数组

数组是一种线性结构,以十二生肖(鼠、牛、虎、兔、龙、蛇、马、羊、猴、鸡、狗、猪)排序为例:如下图

数组有连续的内存空间和相同类型的数据。正是有了这两个限制,才有了一个堪称杀手锏的特性:“随机访问”,但是删除和插入一个数据,为了保证连续性,就需要做大量的数据搬移工作。

为什么大多数语言数组都是0开头?而不是1开头呢?

从数组存储的内存模型上来看,“下标”最确切的定义应该是“偏移(offset)”,如果用a来表示数组的首地址,a[0]就是偏移为0的位置,也就是首地址,a[k]就表示偏移k个type_size的位置,所以计算a[k]的内存地址只需要

a[k]_address = base_address + k * type_size

若是数组从1开始计数,那么我们计算数组元素a[k]的内存地址就是

a[k]_address = base_address + (k-1) * type_size

从1开始编号,每次随机访问数组元素都多了一次减法运算,对于cpu来说,就是多了一次减法指令。

在底层开发时,直接使用数组可能会更合适。

优点:

1、存储多个元素,比较常用

2、访问便捷,使用下标[index]即可访问

缺点:

1、数组的创建通常需要申请一段连续的内存空间,并且大小是固定的(大多数的编程语言数组都是固定的),所以在进行扩容的时候难以掌控。

2、一般情况下,申请一个更大的数组,会是之前数组的倍数,比如两倍。然后,再将原数组中的元素复制过去

3、插入数据越是靠前,其成本很高,因为需要进行大量元素的位移。

二维数组

二维数组也称为矩阵,因为是二维的,所以需要两个下标才能确定一个元素,即行下标和列下标。如下图创建一个3行10列的二维数组(矩阵),一共可存放30个元素,

image


栈是一种后进先出(LIFO)线性表,是一种基于数组的数据结构。(ps:其实后面讲到的数据结构或多或少有数组的影子)

说明:

1、LIFO(Last In First Out)表示后进先出,后进来的元素第一个弹出栈空间。类似于自动餐托盘,最后放上去的托盘,往往先被拿出来使用。

2、仅允许在表的一端进行插入和移除元素。这一端被称为栈顶,相对地,把另一端称为栈底。如上图的标识。

3、向一个栈插入新元素称作进栈、入栈或压栈,这是将新元素放在栈顶元素上面,使之成为新的栈顶元素。

4、从一个栈删除元素又称为出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。


队列

队列可以用数组实现,也可以用链表实现,用数组实现时是顺序存储,用链表实现时是链式存储。

队列是一种先进先出(FIFO)受限的线性表。受限体现在于其允许在表的前端(front)进行删除操作,在表的末尾(rear)进行插入【优先队列这些排除在外】操作。(即数据在尾部进入,在头部拿出)


链表

链表是由一组节点组成的集合。每个节点都使用一个对象的引用指向它的后继。

和数组的区别:

1、链表亦可以存储多个元素,而且存储的元素在内容中不必是连续的空间。

2、在插入和删除数据时,时间复杂度可以达到O(1)。

3、在查找元素的时候,还是需要从头开始遍历的,比数组在知道下标的情况下要慢,但是数组如果不确定下标的话,那就另说。

 


以上为常见的线性表。

接下来讲常见的非线性表。


散列表/哈希表

 

说明:Hash 表又称散列表,通过把目标值映射到数组中的一个位置来访问记录,以加快查找速度。

散列是一种常用的存储技术,散列使用的数据结构叫做散列表/哈希表。 在散列表上插入、删除和获取数据都非常快,但是对于查找操作来说却效率低下,比如查找一组数据中的最大值和最小值。查找的这些操作得求助其它数据结构。

哈希表的原理是什么呢?因为在查找数据时大部分时间都用于目标值的比较,于是我们思考,能否不经过值的比较就能找到我要的记录呢?于是,我们将目标值(关键值,即一组数据中比较关键的值,通常具有唯一性,比如用户id)通过一个函数映射成存储地址,这个映射函数称为Hash函数,存放记录的数组称为Hash表。比如:

理想情况下,哈希函数会保证每一个地址对应唯一的一个值。但是实际情况下不太可能,于是就可能会产生冲突。

于是我们就要去解决冲突,即当冲突产生时,我们为冲突的值寻找下一个可用的地址。

构造哈希函数和解决冲突都有好多种方式。

构造哈希函数的常用方式:

直接定址法,即类似上方举例中的加减某个常量;平方取中法;折叠法;最常用的是除留余数法:

 

通常我们要求这个除数为质数,为什么?

处理冲突的常用方式

开放定址法

其中前两个取值用得比较多,并且二次探测再散列的方法更好。

链地址法

公共溢出区

哈希表的查询


树(Tree):n(n >= 0)个节点构成的有限集合。

1、当`n = 0`时,称为空树。

2、对任意一棵非空树`(n > 0)`,它具备以下性质:

3、树中有一个称为根(Root)的特殊节点,用`r(root)`表示;

4、其余节点可分为`m(m > 0)`个互不相交的有限集`T1,T2,…Tm`,其中每个集合本身又是一棵树,称为原来树的子树(SubTree)

注意:

1、子树之间`不可以相交`;

2、除了根节点外,每个节点有且仅有一个父节点;

3、一个`N`个节点的树有`N-1`条边。


定义:图由边的集合及顶点的集合组成。 关于相关术语,请自行查找

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值