- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 559811 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 173316
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 18
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
[数据结构与算法]16 什么,图这种数据结构把你难住了?!$ H9 ~0 K& c) |9 `
你是不是和我一样,在学习数据结构与算法时,了解了一下图这种数据结构之后,根本不知道它的用武之地在哪里?7 [9 H. { t7 l8 }$ s8 H1 K T
在我查了资料之后,现在我可以跟你讲讲,图可以这么用!, g+ J" i3 E9 M2 @' J( h
/ O+ N$ D$ R0 F5 z0 E
概念介绍
! j3 m4 S3 c( j8 Q5 l" g# C, X, c
7 s5 U! `* E2 c: H" |& n1 S# R" e先来了解一下什么是图.
+ m; m! H) \4 F6 s! I$ a图,是一种非线性表数据结构./ q. Q9 G0 n# `! y+ H6 ]; Y
那么你可能会问了,什么是线性表结构哇,我怎么区别一种数据结构是线性的,还是非线性的呢.+ R, v7 @2 y- G" h6 Q6 I2 s t4 S
哈哈,还好我机智,在这篇文章之前就写了一篇文章来介绍,如果还有疑问,楼上雅座请: [数据结构与算法]14 搞不懂线性结构,非线性结构?
6 v7 } j8 i1 L$ |. ~( |% L: J+ I7 _2 U
在图中元素叫做顶点( vertex ),图中的一个顶点可以和其他任意顶点建立连接关系,这种建立的关系叫做边( edge ): W* _/ |, b# Q" Q
' v+ K3 k: g0 k6 n' `
无向图- Q y2 Q0 j6 R2 ~, m+ ~, M( E
% y, I- ?$ t: G
& J) t9 }" X n5 _9 j上面给出的是无向图.看到这里你可能就觉得比较疑惑,这个无向图看起来没啥呀,怎么会有这种数据结构呢?" C* a q9 C) {* ^: w4 q5 A; \
不知道你是怎么想的,我刚开始学的时候就有这种疑问,这是什么神仙数据结构哇,还会有应用场景?
6 @% {: T) ~0 N* k# p
: ^3 O& ]; q O# [$ R既然有疑惑,那就给个应用场景:
+ U+ i1 r' @- E; K* e* C5 p7 M+ a9 M假设,现在你和我是微信好友,那是不是应该你的好友列表里面有我,我的好友里面有你,这样咱们才是好友对不对~- x* ~9 ^+ [' z: z2 M# ^
那在数据库中如何表示呢?吼~这个时候无向图就登场了
2 M2 N" j, U( x* C你和我是微信好友,那就在咱俩之间来条线,表示咱俩之间有关系,一条线就解决了问题,真是完美至极啊! k. o: \6 h: J4 B; o
假设,(怎么又是假设,哈哈哈)上图中表示的就是 A,B,C,D,E,F 之间的关系,那你可能就发现问题了,有的顶点线比较多,比如 D 有四条线,有的就相对少一些,比如 B 有两条线.这些线就表示顶点的度( degree ).这个概念有啥用?. v4 }$ G" o2 h- g" B0 d
能一眼看出来谁的好友多!那这个功能有啥用?(好吧,这个功能好像是有点儿鸡肋,不过也算是一个应用场景 s( B* w9 W1 R R
$ q" O3 n$ Z2 {
有向图: j( @: w) p" Q' p3 _
4 D4 X7 B8 g1 c2 e
看到上面的无向图,基础不错的小伙伴肯定会说了,我还知道有向图呢!% Y8 l1 a+ T u5 v% l. J. ^
呦呵,不错,有向图就是下面这个样子:
: [0 l& I0 v+ T% T( d& }3 A
* ?& @7 d. p1 [0 Q$ o5 a7 R在无向图中,咱们知道一个顶点有多少条边,就说它的度为多少.
, V( ~, S2 d5 u在有向图中呢,有指向顶点的,也有从顶点指出去的,基于无向图的概念,咱们把从这个顶点指出去的边称为出度,指向该顶点的边称为入度.2 X6 p/ N+ {/ A' s j! r- p2 i
那么有向图会应用在哪些场景呢?微信好友这个场景是不太可以了$ P9 h- A8 o/ [$ y1 q
那么微博呢?( c% y# n+ h$ V0 M7 P) f
微博和微信有什么不一样呢?微信是你和我是好友,那么咱们的好友列表里一定是要有彼此的,拉黑或者删除彼此了,那就不能互相发送消息了.
, P4 q, V h- Y$ j. j但是微博呢?你关注了我,并不代表我就要关注你对吧?看到这里有没有一种豁然开朗的感觉~( @% Z( v. z! D/ \
那么我关注了多少人就是出度,多少人关注了我就是入度.# A* R F0 w+ k; K: J' B
这样带入理解是不是会比较好一点儿?(我可真是个天才,哈哈哈
, ~8 P, l* T& H) e9 N+ x- q0 k7 D
& }2 w1 m5 [; [3 s$ T' n带权图; U/ D/ x( r3 c9 k- ?! s2 H
1 M. B9 c. I4 e) l# i看完了无向图,有向图,相信就有人说,我还见过带权图!(陈独秀给我坐下!
6 w: v6 t8 U7 G* m9 O7 i3 F4 S带权图长啥样呢?就下面这个样子:
9 L( e* _0 O. a( k. d* g, o2 j# K4 V. _. L
懵逼了,这每条边上的数字是个什么鬼呦
8 r9 k( ~0 v7 }2 ?. v- D别急,咱们来个场景:大家都玩 QQ 嘛?(别跟我说不玩,配合一下嘛…; f- Y5 v `, x* `; k4 A
玩 QQ 的话,一定知道有 QQ 空间,然后空间里面有个「谁在意我」「我在意谁」的功能,就是下图: k3 m- \2 Q& L6 C# ~
3 \9 g( l, v) e- \# F" b' ^
那么有没有好奇过呢? QQ 怎么知道我在意谁,谁在意我呢?+ H) @6 c/ _$ ^& d; h @$ u5 d
就是通过带权图哇& L0 p! J1 m( G5 y7 D
你访问了一个人的空间,这条边的权重就增加一点儿;别人访问了你的空间,那这条边的权重就增加一点儿;这段时间你们两个人聊天聊得比较频繁,来个小火花,顺便在你们两者之间的边权重增加一点儿.然后根据这些边的权重从大到小排序就得出了「谁在意我」「我在意谁」) \) T6 a! v/ z# F, X
/ J4 ~0 B( g6 Q% @7 k% _- w, Y
到这里,上面的一切理解都还 OK ?8 d! {6 N5 z3 h x$ l
那咱们继续.图是怎么表示的呢?1 G8 `" P1 y% ]3 O. [' |
图这种数据结构,再怎么画顶点,画边,到最后在物理结构上是怎么存储的呢?( U4 ? S$ u, Y; m/ s
别急,你所疑惑的,我都帮你想到了
7 ]! O" n c/ j5 C v$ \# S3 \/ Z* P7 m0 M
图的存储方法
% S$ c0 s4 Z, m7 c% y/ ^" P5 h5 V }" ~9 F
图的存储方法主要有以下两种:" {8 ]/ A. z+ u! ^' f+ A4 W6 h
' c" Z" D$ a6 ^5 |) i! _3 T* I6 v& a邻接矩阵( [) E& y- }# J( m2 k; ?* W* O
$ ?4 l9 n* D5 z6 d* I
邻接矩阵的底层依赖一个二维数组.对于无向图来说,如果 i 与 j 之间有边,那就将 A[j] 和 A[j] 标记为 1 ;对于无向图来说,如果 i 指向 j ,那么 A[j] 值为 1 ,如果 j 指向 i ,那么 A[j] 值为 1 ;对于带权图来说, A[j] 存储的值就不是 1 了,而是对应的权重值.所以这是图最直观的一种存储方法.$ P- d& G# X8 r! k$ Y
啥,你跟我说这还不直观?该不会是没有看下图吧:
0 {2 d4 s4 L* A0 |* h) l, E, r4 s
% [7 V' e& W: w% o1 ]但是你发现问题了嘛,这样看起来确实是直观了很多,但是很浪费空间有没有!比如无向图,如果 A[j] 为 1 ,那么 A[j] 肯定也是 1 ,多存储 A[j] 根本没啥必要.就像买东西,明明一块钱能买到的东西,为啥非要花两块钱?! {% a! s- I8 N1 n: Q! r# ~
所以如果使用邻接矩阵来表示的话,一定要清楚它的缺点.
2 p/ t4 B* e# K+ H% y) L* R! ]+ G3 r3 a# Q: C+ h
但这并不是说,使用邻接矩阵来存储就没啥优点.这天底下哪儿有那么绝对的事情呢.; B3 a- o& f! E! ]& p6 i; s8 v; J
首先,邻接矩阵的存储方式简单,直接,所以当我们需要获取两个顶点之间的关系时,相信我没有比这种存储结构更高效的了.( J% H& V- c, w; N* p
还有就是使用邻接矩阵存储图的另外一个优点就是方便计算,因为可以将很多图的运算转换成矩阵之间的运算./ a1 a! m2 A/ Q
+ z8 p7 N! g6 h1 s
邻接表8 L# v; \/ s' T, F) n/ H; s4 F
! ]4 A) {* O6 u' a4 o
先来看图:
' s- ~% c, R/ M% R; |
9 K- I3 a& u# Y* t6 w* ~2 } i, R3 O: l
乍一看,这不是散列表嘛!每个顶点对应一条链表,链表中存储的是与这个顶点相连接的其他顶点.1 T" c! z) v6 p3 l8 w+ w. w
嘿嘿,直觉超棒!2 n; {1 U. J2 a# J' p
/ c" S# \* G* ^5 m+ x! f; \/ ^如果你对散列表熟悉的话,应该知道,在散列表中,如果链太长了,会导致冲突概率增大,复杂度也蹭的一下升高.而且吧,链表的存储方式你也知道,不是连续的,所以相对于数组来说, CPU 读取就会慢一些,相对于邻接矩阵的存储方式,在邻接表中查询两个顶点之间的关系就没那么高效了.2 Z" D3 s' } d, p- V! @# A4 u
所以在实际开发中要注意遇到这种情况该如何处理,或者在刚开始的时候就直接设计好实现方式.比如可以将邻接表中的链表改为平衡二叉树,或者红黑树.
% H, T5 _1 V+ F6 P. _, W$ C2 |) D. H/ W/ {! i ?
我觉得对于数据结构来说,没有最好的,只有最合适的~
9 ]) R0 l3 F$ }1 X/ C1 e$ U G
: Z( N" r7 d! j( b4 ^参考0 Q" w7 Z+ G4 |# L* ~
" F! x8 D& m3 \: {极客时间—<数据结构与算法之美>& f1 v0 H8 t5 l
————————————————- P4 m+ K9 M: I& G) y' N
版权声明:本文为CSDN博主「郑璐璐」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。) m& E. D+ M' k* u
原文链接:https://blog.csdn.net/zll_0405/article/details/105209800
7 R) S: ]5 `' f6 r7 L9 D; Y. `3 W5 O
& D# m' G8 t& e) y
0 q7 X% ?- I8 h1 e |
zan
|