- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 564648 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 174617
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
[数据结构与算法]16 什么,图这种数据结构把你难住了?!
9 J9 R; V8 X9 p你是不是和我一样,在学习数据结构与算法时,了解了一下图这种数据结构之后,根本不知道它的用武之地在哪里?' X* a9 ]- `& G5 M9 m0 ]* c
在我查了资料之后,现在我可以跟你讲讲,图可以这么用!
, z( w. N* ]$ x9 q x8 n: x0 u+ l; |1 a$ Q3 y
概念介绍
+ Q8 Z' g+ Q* P
& w4 ~6 c2 T2 U9 W2 }$ J先来了解一下什么是图.
( [; [; [# A; H* Q' z图,是一种非线性表数据结构.
. `" w6 F1 q; T8 A( U; }: {3 q6 M0 \那么你可能会问了,什么是线性表结构哇,我怎么区别一种数据结构是线性的,还是非线性的呢.
& e; k/ D' m# y# [2 \5 ?哈哈,还好我机智,在这篇文章之前就写了一篇文章来介绍,如果还有疑问,楼上雅座请: [数据结构与算法]14 搞不懂线性结构,非线性结构?9 ?2 D) g7 M9 k7 W
1 ~# x- e& i _
在图中元素叫做顶点( vertex ),图中的一个顶点可以和其他任意顶点建立连接关系,这种建立的关系叫做边( edge )0 }0 K7 r8 i! J
0 p; O/ o% q1 C4 i& w
无向图
+ a8 O2 A6 N- _1 }0 B$ X, E
# O( x9 X" e1 r! R
$ j0 @9 S/ j/ u* u/ Q# F0 H上面给出的是无向图.看到这里你可能就觉得比较疑惑,这个无向图看起来没啥呀,怎么会有这种数据结构呢?. J& ]5 s, p$ I& b M
不知道你是怎么想的,我刚开始学的时候就有这种疑问,这是什么神仙数据结构哇,还会有应用场景?
( [; A5 M# b* s. w! \/ ]- j0 O' `
既然有疑惑,那就给个应用场景:7 Z8 a! T. X `0 x$ [& \
假设,现在你和我是微信好友,那是不是应该你的好友列表里面有我,我的好友里面有你,这样咱们才是好友对不对~
9 a( Z; X4 J- b/ R那在数据库中如何表示呢?吼~这个时候无向图就登场了3 M% J! p+ a8 L- J
你和我是微信好友,那就在咱俩之间来条线,表示咱俩之间有关系,一条线就解决了问题,真是完美至极啊
$ Z8 b4 y+ g* l, F假设,(怎么又是假设,哈哈哈)上图中表示的就是 A,B,C,D,E,F 之间的关系,那你可能就发现问题了,有的顶点线比较多,比如 D 有四条线,有的就相对少一些,比如 B 有两条线.这些线就表示顶点的度( degree ).这个概念有啥用?
/ w/ l1 h5 M$ _2 y/ C3 Y Q t能一眼看出来谁的好友多!那这个功能有啥用?(好吧,这个功能好像是有点儿鸡肋,不过也算是一个应用场景6 H* V& H9 S* i4 r' w3 e& N% m
9 W, ~4 W2 X% f- ]0 v6 i: _/ [
有向图# a: a7 t* ]/ D+ C! o
- j: [: {/ x' |. D看到上面的无向图,基础不错的小伙伴肯定会说了,我还知道有向图呢!
8 r. Q* L+ z; w$ x3 y& I9 F2 ~呦呵,不错,有向图就是下面这个样子:
5 ^0 Z' n7 }& O# X' c" B# r
, Q Z4 U1 [. k在无向图中,咱们知道一个顶点有多少条边,就说它的度为多少.
$ k8 H t F9 K) V3 ]在有向图中呢,有指向顶点的,也有从顶点指出去的,基于无向图的概念,咱们把从这个顶点指出去的边称为出度,指向该顶点的边称为入度.
; T& `1 _$ H8 G0 |那么有向图会应用在哪些场景呢?微信好友这个场景是不太可以了
% J# d$ q b% u9 |& N那么微博呢?6 B6 N8 {, C+ j9 ?4 T, K$ s0 K
微博和微信有什么不一样呢?微信是你和我是好友,那么咱们的好友列表里一定是要有彼此的,拉黑或者删除彼此了,那就不能互相发送消息了.
& x; q) M& g" S N; y( X1 {但是微博呢?你关注了我,并不代表我就要关注你对吧?看到这里有没有一种豁然开朗的感觉~
/ ?$ e; X9 g# P1 K" v那么我关注了多少人就是出度,多少人关注了我就是入度.# r# M. _6 z1 _8 Z# j* A; \
这样带入理解是不是会比较好一点儿?(我可真是个天才,哈哈哈
- }, i2 h8 O/ e) U
* y. \* ~0 }6 @' c) i' R! q带权图
4 h8 ^1 @2 C! R @5 s. { G" d; z; z) [
( l% ~( f& v# a
看完了无向图,有向图,相信就有人说,我还见过带权图!(陈独秀给我坐下!& W( Q# U; y- J6 W7 ~
带权图长啥样呢?就下面这个样子:# g3 r0 m$ o8 \
; v/ i$ e3 Z- S! [, ?8 M4 w
懵逼了,这每条边上的数字是个什么鬼呦
2 s/ h' x" k) e4 b别急,咱们来个场景:大家都玩 QQ 嘛?(别跟我说不玩,配合一下嘛…9 q1 f+ X8 m$ }
玩 QQ 的话,一定知道有 QQ 空间,然后空间里面有个「谁在意我」「我在意谁」的功能,就是下图:+ F% Q! | H: e8 _" x% x
& o* Y1 X2 ^! A# R' k7 i7 {那么有没有好奇过呢? QQ 怎么知道我在意谁,谁在意我呢?
8 {4 T: \' ~8 ?& `1 H+ O0 t& Q/ \ F就是通过带权图哇4 G8 T# x3 y7 |8 P- L/ M
你访问了一个人的空间,这条边的权重就增加一点儿;别人访问了你的空间,那这条边的权重就增加一点儿;这段时间你们两个人聊天聊得比较频繁,来个小火花,顺便在你们两者之间的边权重增加一点儿.然后根据这些边的权重从大到小排序就得出了「谁在意我」「我在意谁」4 C7 X6 N- a7 B* L& f
" i) n/ o+ N0 D% i, B/ ]. L% v
到这里,上面的一切理解都还 OK ?
: r0 O4 T6 t" S1 A% L那咱们继续.图是怎么表示的呢?6 u" Y0 l, T. Z3 e+ a X6 Y
图这种数据结构,再怎么画顶点,画边,到最后在物理结构上是怎么存储的呢?
* U& ^8 b- o: O+ d: W8 Q- K别急,你所疑惑的,我都帮你想到了8 [$ Q% r8 s4 t8 V& r* {
( L1 H( u+ @6 A7 q9 B图的存储方法- j1 p2 t' d q- N# C
G" U8 \4 x: S, R: f6 P: ~- |
图的存储方法主要有以下两种:
# F7 L, q. y0 M4 R( q; p, A# V) T9 H# \" a. ?" o4 b
邻接矩阵! D3 o6 N& X7 ?; \1 ~
& d2 J; Z! Y: [: [ {# O# ~
邻接矩阵的底层依赖一个二维数组.对于无向图来说,如果 i 与 j 之间有边,那就将 A[j] 和 A[j] 标记为 1 ;对于无向图来说,如果 i 指向 j ,那么 A[j] 值为 1 ,如果 j 指向 i ,那么 A[j] 值为 1 ;对于带权图来说, A[j] 存储的值就不是 1 了,而是对应的权重值.所以这是图最直观的一种存储方法.
) b* ~9 N5 I1 A. w/ |9 i' J3 v1 e啥,你跟我说这还不直观?该不会是没有看下图吧:
# F1 z/ S i# Q. M2 I
: n0 r8 C. z. g) d0 N6 W) F& J& h但是你发现问题了嘛,这样看起来确实是直观了很多,但是很浪费空间有没有!比如无向图,如果 A[j] 为 1 ,那么 A[j] 肯定也是 1 ,多存储 A[j] 根本没啥必要.就像买东西,明明一块钱能买到的东西,为啥非要花两块钱?
1 g) d9 e y' P( R) O: S) ^0 P; x- I+ T所以如果使用邻接矩阵来表示的话,一定要清楚它的缺点.6 f, p8 j5 F* z4 U, Z
: ~2 Q/ z4 [! H# T: O/ R
但这并不是说,使用邻接矩阵来存储就没啥优点.这天底下哪儿有那么绝对的事情呢.
f4 c: S9 l# Y; x: ^首先,邻接矩阵的存储方式简单,直接,所以当我们需要获取两个顶点之间的关系时,相信我没有比这种存储结构更高效的了.) e4 ~* i# a, D' a5 T! c
还有就是使用邻接矩阵存储图的另外一个优点就是方便计算,因为可以将很多图的运算转换成矩阵之间的运算.2 h" ~) G5 o9 _& r7 y0 E
" V& ~' M1 ^! c8 G- T' C, H. o2 `邻接表$ W4 v- D/ R# ]$ |
. [" e/ a+ s6 E3 }( W. R1 Z
先来看图:
5 I# }- T6 }2 _ l, U9 \1 k
% \8 J; H* L( O, h2 z1 G
^! @0 c& [1 J2 q* C
乍一看,这不是散列表嘛!每个顶点对应一条链表,链表中存储的是与这个顶点相连接的其他顶点." C% z' f8 C& ~
嘿嘿,直觉超棒!
1 v6 Y' \: m: n4 \0 N" I6 o8 }
! R1 Z+ Z8 ^+ u9 S) x如果你对散列表熟悉的话,应该知道,在散列表中,如果链太长了,会导致冲突概率增大,复杂度也蹭的一下升高.而且吧,链表的存储方式你也知道,不是连续的,所以相对于数组来说, CPU 读取就会慢一些,相对于邻接矩阵的存储方式,在邻接表中查询两个顶点之间的关系就没那么高效了.8 s) [! d w- g) h
所以在实际开发中要注意遇到这种情况该如何处理,或者在刚开始的时候就直接设计好实现方式.比如可以将邻接表中的链表改为平衡二叉树,或者红黑树.* r" C( B! q2 V9 `" m
5 c. ^+ x& ?# k8 C" S
我觉得对于数据结构来说,没有最好的,只有最合适的~
- h# W8 j( l4 p2 O3 s% J' \
9 H8 b5 ~ Y" j! R: k! R# D, @$ x参考
7 g3 O' Y0 x3 _6 \
" t; M8 M' d' @0 @# [, d5 H极客时间—<数据结构与算法之美>
* t. H: T+ y& K! y# n————————————————
# X: A4 g1 C' p版权声明:本文为CSDN博主「郑璐璐」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。" L' j& B) A/ W. _
原文链接:https://blog.csdn.net/zll_0405/article/details/105209800
; L. \, B0 Z- \: [; T8 Z+ L
) w9 |& x; V0 M' t6 L
' F! f- P' ^- J& W* {, {7 Z( \+ l |
zan
|