6.4 置换基本概念

​一 互换与轮换

  要了解群论,置换必不可少。而且置换在生活、工作中也非常常见。虽然说置换,有点小儿科,但是确实是数学里的重要内容。排列、组合和置换三者缺一不可。不能只学排列组合而不学置换。置换是对集合上的元素进行位置互换。这是对现实世界各种位置互换的抽象。现实中有很多置换的例子,比如击鼓传花游戏、华容道、滑块游戏、魔方、推箱子游戏、工厂的传送带、流水线等等。但是有些游戏,不是置换,比如象棋的吃子,就是替换,不是置换,那就是另一类数学问题。置换与排列密不可分。
  简单的置换分为两种:互换与轮换。

  同样,由简单到复杂。先由1 2 3 4 四个数字开始。

  首先是两两互换,所以这是个C(4,2)组合,所以有6种互换,如下

  1、2互换,1、3互换,1、4互换, 2、3互换, 2、4互换 ,3、4互换

  上面六个式子里的数字代表位置。

  轮换呢,就是几个位置,首位相连,形成一个环,每个位置把自身的元素移动到下一个位置。比如1、2、3轮换就是位置1上的元素移动到了位置2,位置2的元素移动到了位置3,位置3的元素移到了位置1。这对应了数学里循环排列的概念。互换其实是最小的轮换。所有的置换都可以表示为轮换或轮换的组合,这个划重点记哈,是学习置换的基础。但是还有一类置换,就是什么都不改变,类似数字的0,叫恒等置换。
  因为置换的作用对象是某个排列,所以可以说置换是个一元运算符,也可以说置换是一个函数,也可以说置换是一个映射,也可以说置换是一种作用。
  置换怎么表示呢?
  如果用(1,2)这样的写法来表示置换,容易和线性代数里的向量搞混了,所以不能那么表示,标准的做法是空格隔开位置,外面加一对括号,然后数字代表位置。所以互换的写法如下:
   ( 1    2 ) 、 ( 1    3 ) 、 ( 1    4 ) 、 ( 2    3 ) 、 ( 2    4 ) 、 ( 3    4 ) (1\;2) 、(1\;3)、 (1\;4)、 (2\;3) 、 (2\;4)、 (3\;4) (12)(13)(14)(23)(24)(34)
  多个元素的轮换,比如1、2、3的轮换记为 ( 1    2    3 ) (1\;2\;3) (123)。当然, ( 1    2    3 ) (1\;2\;3) (123)也可以写 ( 2    3    1 ) (2\;3 \;1) (231),因为1、2、3这3个顺序首位相连,形成一个环,以谁开始都无所谓。但是要注意里面不能有重复的位置,比如(1 2 1 4)这种就是不合法的置换,因为出现了1,2和1,4,这就有歧义了,位置1上的元素到底是移动到位置2,还是位置4呢?
  再考虑更复杂的置换的组合的写法
  比如(1 2)接着(1 3)怎么表示呢?
  群论里可以用加号+,也可以用乘号*,点号·,来表示“接着做”这个二元运算。伽罗瓦是推荐用乘号的,为了致敬伽罗瓦,我也用乘号,也可以省略乘号。而写的顺序就是按操作或执行顺序写
  所以(1 2)接着(1 3)写成(1 2)·(1 3)或 (1 2)(1 3)
  因为用的是乘号表达,所以(1 2 3),再(1 2 3)就可以表示为二次方,就写成 ( 1    2    3 ) 2 (1\;2\;3)^2 (123)2
  那么反向轮换,就可以表示为-1次方,就写成 ( 1    2    3 ) − 1 (1\;2\;3)^{-1} (123)1
  为了简洁,写轮换时,最好将最小的数字写在第一个位置。
  置换作用在排列上就直接把置换当成一个特殊函数,用函数的写法就行,比如对[A,B, C, D]这个字母的排列进行1、2、3轮换就可以这样写
   [ A , B , C , D ] ( 1    2    3 ) = [ C , A , B , D ] [A,B ,C ,D](1\;2\;3)=[C,A,B,D] [A,B,C,D](123)=[C,A,B,D]
  注意:数学里{}表示集合,是没有顺序的,而[]表示排列(计算机界叫列表),是有顺序的。排列写前面,置换写后面意思是对排列进行置换。
  按照伽罗瓦的习惯,什么都不改变记为单位元e。
  可以做个小练习
  1 计算如下置换
   [ 精 , 忠 , 报 , 国 ] ( 1    4    2    3 ) [精,忠,报,国](1\;4\;2\;3) [,,,](1423)
  答案是[报,国,忠,精]
  2 原排列是[国,精,忠,报],目前状态是[精,忠 ,报, 国],置换表达式是什么
  答案是(1 4 3 2)
  思考题:
  能不能用置换表示一个排列?
  答案:不能,除非指定初始排列。指定了初始状态的置换才能表示一个排列。

二 置换交换律与结合律

  那么继续探索置换是否符合交换律。
  以置换(1 3) (1 2)作用于(1 2 3 4)这个排列为例子:
[ 1 , 2 , 3 , 4 ] ( 13 ) = [ 3 , 2 , 1 , 4 ] ∴ [ 1 , 2 , 3 , 4 ] ( 13 ) ( 12 ) = [ 3 , 2 , 1 , 4 ] ( 12 ) = [ 2 , 3 , 1 , 4 ] [1,2,3,4] (1 3)= [3, 2, 1, 4]\\ ∴ [1, 2, 3, 4](1 3)(1 2)=[3, 2 ,1 ,4](1 2)=[2 ,3 ,1 ,4] [1,2,3,4](13)=[3,2,1,4][1,2,3,4](13)(12)=[3,2,1,4](12)=[2,3,1,4]
  注意,因为计算顺序是先计算(1 3),再计算(1 2),所以写法是 [1 ,2 ,3 ,4](1 3) (1 2) ,实际上要先计算[1 ,2, 3, 4](1 3) ,得到结果再执行(1 2)。
  而[2 ,3 ,1 ,4]是(1 3 2)这个轮换作用于[1 ,2 ,3, 4]这个排列的结果,所以(1 3) (1 2) = (1 3 2)。
  而经过运算我们得知,(1 2)(1 3)=(1 2 3)≠(1 3 2),所以置换不符合交换律
  再来看,无共同位置的置换叠加,也就是类似这种 ( 1    2 ) ( 3    4 ) (1\;2) (3\;4) (12)(34)
  而这种置换是符合交换律的,因为两次置换互相独立。只有部分场景符合交换律,不能说置换这个运算符合交换律。
  那么置换符不符合结合律?
  肯定是符合的,因为假设有三次置换。先做前两次置换的组合运算,再做第三次置换。先做第一次置换,再做后两次置换的组合,效果都是顺序三次置换。
  正因为这样才有了置换的化简。

三 置换的化简方法

   首先可以把置换进行以下的分类,大类是三类e、轮换和轮换组合。
