数据结构几个最简单的阐述完整版(带你入门:链表,栈,队列,哈希表,树)通俗易懂简单明了

数据结构几个最简单的阐述完整版
一.链表(Linked list):
如下图是一个链表:
1.链表是无须存储在连续的空间内,一般都是分散存储于内存中。(指针是指向下一个数据的内存地址)
2.所有要访问或查找时要一个一个往下连续访问。这就是所谓的 顺序访问
   (1)如果要添加一个数据:如添加一个数据D到AB之间
   只需要将A的指针指向位置由B变成D,D的指针指向B即可。
   (2)如果要删除一个数据:如把B从数据中删除
   只需要把A的指针指向改为C即可,删除即可完成所有无须特意去删除B,用到B的所存储的空间时,就用新数据覆盖即可。
3.操作的时间复杂度:
   对链表的数据量我们假设为n。
   访问时我们从头部开始访问一一访问所有时间复杂度为O(n)。这是指目标数据在链表最后。 
   添加一个数据在链表中的时间复杂度与链表本身的数据量n无关,只需要改变俩个指针指向即可所以时间复杂度为O(1),同理删除也为O(1)。
4.代码实现:你可以使用C/C++,或java等等语言都可以,如果你是科班出身那么建议你先使用C语言实现可以更好的理解。
第一步:想要写好链表代码你应该先要看懂基本的链表代码。
我们先把记录指向下一个结点地址的指针叫做后继指针next。(java,Python没有指针把它理解成“引用”即可)
在写链表代码的时候你可能会经常看到下面这种代码这里我做一个简单的示范:
p->next=q;
这代码表示的是p结点的next指针存储了q结点的内存地址。
这个就更复杂一点   p->next=p->next->next;
表示p结点的next指针存储了下下一个结点的内存地址。
接下来可以试试添加(插入)与删除操作
当你想要向链表中插入一个新的结点如在p后插入一个新结点只需下面的代码:
new_node->next=p-next;
p->next=new_node;
但是你有没有想过一个可能就是链表为空时那么刚刚的操作就明显有问题了,所以你需要补充一个条件如下即可,head表示链头结点
if(head==null){
     head=new_node;
}
接下来可以试试删除操作只需要一行代码
p-next=p->next->next;
这里我们也会遇到一个特殊情况当我们要删除的结点是最后一个结点时显然只用这一行代码是行不通的,一样需要特殊处理。
if(head->next==null){
    head = null;
}
二.数组:
1.数组也是数据呈线性排列的一种数据结构。与链表不同的是数组中的访问是十分简单的,但是添加和删除就要困难许多。
   如下就是数组的概念图。
2.数据按顺序存储在连续的空间内如下图:
由于数据是存储在连续空间内的,所以每个数据的内存地址都可以通过数组下标算出来,
也就是说我们可以直接访问目标数据这就是所谓的 随机访问
(1).如果想要添加一个数据:如在数组第2个位置(a[1])上添加一个数据Green。如图:
首先我们得腾出一个空间这样才能添加数据如图:
然后接下来把Red向后移动到a[3],Yellow移动到a[2]。如图:
接着把空的位置填上Green即可。
(2).当我想删除一个数据时:如把Green删除
首先我们要删除掉目标数据(Green)如图:
然后将数据向左一个个移动,最后在删除掉多余的空间即可。
3.操作的时间复杂度:
同理我们假设数组的数据量为n。
随机访问一个数据的因为只需要通过下标即可计算出内存地址(随机访问),所以时间复杂度为O(1)。
如果想要添加一个数据,因为要把添加目标的位置后面的数据一个个向后移动,所以时间复杂度为O(0)。删除同理。
4.代码实现小练习:你可以使用C/C++,或java等等语言都可以,如果你是科班出身那么建议你先使用C语言实现可以更好的理解。
三.栈
1.栈也是一个数据呈线性排列的数据结构要它的一大特性为 先进后出,后进先出
所以这种数据结构有一个缺点是每次访问只能访问最新放入的数据即栈顶元素。
栈你可以想象成一个一次只能放一本书的箱子,所以很好理解最先放进的书
当然只能最后拿,最后放的书只能最先拿。如图就是一个栈:
2.栈的具体操作。
   (1).当你想要把数据Green和Red放入栈中时我们需要用到的一个操作即是压栈或入栈(push)。
        我们需要先把Green入栈,再把Red的入栈。如图:
    