类型举例描述
ee什么都不做,也叫恒等置换
轮换 (1 2) 互换
(1 2 3) 两个以上的元素轮换
轮换组合 (1 2) (3 4) 各组之间没有相同位置、符合交换律,所以各组轮换的顺序可以任意调整
(1 2)(2 3) 各组之间存在相同位置,不符合交换律,所以在写法上不能调整轮换的顺序
  置换的化简就是把轮换组合变成互相独立的轮换组合。这样做的目的是为了更方便计算,比如下面这个置换:

( 1    4    2    3 ) ⋅ ( 1    4    3    2 ) ⋅ ( 1    2    3 ) ⋅ ( 1    3    2 ) (1\;4\;2\;3)·(1\;4\;3\;2)·(1\;2\;3)·(1\;3\;2) (1423)(1432)(123)(132)
  这就非常复杂,让人根本不知道进行了什么。
  实际执行之后,和以下的置换结果是一样的
  (1 3 4)
  所以可以写成
  (1 4 2 3)· (1 4 3 2) ·(1 2 3)·(1 3 2)= (1 3 4)
  那么怎么化简啊?
  其实很简单,但是要仔细。以上面的式子为例子:
  首先看,1、2、3、4 四个位置都参与了置换
  就一个个来,首先看位置1
  (1 4 2 3) 位置1移动到了位置4
  (1 4 3 2) 位置4移动到了位置3
  (1 2 3)位置3移动到了位置1
  (1 3 2)位置1移动到了位置3
  所以最终位置1移动到了位置3
  再看位置2
  (1 4 2 3) 位置2移动到了位置3
  (1 4 3 2) 位置3移动到了位置2
  (1 2 3)位置2移动到了位置3
  (1 3 2)位置3移动到了位置2
  所以最终位置2不改变
  再看位置3
  (1 4 2 3) 位置3移动到了位置1
  (1 4 3 2) 位置1移动到了位置4
  (1 2 3)和(1 3 2)不影响位置4
  所以最终位置3移动到了位置4
  再看位置4
  (1 4 2 3) 位置4移动到了位置2
  (1 4 3 2) 位置2移动到了位置1
  (1 2 3)位置1移动到了位置2
  (1 3 2)位置2移动到了位置1
  所以最终结果是:
  位置1移动到了位置3
  位置2不改变
  位置3移动到了位置4
  位置4移动到了位置1
  那么最终化简之后,就是(1 3 4)
  总结一下,就是以下几步:
  1 找出所有发生改变的位置
  2 对每个位置,从第一个轮换开始,到最后一个轮换结束,跟踪变化,记录最终位置
  3 将起始位置和最终位置变成置换表达式
  学废了吗?
  化简后的置换表达式,如果是轮换组合,则这些组合是无关联的。
  上面的计算方法很繁琐,我推荐一个矩阵连线法手动计算非常方便快捷。这个手动计算方法来自国内一本介绍李群的电子书。还是刚刚的例子:
(1 4 2 3)· (1 4 3 2) ·(1 2 3)·(1 3 2)
  写出一个矩阵(严格来讲不能叫矩阵,因为矩阵不能残缺啊,哈哈)
1    4    2    3 1    4    3    2 1    2    3 1    3    2 1\;4\;2\;3\\ 1\;4\;3\;2\\ 1\;2\;3\\ 1\;3\;2\\ 14231432123132
再连线
在这里插入图片描述
  每个数字去连接下面行的下一个位置,但是不要忘了最后一行的计算
  所以有
  1连线到1,再下一个位置为3
  3连线到1,再下一个位置为4
  4连线到2,再下一个位置1
  2连线到3,再下一个位置为2,不变
  所以结果为(1 3 4)

四 轮换的乘方计算方法

  所谓乘方,就是同样的轮换,重复几次

  我可以用图形来表示,下图是轮换(1 2 3 4 5 6 7 8)前的状态
在这里插入图片描述
  这个图是轮换后的状态
在这里插入图片描述
  嗨,就是轮换一次转了1/8个圆周呗。转8次就转回原来位置呗。所以理解轮换,就是脑中想象一个圆盘,形成一个轮,然后就豁然开朗。
  根据上面介绍的化简方法,计算轮换的乘方,就非常简单了。
  比如这个复杂的轮换
( 1    11    4    2    3    8    5    12    6    10    7    9 ) (1\;11\;4\;2\;3\;8\;5\;12\;6\;10\;7\;9) (111423851261079)
  重复9次结果为
( 1    10    5    2 ) ⋅ ( 3    11    7    12 ) ⋅ ( 4    9    6    8 ) (1\;10\;5\;2)·(3\;11\;7\;12)·(4\;9\;6\;8) (11052)(311712)(4968)
  那是怎么计算出来的呢?
  先把轮换表达式里的数字进行编号,也就是写出位置的索引
| 索引 |1 |2| 3| 4| 5| 6 |7 |8| 9 |10 |11| 12 |
|–|–|–|–|–|–|–|–|–|–|–|–|–|–|
| 位置 |1| 11| 4| 2| 3| 8| 5 |12| 6| 10| 7| 9 |
  以位置1为例子,轮换1轮,到了位置11,轮换二轮到了位置14,依此类推,第9轮就到了位置10。
  所以可以先对索引做加法

123456789101112
101112131415161718192021
  那么这个索引超出了12,因为是轮换,形成一个轮,那么就需要取余数
  于是下面是取余结果,这就是新旧索引变化表
123456789101112
101112123456789
  然后再去原索引表找位置,记录变换后的位置
原位置11142385126107
原索引1234567891011
新索引10111212345678
新位置10791114238512
  删掉中间两行,得到位置变化表
原位置11142385126107
新位置10791114238512
  所以置换表达式为
( 1    10    5    2 ) ( 3    11    7    12 ) ( 4    9    6    8 ) (1\;10\;5\;2)(3\;11\;7\;12) (4\;9\;6\;8) (11052)(311712)(4968)
  故(1 11 4 2 3 8 5 12 6 10 7 9)9= (1 10 5 2) (3 11 7 12)(4 9 6 8)
  所以计算方法如下:
  1 写下置换表达式各个位置的索引表
  2 根据轮换次数,按模加法(先加再取余数),得到新索引
  3 根据新索引,按索引表取新位置记录下来,得到新旧位置变化表
  4 根据新旧位置变化表写出新的置换表达式
  由此,可以得到三个轮换幂运算的三个规律
  规律一:N个位置的轮换重复N次回到初始状态(常识哈,无需证明)
  脑中想象一个轮在转,转一圈,刚好是N次。
  规律二:N个位置轮换i轮,结果是互相独立的gcd(i,n)组轮换,gcd是最大公约数的意思。
  规律三:轮换的逆运算是其表达式里位置的倒序
  逆运算,写法上就是-1次方。从排列A到排列B,置换是M,从排列B再回到排列A,置换就是M-1.

五 轮换的其他规律

  我们之所以大量研究轮换,无非是一点,轮换太重要了,在置换里占比太多了。先思考一个问题,我们都知道,置换就是三类:零置换、轮换组合、轮换。互换是最小的轮换,不单独考虑。
  规律四:多个位置与同一个位置的置换形成轮换
( a    b ) ( a    c ) ( a    d ) … … ( a    n ) = ( a    b    c    d … … n ) (a\;b) (a\;c)(a\;d)……(a\;n)=(a\;b\;c\;d……n) (ab)(ac)(ad)(an)=(abcdn)
  根据置换的化简规则,依次分析
  a 位置到b,后面的表达式里没有了b
  b位置到了a,第二个表达式里位置再到c
  c位置到了a,下一个表达式里到了d,以后再无改变
  此后,每个位置的改变都只出现在两个表达式中
  最后一个元素n,位置到了a
  所以形成了一个a到n的轮换
  这个规律特别重要,可以快捷运算很多式子
  由这个规律可以计算互换与轮换的乘法
  比如下面这两个式子:
( 1    2    3    4    5    6    7    8    9 ) ⋅ ( 5    6 ) = ( 1    2    3    4    6    7      9 ) ( 5    6 ) ⋅ ( 1    2    3    4    5    6    7    8    9 ) = ( 1    2    3    4    5    7    8    9 ) (1\;2\;3\;4\;5\;6\;7\;8\;9)·(5\;6)=(1\;2\;3\;4\;6\;7\;\;9)\\ (5\;6)·(1\;2\;3\;4\;5\;6\;7\;8\;9)=(1\;2\;3\;4\;5\;7\;8\;9) (123456789)(56)=(1234679)(56)(123456789)=(12345789)
  先分析第一个式子,其实就是对轮换的分解
( 1    2    3    4    5    6    7    8    9 ) = ( 6    7    8    9    1    2    3    4    5 ) = ( 6    7 ) ( 6    8 ) ( 6    9 ) ( 6    1 ) ( 6    2 ) ( 6    3 ) ( 6    4 ) ( 6    5 ) ∴ ( 1    2    3    4    5    6    7    8    9 ) ( 5    6 ) = ( 6    7 ) ( 6    8 ) ( 6    9 ) ( 6    1 ) ( 6    2 ) ( 6    3 ) ( 6    4 ) ( 6    5 ) ( 5    6 ) = ( 6    7 ) ( 6    8 ) ( 6    9 ) ( 6    1 ) ( 6    2 ) ( 6    3 ) ( 6    4 ) = ( 6    7    8    9    1    2    3    4 ) = ( 1    2    3    4    6    7    8    9 ) (1\;2\;3\;4\;5\;6\;7\;8\;9)= (6\;7\;8\;9\;1\;2\;3\;4\;5)=\\ (6\;7) (6\;8) (6\;9) (6\;1) (6\;2) (6\;3) (6\;4) (6\;5)\\ ∴(1\;2\;3\;4\;5\;6\;7\;8\;9)(5\;6)\\ = (6\;7) (6\;8) (6\;9) (6\;1) (6\;2) (6\;3) (6\;4) (6\;5) (5\;6)\\ = (6\;7) (6\;8) (6\;9) (6\;1) (6\;2) (6\;3) (6\;4)\\ =(6\;7\;8\;9\;1\;2\;3\;4)\\ =(1\;2\;3\;4\;6\;7\;8\;9) (123456789)=(678912345)=(67)(68)(69)(61)(62)(63)(64)(65)(123456789)(56)=(67)(68)(69)(61)(62)(63)(64)(65)(56)=(67)(68)(69)(61)(62)(63)(64)=(67891234)=(12346789)
  第二个式子,也是对轮换的分解
( 1    2    3    4    5    6    7    8    9 ) = ( 5    6    7    8    9    1    2    3    4 ) = ( 5    6 ) ( 5    7 ) ( 5    8 ) ( 5    9 ) ( 5    1 ) ( 5    2 ) ( 5    3 ) ( 5    4 ) ( 5    6 ) ⋅ ( 1    2    3    4    5    6    7    8    9 ) = ( 5    6 ) ( 5    6 ) ( 5    7 ) ( 5    8 ) ( 5    9 ) ( 5    1 ) ( 5    2 ) ( 5    3 ) ( 5    4 ) = ( 5    7 ) ( 5    8 ) ( 5    9 ) ( 5    1 ) ( 5    2 ) ( 5    3 ) ( 5    4 ) = ( 5    7    8    9    1    2    3    4 ) = ( 1    2    3    4    5    7    8    9 ) (1\;2\;3\;4\;5\;6\;7\;8\;9)= (5\;6\;7\;8\;9\;1\;2\;3\;4)\\ =(5\;6)(5\;7)(5\;8)(5\;9)(5\;1)(5\;2)(5\;3)(5\;4)\\ (5\;6)·(1\;2\;3\;4\;5\;6\;7\;8\;9)= (5\;6)(5\;6)(5\;7)(5\;8)(5\;9)(5\;1)(5\;2)(5\;3)(5\;4)\\ =(5\;7)(5\;8)(5\;9)(5\;1)(5\;2)(5\;3)(5\;4)\\ =(5\;7\;8\;9\;1\;2\;3\;4)\\ =(1\;2\;3\;4\;5\;7\;8\;9) (123456789)=(567891234)=(56)(57)(58)(59)(51)(52)(53)(54)(56)(123456789)=(56)(56)(57)(58)(59)(51)(52)(53)(54)=(57)(58)(59)(51)(52)(53)(54)=(57891234)=(12345789)
  规律五:类似以下这种链式置换,结果是顺序轮换的逆运算。
  (a b)(b c)(c d)(d e)(e f)(f g)(g h)= (h g f e d c b a)
  这个规律很容易明白。
  A 会一直下去,到达h的位置
  B 到a的位置,后续互换a再也不出现
  C到了b的位置,后续互换b再也不出现
  ……
  中间过程省略
  一直到最后h互换到了g的位置。
  所以组成了一个倒转的轮换。

六 置换凯来图

  规律六:所有的互换都可以拆分为第一个元素和其他元素的置换。因为(a b)(a c)(a b)= (b c)
  这里b、c的互换,可以通过a为中介做的,这也是凯来图的基础。以四个元素的置换为例子,我们知道所有的24种排列对应24种置换(包括零置换e)。最基础的互换是以下六种
  (1 2) (1 3) (1 4) (2 3) (2 4) (3 4)
  这六种中
  (2 3) (2 4) (3 4)可以拆分为:
  (2 3)=(1 2)(1 3)(1 2)
  (2 4)=(1 2)(1 4)(1 2)
  (3 4)=(1 3)(1 4)(1 3)
  所以,所有24种置换都可以由(1 2) (1 3) (1 4)三种互换生成。而生成关系可以画成一张图,称为凯莱图。这个非常重要,是凯莱图的理论基础。
  首先考虑只有一种置换,那么凯来图很简单,只有两个元素
E 、(1 2)
  只有两种的置换,凯来图是六个元素组成的环。
  如下图
在这里插入图片描述
  注意:上图的路径是(1 2)与(1 3)交替进行。
  这个置换凯莱图是更高阶的置换凯莱图的基础,因为更高级的置换是无数个这样的六边形组成的。
  四个元素的凯来图是,也是有多个六边形组成的。但是凯莱图很难画出。因为每个点连接三个六边形。总共24个点。凯来图比较复杂,如下:
在这里插入图片描述
  图中
  黑色线条代表(1 2)
  红色线条代表(1 3)
  蓝色线条代表(1 4)
  需要注意的是上图,有几个六边形特别难发现,这长得像核辐射符号。比如:
(1 3 4 2)->(2 3 4)->(1 4 2 3)->(1 4 2)->(2 4)->(1 2)(3 4)
  那么总共有几个六边形呢?
  我们可以这样计算,总共24个节点,每个六边形拥有6个节点。但是每个点属于三个六边形,也就是每个六边形实际上占有两个点。那么就是12个六边形。我们肉眼能直接看到7个六边形加上两个个辐射符号,再加上三个线轴形,也就是12个啊。
  1个正六边形挨着六个不规则六边形
  1个不规则六边形挨着1个正六边形,两个不规则六边形,1个核辐射,两个线轴
  1个核辐射挨着3个不规则六边形,三个线轴
  1个线轴挨着4个不规则六边形,两个核辐射
  超过四元素的置换凯莱图特别复杂,所以用凯莱图计算置换会非常吃力,最好使用代数运算或者数值运算的方法进行计算。
  不过对于大于四元素的置换凯来图也不必要那么慌,可以利用子群的方法去解开。比如从e出发的以(1 2) (1 3)交替前进的就是一个子群。
  这个子群的表示方法为<(1 2) ,(1 3)>。(1 2)和 (1 3)是路径,也叫生成元。那么再看那三个线轴符号,也是红黑两种线组成,这个叫左陪集。左陪集的意思是由非子群内单位元开始,生成的集合。以横着的线轴为例子,用左陪集表示就是(1 2)(3 4)<(1 2),(1 3)>表示以(1 2)(3 4)出发,沿着路径(1 2)和(1 3)往前走,形成一个六边形。
  所以这个复杂的置换群,可以拆分为一个子群和三个左陪集。
  可以这样拆成四个:
< ( 1    2 ) , ( 1    3 ) > ( 1    4 ) < ( 1    2 ) , ( 1    3 ) > ( 2    4 ) < ( 1    2 ) , ( 1    3 ) > ( 3    4 ) < ( 1    2 ) , ( 1    3 ) > <(1\;2),(1\;3)>\\ (1\;4)<(1\;2),(1\;3)>\\ (2\;4)<(1\;2),(1\;3)>\\ (3\;4)<(1\;2),(1\;3)> <(12),(13)>(14)<(12),(13)>(24)<(12),(13)>(34)<(12),(13)>

七 置换代数运算

  置换的代数运算就是去掉表示位置,纯粹用符号运算。以下就是置换代数运算的例子:
( a    b    c ) ⋅ ( a    d ) ⋅ ( a    b    c ) 2 = ( c    d ) ( a    b    c ) 2 ⋅ ( a    d ) ⋅ ( a    b    c ) = ( b    d ) (a\;b\;c)·(a\;d)·(a\;b\;c)^2=(c\;d)\\ (a\;b\;c)^2· (a\;d)·(a\;b\;c)=(b\;d) (abc)(ad)(abc)2=(cd)(abc)2(ad)(abc)=(bd)
  这种运算,只需要把前面介绍的化简方法改成代数符号运算就可以了。
  比如运算 ( a    b    c ) ⋅ ( a    d ) ⋅ ( a    b    c ) 2 (a\;b\;c)·(a\;d)·(a\;b\;c)^2 (abc)(ad)(abc)2
( a    b    c ) ⋅ ( a    d ) ⋅ ( a    b    c ) 2 = ( a    b    c    d ) ( a    b    c ) 2 (a\;b\;c)·(a\;d)·(a\;b\;c)^2 =(a\;b\;c\;d)(a\;b\;c)^2 (abc)(ad)(abc)2=(abcd)(abc)2
  利用乘方计算法则计算
( a    b    c ) 2 = ( a    c    b ) ∴ ( a    b    c    d ) ⋅ ( a    b    c ) 2 = ( a    b    c    d ) ( a    c    b ) (a\;b\;c)^2=(a\;c\;b)\\ ∴(a\;b\;c\;d)·(a\;b\;c)^2 = (a\;b\;c\;d)(a\;c\;b) (abc)2=(acb)(abcd)(abc)2=(abcd)(acb)
  再用最原始办法,写出四个元素的位置映射
a − > b − > a b − > c − > b c − > d d − > a − > c a->b->a\\ b->c->b\\ c->d\\ d->a->c\\ a>b>ab>c>bc>dd>a>c
  所以结果为(c d)
  另一个我就不详细写出了。