(2).当你想把数据移动出栈时你需要用到出栈操作(pop)。
与入栈同理都要依次一个个出栈。如图:
所以每次你要访问一个数据必须先把它移到栈顶。删除与添加都必须在一端进行。
3.操作的时间复杂度
假设数据量为n。
当你访问栈底数据你需要将数据一个个依次出栈,所以时间复杂度为O(n)。
4.代码实现小练习:你可以使用C/C++,或java等等语言都可以,如果你是科班出身那么建议你先使用C语言实现可以更好的理解。
四.队列
1.队列也是一种呈线性排列的数据结构。虽然与栈有点类似,但是在队列中添加与删除操作在两端进行。
如同它名字一样我们就把它看成正在排队的人群队伍一样,先自然就是排在最前面,后来排在最后面,
就是我们所说的 先进先出,后进后出。下面就是队列的概念图:
2. 具体操作 
(1).入队enqueue()
当你想往里添加一个数据时你必须一个个通过入队操作往里添加,
如图往里添加一个数据Green。再添加一个数据Red。如图:
(2).出队dequeue()
当你想从队中删除数据时,你只需使用出队操作。
遵循先进先出原则,所以先把数据Blue进行出队操作,
再把Green,Red依次进行出队操作,如图:
与栈不同数据添加与删除在两端进行,无法直接访问中间数据,访问中间数据时
需要通过出队edqueue()进行操作把目标数据移动到首位才能访问。
3.操作的时间复杂度
假设数据量为n。
要访问一个数据因为队列也是一种与栈一样操作受限的线性表数据结构,所以要把目标数据的
变成首位才能访问,假设目标数据最后入队,想要访问时间复杂度为O(n)。
4.代码实现小练习:你可以使用C/C++,或java等等语言都可以,如果你是科班出身那么建议你先使用C语言实现可以更好的理解。
五.哈希表
1.哈希表也是一种数据结构,使用“哈希函数”,可以使数据的查询效率得到显著提升。下面就是哈希表
哈希表存储的是由键(Key)和值(Value)组成的数据。如图我们将每个人的性别作为数据进行存储,键为人名,值为性别。
2.具体操作
我们来介绍一下哈希表的具体存储方式,看看能带给1我们什么便利。下面我们有五个空间来存储数据。如图:
我们先尝试存储一个元素进去。
(1)使用哈希函数(Hash)计算元素的键,得到结果为4928.(将得到的哈希值除以数组的长度这里为5),求得其余数。这样的求余运算叫做
“mod运算”得为3。就将它存入位置3。如图
同理你可以得到如下俩图
第二张图其实就是发生了存储位置的重复了的情况。将它先称为“冲突”。
那么相信看到这里应该有人可以知道如何解决这个问题了,没错那就是可以使用我们前面最开始讲到的链表。得到如下效果
具体我就不做多的描述相信很好理解。这样哈希表就制作完了。
(2)接下来就是查询操作。
当你想要查找一个元素时,其实并不复杂,如你要查找一个数据Ally的姓别(M为男,F为女)。
首先你要先找到它的位置。
第一步:先算出对应的哈希值。然后对其做mod运算,最终得到的结果为3,在3中查看会发现并不是你要找的
元素,那么这里就要使用我们前面讲的线性查找,于是一个个遍历我们便找到了Ally,对应其性别为F(女)。
(3)优点与缺点
优点非常的明显啦,我们在哈希表中可以利用哈希函数快速的查找出我们需要访问的元素。
如果发生哈希冲突,那么我们就使用链表来解决这个问题。这样一来我们不管数据量有多
少我们都可以灵活应对了。
缺点呢,如果存储的数组空间太小了,那么使用哈希表就很容易发生哈希冲突。那么这样的
话线性查找的频率就会大大加大。反之如果空间太大出现了很多空间,那么就会造成内存的浪费。
也就是说,给数组设定合适的空间非常的重要了。
4.代码实现小练习:你可以使用C/C++,或java等等语言都可以,如果你是科班出身那么建议你先使用C语言实现可以更好的理解。
六.树
我们这里以最为常见的二叉查找树为例子(又叫做二叉搜索树或者二叉排序树)是一种数据结构。
采用图的树形结构。
(1)这就是简单二叉查找树。每个结点最多为俩个子结点。二叉查找树有俩个性质:
第一个是每个结点的值均大于其左子树上任意一个结点的值。
比如9大于其左子树上的3和8。
第二个是每个结点的值均小于其右子树上任意的一个结点的值。比如结点15小于23,17,28.
(2)具体操作:
接下来我们试着插入一个元素。如添加一个元素1。
首先将1与顶元素进行比较,1<15。(小于王左大于往右)所有将1往左继续比较
1<9。所有继续往左,1<3。继续往左,发现没有结点了,所有把1放入到左下方。如下图
接下来我们试着把如下图中的元素28进行删除操作:
非常简单如果被删除元素没有子结点直接删除即可。假如你想删除元素8或者9呢。
如果我们要删除8也非常简单,只需要把8删除然后将4移动到原来8的位置即可。
如果你要删除9你可以进行如下操作。先把9删除,然后在被删除元素的左子树数中
既原来9的左子树中寻找一个最大的结点,这里为4,因为8已被删除。那么将4移动到
原来被删除的元素位置9的位置即可。那么就完成了一次删除操作了。
查找:
下面我们来介绍一下二叉查找树的查找操作。我们可以试试查找一下元素12。
首先我们先对顶元素进行比较12<15。所以继续往左查找。12>4,所以我们
往右进行查找,即可查询到元素12.
(3)特点:
我们可以把二叉查找树当做二分查找算法思想的树形结构体现。
因为它具有的俩个性质所有在查询数据或寻找合适添加数据的位置时,只要将其和现有的
数据进行比较大小,就可以根据比较结果得出该往那边移动。那么它比较的次数就取决于
树的高度了。如果结点树为n。那么树的形状相对均衡的话,比较大小和移动的次数最多为log2n。
时间复杂度为O(logn)。但是如果树的形状朝单侧纵向延伸,那么树自然就变的非常高,时间复杂度
也就变成了O(n)。
4.代码实现:你可以使用C/C++,或java等等语言都可以,如果你是科班出身那么建议你先使用C语言实现可以更好的理解。
看完以上介绍后,可以自行进行一些简单的代码实现作为练习。
以上图片全部出自书籍(我的第一本算法书———宫崎修一,石田保辉)
理解出自原创如有错误观点欢迎评论指出。
借鉴了我的第一本算法书,本文章自提供大家当读物使用。
  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值