静态链表示意图:2.2 顺序表与链表的比较存储密度比较:顺序表:只存储数据元素、预分配存储空间链表:指针的结构性开销、链表中的元素个数没有限制按位查找:顺序表:O(1),随机存取链表:O(n),顺序存取插入和删除:顺序表:O(n),平均移动表长一半的元素链表:不用移动元素,合适位置的指针——O(1)时间复杂度:顺序表:若线性表频繁查找却很少进行插入和删除操作链表:若线性表需频繁插入和删除时空间复杂度:顺序表:知道线性表的大致长度,空间效率会更高链表:若线性表中元素个数变化较大或者未知2.3 栈        定义:限定仅在一端(栈顶)进行插入和删除操作的线性表,后进先出。栈示意图:        时间复杂度(插入与删除):顺序栈与链栈均为O(1)        空间复杂度:链栈多一个指针域,结构性开销较大,使用过程中元素个数变化较大时,用链栈;反之顺序栈。        出栈元素不同排列的个数:   (卡特兰数)        共享栈: 两个栈共享一片内存空间, 两个栈从两边往中间增长。卡特兰数的应用:存储结构:顺序栈初始化:top=-1链栈初始化:top=NULL栈的应用:        1) 括号匹配        2) 递归        3) 中缀表达式 转 后缀表达式        4) 中缀表达式:设两个栈(数据栈和运算符栈),根据运算符栈的优先级进行运算。2.4 队列        定义: 只允许在一端插入, 在另一端删除。具有先进先出的特点。队列示意图:        时间复杂度:均为O(1)        空间复杂度:链队列多一个指针域,结构性开销较大;循环队列存在浪费空间和溢出问题。使用过程中元素个数变化较大时,用链队列;反之循环队列。        双端队列: 只允许从两端插入、两端删除的线性表。双端队列示意图: 存储结构:        链队列:队头指针指向队头元素的前一个位置,队尾指针指向队尾元素,先进先出。        循环队列:                1)队空:front=rear                2)队满:(rear+1)%QueueSize=front                3)队列元素个数:(队尾-队头+队长)%队长==(rear-front+QueueSize)%QueueSize队列的应用:        1) 树的层次遍历        2) 图的广度优先遍历2.4 数组与特殊矩阵一维数组的存储结构:二维数组的存储结构: 对称矩阵的压缩(行优先):下三角矩阵的压缩(行优先):  上三角(行优先):三对角矩阵的压缩(行优先):稀疏矩阵压缩:十字链表法压缩稀疏矩阵:2.5 串        串,即字符串(String)是由零个或多个字符组成的有限序列。串是一种特殊的线性表,数据元素之间呈线性关系。字符串模式匹配:        1)朴素模式匹配算法        2)KMP算法手算KMP的next数组示意图:求next[2] :求next[3]: 求next[4]: 求next[5]: C语言求KMP的next数组代码示例:void Createnext(char *sub, int *next){ assert(sub != NULL && next != NULL); int j = 2; //模式串的next指针 int k = 0; //next数组的回溯值,初始化为next[1]=0 int lenSub = strlen(sub); assert(lenSub != 0); next[0] = -1; next[1] = 0; while (j < lenSub){ if (sub[j-1] == sub[k]){ next[j] = ++k; j++; } else{ k = next[k]; if (k == -1){ k = 0; next[j] = k; j++; } } }}求nextValue:void nextValue(char *sub, int *next) { int lenSub = strlen(sub); for(int j=2;j<lensub; j++){ if(sub[j]==sub[next[j]]) next[j]=next[next[j]] }}备注:         1) 实现next有多种不同方式, 对应不同的next数组使用        2) 根据实现方式不同, next数组整体+1不影响KMP算法。第三章 树和二叉树3.1 树和森林        定义(树):n(n≥0)个结点(数据元素)的有限集合,当 n=0 时,称为空树。3.1.1 树的基本术语        结点的度:结点所拥有的子树的个数。        叶子结点:度为 0 的结点,也称为终端结点。        分支结点:度不为 0 的结点,也称为非终端结点。        孩子:树中某结点子树的根结点称为这个结点的孩子结点。        双亲:这个结点称为它孩子结点的双亲结点。        兄弟:具有同一个双亲的孩子结点互称为兄弟。        路径:结点序列 n1, n2, …, nk 称为一条由 n1 至 nk 的路径,当且仅当满足结点 ni 是 ni+1 的双亲(1<=i<k)的关系。        路径长度:路径上经过的边的个数。        祖先、子孙:如果有一条路径从结点 x 到结点 y,则 x 称为 y 的祖先,而 y 称为 x 的子孙。        结点所在层数:根结点的层数为 1;对其余结点,若某结点在第 k 层,则其孩子结点在第 k+1 层。        树的深度(高度):树中所有结点的最大层数。        树的宽度:树中每一层结点个数的最大值。        树的度:树中各结点度的最大值。        树的路径长度:  从根到每个结点的路径长度总和        备注: 在线性结构中,逻辑关系表现为前驱——后继,一对一; 在树结构中,逻辑关系表现为双亲——孩子,一对多。        森林: 森林是m(m≥0)棵互不相交的树的集合, m可为0, 即空森林。3.1.2 树的性质        结点数=总度数+1        度为m的树第 i 层至多有 个结点(i≥1)        高度为h的m叉树至多有 个结点        具有n个结点的m叉树的最小高度为 最小高度推理过程图:3.1.3 树与森林的遍历树的遍历:先根遍历(先根后子树)后根遍历(先子树后根)层序遍历森林的遍历:前序遍历(先根, 后子树)中序遍历(先子树后根, 其实就是后序遍历树)区别与联系:         1) 树的前序遍历等价于其树转化二叉树的前序遍历!        2) 树的后序遍历等价于其树转化二叉树的中序遍历!3.1.4 树的存储结构双亲表示法图:孩子表示法图:孩子兄弟表示法图(树/森林转化为二叉树):3.1.5 树转二叉树在树转为二叉树后, 有以下结论:        1) 树的叶子结点数量 = 二叉树左空指针数量(形象理解为树越宽, 兄弟越多, 越是向右长)        2) 树的非叶子结点数量 = 二叉树右空指针-1(非叶子必有儿子, 右指针由儿子提供, -1是根节点多了一个右空指针)3.2 二叉树3.2.1 二叉树的性质斜树:左斜树:所有结点都只有左子树的二叉树右斜树:所有结点都只有右子树的二叉树        满二叉树:所有分支结点都存在左子树和右子树,且所有叶子都在同一层上的二叉树        完全二叉树:在满二叉树中,从最后一个结点开始,连续去掉任意个结点得到的二叉树完全二叉树特点:叶子结点只能出现在最下两层且最下层的叶子结点都集中在二叉树的左面完全二叉树中如果有度为 1 的结点,只可能有一个,且该结点只有左孩子深度为 k 的完全二叉树在 k-1 层上一定是满二叉树在同样结点个数的二叉树中,完全二叉树的深度最小        性质:在二叉树中,如果叶子结点数为 n0,度为 2 的结点数为 n2,则有: n0=n2+1证明: 设 n 为二叉树的结点总数,n1 为二叉树中度为 1 的结点数,则有: n=n0+n1+n2        在二叉树中,除了根结点外,其余结点都有唯一的一个分枝进入,一个度为 1 的结点射出一个分枝,一个度为 2 的结点射出两个分枝,所以有:n=n1+2n2+1        性质:二叉树的第 i 层上最多有个结点(i≥1)        性质:一棵深度为 k 的二叉树中,最多有 个结点        性质:具有 n 个结点的完全二叉树的深度为 向下取整+1 (或向上取整)证明:设具有 n 个结点的完全二叉树的深度为 k,则:≤n  <对不等式取对数,有:k-1 ≤ <k即:<k ≤ +1由于 k 是整数,故必有k= +1         性质:对一棵具有 n 个结点的完全二叉树中从 1 开始按层序编号,对于任意的序号为 i(1≤i≤n)的结点(简称结点 i),有:如果 i>1,则结点 i 的双亲结点的序号为 i/2,否则结点 i 无双亲结点如果 2i≤n,则结点 i 的左孩子的序号为 2i,否则结点 i 无左孩子如果 2i+1≤n,则结点 i 的右孩子的序号为2i+1,否则结点 i 无右孩子        性质:若已知一棵二叉树的前序序列和中序序列,或者中序序列和后序序列,能唯一确定一颗二叉树。 3.2.2 二叉树的遍历        从根结点出发,按照某种次序访问树中所有结点,并且每个结点仅被访问一次。前序遍历(深度优先遍历)中序遍历后序遍历层序遍历(广度优先遍历)3.2.3 二叉树的存储链式存储图:顺序存储图:3.2.4 线索二叉树        利用二叉树中n+1个空指针, 将指针指向结点的前驱和后继。线索二叉树是加上线索的链表结构,  是一种物理结构存储结构:示例图:三种线索化的对比图: 各自特点:3.3 哈夫曼树和哈夫曼编码        带权路径长度(WPL):从根结点到各个叶子结点的路径长度与相应叶子结点权值的乘积之和        最优二叉树(哈夫曼树):给定一组具有确定权值的叶子结点,带权路径长度最小的二叉树特点:权值越大的叶子结点越靠近根结点只有度为 0 和度为 2 的结点,不存在度为 1 的结点构造过程中共新建了n-1个结点, 因此总结点数为2n-1        前缀编码:在一组编码中,任一编码都不是其它任何编码的前缀, 前缀编码保证了在解码时不会有多种可能。         度为m的哈夫曼树: 通过只有度为m和度为0求解非叶子结点 3.4 并查集        存储结构: 双亲表示法        实现功能: 并查(并两个集合, 查根结点)        优化: 小树并到大树, "高树变矮树"(压缩路径)第四章 图        定义:顶点集V和边集E组成,记为G = (V, E)        注意:线性表可以是空表,树可以是空树,但图不可以是空,即V一定是非空集, 边集E可以为空        子图:若图G=(V, E),G'=(V', E'),如果V' 属于 V 且E' 属于E,则称图G'是G的子图4.1 图的基本概念图的分类:        无向边:表示为(vi,vj),顶点vi和vj之间的边没有方向        有向边(弧):表示为<vi,vj>,从vi 到vj 的边有方向, vi为弧尾, vj为弧头        稠密图:边数很多的图        稀疏图:边数很少的图        无向完全图:无向图中,任意两个顶点之间都存在边        有向完全图:有向图中,任意两个顶点之间都存在方向相反的两条弧度、入度和出度:        顶点的度:在无向图中,顶点 v 的度是指依附于该顶点的边数,通常记为TD (v)        顶点的入度:在有向图中,顶点 v 的入度是指以该顶点为弧头的弧的数目,记为ID (v);        顶点的出度:在有向图中,顶点 v 的出度是指以该顶点为弧尾的弧的数目,记为OD (v);        握手定理: 路径:         回路(环):第一个顶点和最后一个顶点相同的路径        简单路径:序列中顶点不重复出现的路径        简单回路(简单环):除第一个和最后一个顶点外,其余顶点不重复出现的回路。        路径长度:非带权图——路径上边的个数        路径长度:带权图——路径上边的权值之和         极大连通子图: 连通的情况下, 包含尽可能多的边和顶点, 也称连通分量        极小连通子图: 删除该子图中任何一条b边, 子图不再连通, 如生成树无向连通图:        连通顶点:在无向图中,如果顶点vi和顶点vj(i≠j)之间有路径,则称顶点vi和vj是连通的        连通图:在无向图中,如果任意两个顶点都是连通的,则称该无向图是连通图        连通分量:非连通图的极大连通子图、连通分量是对无向图的一种划分连通分量示意图:有向强连通图、强连通分量:        强连通顶点:在有向图中,如果从顶点vi到顶点vj和从顶点vj到顶点vi均有路径,则称顶点vi和vj是强连通的        强连通图:在有向图中,如果任意两个顶点都是强连通的,则称该有向图是强连通图        强连通分量:非强连通图的极大连通子图强连通分量示意图: 子图与生成子图:常考点无向图:        所有顶点的度之和=2|E|        若G是连通图,则最少有 n-1 条边(树),若 |E|>n-1,则一定有回路        若G是非连通图,则最多可能有 条边 (n-1个完全图+1个孤点)        无向完全图共有条边有向图:        所有顶点的出度之和=入度之和=|E|        所有顶点的度之和=2|E|        若G是强连通图,则最少有 n 条边(形成回路)        有向完全图共有条边图的遍历:从图中某一顶点出发访问图中所有顶,并且每个结点仅被访问一次。深度优先遍历序列(dfs)广度优先遍历序列(bfs)    备注:  调⽤BFS/DFS函数的次数 = 连通分量数4.2 图的存储结构 邻接矩阵:一维数组:存储图中顶点的信息二维数组(邻接矩阵):存储图中各顶点之间的邻接关系特点:一个图能唯一确定一个邻接矩阵,存储稀疏图时,浪费空间。空间复杂度为: O()。示意图:性质 (行*列) :邻接表:顶点表:所有边表的头指针和存储顶点信息的一维数组边表(邻接表):顶点 v 的所有邻接点链成的单链表示意图:特点:空间复杂度为:O(n+e), 适合存储稀疏图。两者区别:十字链表法图:备注:         1) 十字链表只用于存储有向图        2) 顺着绿色线路找: 找到指定顶点的所有出边        3) 顺着橙色线路找: 找到指定顶点的所有入边        4) 空间复杂度:O(|V|+|E|)邻接多重表图:备注:        1) 邻接多重表只适用于存储无向图        2) 空间复杂度:O(|V|+|E|)四者区别: 4.3 最小生成树        生成树:连通图的生成树是包含全部顶点的一个极小连通子图, 可用DFS和BFS生成。        生成树的代价:在无向连通网中,生成树上各边的权值之和        最小生成树:在无向连通网中,代价最小的生成树        性质: 各边权值互不相等时, 最小生成树是唯一的。边数为顶点数-1生成森林示意图:4.3.1 Prim算法        从某⼀个顶点开始构建⽣成树;每次将代价最⼩的新顶点纳⼊⽣成树,直到所有顶点都纳⼊为⽌。基于贪心算法的策略。        时间复杂度:O(|V|2) 适合⽤于边稠密图。4.3.2 Kruskal 算法(克鲁斯卡尔)        每次选择⼀条权值最⼩的边,使这条边的两头连通(原本已经连通的就不选), 直到所有结点都连通。基于贪心算法的策略。        时间复杂度:O( |E|log2|E| ) 适合⽤于边稀疏图。4.4 最短路径        非带权图: 边数最少的路径(广度优先遍历)        带权图: 边上的权值之和最少的路径4.4.1 Dijkstra算法        时间复杂度:O(n2)        备注: Dijkstra 算法不适⽤于有负权值的带权图4.4.2 Floyd算法核心代码:        时间复杂度:O(n3)        备注: 可以⽤于负权值带权图, 不能解决带有“负权回路”的图三者区别:4.5 有向⽆环图(DAG)描述表达式 (简化前) :描述表达式 (简化后) :4.6 拓扑排序        AOV⽹(Activity On Vertex NetWork,⽤顶点表示活动的⽹): ⽤DAG图(有向⽆环图)表示⼀个⼯程。顶点表示活动,有向边表示活动Vi必须先于活动Vj进⾏如图:拓扑排序的实现:        ① 从AOV⽹中选择⼀个没有前驱(⼊度为0)的顶点并输出。        ② 从⽹中删除该顶点和所有以它为起点的有向边。        ③ 重复①和②直到当前的AOV⽹为空或当前⽹中不存在⽆前驱的顶点为⽌。逆拓扑排序(可用DFS算法实现):        ① 从AOV⽹中选择⼀个没有后继(出度为0)的顶点并输出。        ② 从⽹中删除该顶点和所有以它为终点的有向边。        ③ 重复①和②直到当前的AOV⽹为空备注: 上三角(对角线为0)矩阵, 必不存在环, 拓扑序列必存在, 但拓扑不唯一。(拓扑唯一, 图不唯一)4.7 关键路径        在带权有向图中,以顶点表示事件,以有向边表示活动,以边上的权值表示完成该活动的开销(如完成活动所需的时间),称之为⽤边表示活动的⽹络,简称AOE⽹示意图:        关键活动: 从源点到汇点的有向路径可能有多条,所有路径中,具有最⼤路径⻓度的路径称为 关键路径,⽽把关键路径上的活动称为关键活动。        事件vk的最早发⽣时间: 决定了所有从vk开始的活动能够开⼯的最早时间。        活动ai的最早开始时间: 指该活动弧的起点所表⽰的事件的最早发⽣时间。        事件vk的最迟发⽣时间: 它是指在不推迟整个⼯程完成的前提下,该事件最迟必须发⽣的时间。        活动ai的最迟开始时间: 它是指该活动弧的终点所表示事件的最迟发⽣时间与该活动所需时间之差。        活动ai的时间余量:表⽰在不增加完成整个⼯程所需总时间的情况下,活动ai可以拖延的时间。d(k)=0的活动就是关键活动, 由关键活动可得关键路径。示例图:第五章 查找        静态查找 :不涉及插入和删除操作的查找        动态查找 :涉及插入和删除操作的查找        查找⻓度: 在查找运算中,需要对⽐关键字的次数称为查找⻓度        平均查找长度:衡量查找算法的效率公式:5.1 顺序查找(线性查找):        顺序查找适合于存储结构为顺序存储或链接存储的线性表。  基本思想:从数据结构线形表的一端开始,顺序扫描,依次将扫描到的结点关键字与给定值k相比较,若相等则表示查找成功;若扫描结束仍没有找到关键字等于k的结点,表示查找失败。        时间复杂度: O(n)。有序顺序查找的ASL图:        无序查找失败时的平均查找长度:  n+1次 (带哨兵的情况)5. 2 折半查找:        元素必须是有序的,顺序存储结构。判定树是一颗平衡二叉树, 树高 (由n=-1得来)。        基本思想:用给定值k先与中间结点的关键字比较,中间结点把线形表分成两个子表,若相等则查找成功;若不相等,再根据k与该中间结点关键字的比较结果确定下一步查找哪个子表。        公式:mid=(low+high)/2, 即mid=low+1/2*(high-low);           1)相等,mid位置的元素即为所求           2)>,low=mid+1;                3)<,high=mid-1。        时间复杂度: 二叉判定树的构造:         备注:对于静态查找表,一次排序后不再变化,折半查找能得到不错的效率。但对于需要频繁执行插入或删除操作的数据集来说,不建议使用。失败结点的ASL不是方形结点, 而是其父节点。5.3 分块查找        分块查找,⼜称索引顺序查找。        基本思想:将查找表分为若干子块, 块内的元素可以无序, 块间的元素是有序的, 即前一个快的最大元素小于后一个块的最大元素。再建立索引表, 索引表中的每个元素含有各块的最大关键字和第一个元素的地址。索引表按关键字有序排列。示意图:备注:         1) 设索引查找和块内查找的平均查找⻓度分别为LI、LS,则分块查找的平均查找⻓度为ASL=LI + LS        2) 将长度为n的查找表均匀分为b块, 每块s个记录, 在等概率情况下, 若在块内和索引表中均采用顺序查找, 则平均查找长度为:5.4 二叉排序树        又称二叉查找树(BST,Binary Search Tree), 是具有如下性质的二叉树:左子树结点值 < 根结点值 < 右子树结点值        二叉排序树的插入:  新插入的结点 一定是叶子。二叉排序树的删除        1) 情况一, 删除叶结点, 直接删除        2) 情况二, 待删除结点只有一颗子树, 让子树代替待删除结点        3) 情况三, 待删除结点有左, 右子树, 则令待删除的直接前驱(或直接后继(中序遍历))代替待删除结点。示意图: (30为直接前驱, 60为直接后继)平均查找效率: 主要取决于树的高度。时间复杂度: 5.5 平衡二叉树        简称平衡树(AVL树), 树上任一结点的左子树和右子树的 高度之差不超过1。 结点的平衡因子=左子树高-右子树高。平衡二叉树的插: LL型:RR型:RL型:LR型:        平衡二叉树的删除: 同上考点:        假设以表示深度为h的平衡树中含有的最少结点数。 则有 = 0, = 1, = 2,并且有=  +          时间复杂度: 5.6 红黑树        与AVL树相比, 插入/删除 很多时候不会破坏“红黑”特性,无需频繁调整树的形态。因为AVL是高度差严格要求不超过1, 红黑树高度差不超过2倍, 较为宽泛。定义:        ①每个结点或是红色,或是黑色的        ②根节点是黑色的        ③叶结点(外部结点、NULL结点、失败结点)均是黑色的        ④不存在两个相邻的红结点(即红结点的父节点和孩子结点均是黑色)        ⑤对每个结点,从该节点到任一叶结点的简单路径上,所含黑结点的数目相同        口诀: 左根右,根叶黑 不红红,黑路同示例图:性质:        性质1:从根节点到叶结点的最长路径不大于最短路径的2倍 (红结点只能穿插 在各个黑结点中间)        性质2:有n个内部节点的红黑树高度          结论: 若根节点黑高为h,内部结点数(关键字)最多有 , 最少有示例图:红黑树的插入操作:红黑树的插入示例图:         红黑树的删除: 和“二叉排序树的删除”一样! 具体还是算了吧, 放过自己。。。        时间复杂度: 5.7 B树        B树,⼜称多路平衡查找树,B树中所被允许的孩⼦个数的最⼤值称为B树的阶,通常⽤m表示。 m阶B树的特性:        1)树中每个结点⾄多有m棵⼦树,即⾄多含有m-1个关键字。        2)若根结点不是终端结点,则⾄少有两棵⼦树。        3)除根结点外的所有⾮叶结点⾄少有 棵⼦树,即⾄少含有个关键字。         4) 所有的叶结点都出现在同⼀层次上,并且不带信息, ( 指向这些结点的指针为空 ) 。        5) 最小高度:    (n为关键字, 注意区分结点)        6) 最大高度:         7) 所有⼦树⾼度要相同        8) 叶结点对应查找失败的情况, 即n个关键字有n+1个叶子结点示例图: B树的插入(5阶为例):B树的删除:        1) 若被删除关键字在终端节点,则直接删除该关键字 (要注意节点关键字个数是否低于下限 ⌈m/2⌉ − 1)        2) 若被删除关键字在⾮终端节点,则⽤直接前驱或直接后继来替代被删除的关键字 删除77:删除38:删除90:        3) 若被删除关键字所在结点删除前的关键字个数低于下限,且此时与该结点相邻的左、右兄弟结 点的关键字个数均=⌈m/2⌉ − 1,则将关键字删除后与左(或右)兄弟结点及双亲结点中的关键字进⾏合并 删除49: 5.8 B+树⼀棵m阶的B+树需满⾜下列条件        1)每个分⽀结点最多有m棵⼦树(孩⼦结点)。        2)⾮叶根结点⾄少有两棵⼦树,其他每个分⽀结点⾄少有 ⌈m/2⌉ 棵⼦树。        3)结点的⼦树个数与关键字个数相等。        4)所有叶结点包含全部关键字及指向相应记录的指针,叶结点中将关键字按⼤⼩顺序排列,并且相邻叶结点按⼤⼩顺序相互链接起来        5)所有分⽀结点中仅包含它的各个⼦结点中关键字的最⼤值及指向其⼦结点的指针。所有⾮叶结点仅起索引作⽤,        6) 所有⼦树⾼度要相同B+树示例图:B+树与B树的对比图:5.9 哈希表(Hash)        根据数据元素的关键字 计算出它在散列表中的存储地址。        哈希函数: 建⽴了“关键字”→“存储地址”的映射关系。        冲突(碰撞):在散列表中插⼊⼀个数据元素时,需要根据关键字的值确定其存储地址,若 该地址已经存储了其他元素,则称这种情况为“冲突(碰撞)”        同义词:若不同的关键字通过散列函数映射到同⼀个存储地址,则称它们为“同义词”        复杂度分析:对于无冲突的Hash表而言,查找复杂度为O(1) 5.9.1 构造哈希函数        1) 除留余数法 —— H(key) = key % p, 取⼀个不⼤于m但最接近或等于m的质数p        适⽤场景:较为通⽤,只要关键字是整数即可        2) 直接定址法 —— H(key) = key 或 H(key) = a*key + b        适⽤场景:关键字分布基本连续        3) 数字分析法 —— 选取数码分布较为均匀的若⼲位作为散列地        适⽤场景:关键字集合已知,且关键字的某⼏个数码位分布均匀        4) 平⽅取中法(二次探测法)——取关键字的平⽅值的中间⼏位作为散列地址        适⽤场景:关键字的每位取值都不够均匀。5.9.2 处理冲突拉链法示意图:开放定址法:        1) 线性探测法        2) 平⽅探测法        3) 双散列法        4) 伪随机序列法示意图:        删除操作: 采用开放定址法时, 只能逻辑删除。        装填因子: 表中记录数 / 散列表长度 。        备注: 平均查找长度的查找失败包含不放元素的情况。(特殊: 根据散列函数来算: 2010真题)        聚集: 处理冲突的方法选取不当,而导致不同关键字的元素对同一散列地址进行争夺的现象第六章 排序        稳定 :如果a原本在b前面,而a=b,排序之后a仍然在b的前面;        内排序 :所有排序操作都在内存中完成;        外排序 :由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行。参考博客:超详细十大经典排序算法总结(java代码)c或者cpp的也可以明白_Top_Spirit的博客-CSDN博客6.1 直接插入排序动图演示:         优化: 折半插入排序6.2 希尔排序        又称缩小增量排序, 先将待排序表分割成若⼲形如 L[i, i + d, i + 2d,…, i + kd] 的“特殊”⼦表,对各个⼦表分别进⾏直接插⼊排序。缩⼩增量d,重复上述过程,直到d=1为⽌。建议每次将增量缩⼩⼀半。示例图:6.3 冒泡排序动图演示:6.4 快速排序算法思想:        1) 在待排序表L[1…n]中任取⼀个元素pivot作为枢轴(或基准)        2) 通过⼀趟排序将待排序表划分为独⽴的两部分L[1…k-1]和L[k+1…n],使得L[1…k-1]中的所有元素⼩于pivot,L[k+1…n]中的所有元素⼤于等于 pivot,则pivot放在了其最终位置L(k)上,这个过程称为⼀次“划分”。        3) 然后分别递归地对两个⼦表重复上述过程,直每部分内只有⼀个元素或空为⽌,即所有元素放在了其最终位置上。示例图:  6.5 简单选择排序        算法思想: 每⼀趟在待排序元素中选取关键字最⼩的元素加⼊有序⼦序列。动画演示:6.6 堆排序        ⼤根堆: 若满⾜:L(i)≥L(2i)且L(i)≥L(2i+1) (1 ≤ i ≤n/2 )        ⼩根堆: 若满⾜:L(i)≤L(2i)且L(i)≤L(2i+1) (1 ≤ i ≤n/2 )大根堆示例图:6.6.1 建立大根堆        思路:从开始, 把所有⾮终端结点都检查⼀遍,是否满足大根堆的要求,如果不满⾜,则进⾏调整。若元素互换破坏了下⼀级的堆,则采⽤相同的方法继续往下调整(⼩元素不断“下坠”)小元素下坠示例图:          结论: 建堆的过程,关键字对⽐次数不超过4n,建堆时间复杂度=O(n)6.6.2 堆的插入与删除        插入: 将新增元素放到表尾, 而后根据大小根堆进行上升调整。        删除: 被删除的元素⽤堆底元素替代,然后让该 元素不断“下坠”,直到⽆法下坠为⽌排序动图演示:6.7 归并排序        该算法是采用分治法, 把两个或多个已经有序的序列合并成⼀个。2路归并图:        结论:n个元素进⾏k路归并排序,归并趟数= 6.8 基数排序 (低位优先)        基数排序是非比较的排序算法,对每一位进行排序,从最低位开始排序,复杂度为O(kn),为数组长度,k为数组中的数的最大的位数;动图演示:         时间复杂度: ⼀趟分配O(n),⼀趟收集O(r),总共 d 趟分配、收集,总的时间复杂度=O(d(n+r)) , 其中把d为关键字拆 为d个部分, r为每个部分可能 取得 r 个值。基数排序适用场景:        ①数据元素的关键字可以⽅便地拆分为 d 组,且 d 较⼩        ②每组关键字的取值范围不⼤,即 r 较⼩        ③数据元素个数 n 较⼤如:内部排序总结:         基本有序:  直接插入(比较最少), 冒泡(趟数最少)6.9 外部排序        数据元素太多,⽆法⼀次全部读⼊内存进⾏排序, 读写磁盘的频率成为衡量外部排序算法的主要因素。示例图:多路归并:        结论: 采⽤多路归并可以减少归并趟数,从⽽减少磁盘I/O(读写)次数。对 r 个初始归并段,做k路归并,则归并树可⽤ k 叉树表示 若树⾼为h,则归并趟数 = h-1 = 。K越大, r越小, 读写磁盘次数越少。(缺点: k越大, 内部排序时间越大)6.9.1 败者树        使⽤k路平衡归并策略,选出⼀个最小元素需要对⽐关键字 (k-1)次,导致内部归并所需时间增加。因此引入败者树。示例图:        结论: 对于 k 路归并,第⼀次构造败者 树需要对⽐关键字 k-1 次 , 有了败者树,选出最⼩元素,只需对⽐关键字次6.9.置换-选择排序        使用置换-选择排序可以减少初始化归并段。示意图: 6.9.3 最佳归并树原理图:        注意:对于k叉归并,若初始归并段的数量⽆法构成严格的 k 叉归并树, 则需要补充⼏个⻓度为 0 的“虚段”,再进⾏ k 叉哈夫曼树的构造。示例图: 添加虚段数目: 难点:结束!  !  !注: 以上部分图片素材来自王道数据结构我要的图文并茂关注
最新发布
03-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

醒过来摸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值