问题描述

把数列\((x_1,x_2,\cdots,x_n)\)变换顺序为\((x_{p(1)},x_{p(2)},\cdots,x_{p(n)})\),其中\(p\)是\(A=\{1,2,3,\cdots,n\}\)的一个排列,要求只使用\(O(1)\)的额外空间。例如,当数列为\((10,20,30,40)\),\(p\)为\((3,1,2,4)\)时得到的数列是\((30,10,20,40)\).

算法描述

对于映射\(p:A\rightarrow A\),它的含义是“排列后的数组每个元素从哪里来”。即:变换后,数组下标\(k\)处的数从变换前的下标\(p(k)\)处来。变换后下标为\(p(k)\)处的数从变换前下标为\(p(p(k))\)处的数来……因此我们可以把这条变换的链记为:

\[k\leftarrow p(k)\leftarrow p(p(k))\leftarrow \cdots
\]

每一个下标都在唯一的一个“圈”内(原文这里的用词为"cycle")。举个例子:

对于给定的一个排列:

\[p=(8,2,7,1,6,9,3,4,5)
\]

我们可以观察到这样的规律:

\[\left\{\begin{array}{l}p(1)=8,p(8)=4,p(4)=1\\p(2)=2\\p(3)=7,p(7)=3\\p(5)=6,p(6)=9,p(9)=5\end{array}\right.
\]

对于括号中的每一行。最后一个等式右侧的数在\(p\)映射下的像,等于第一个等式左侧\(p\)作用的原像。对于每一个这样的圈,我们都能用大小为\(O(1)\)的额外空间完成数字的交换。而这个交换我们从每个圈中的最小数开始做。

代码描述:
for (int j = 1;j <= n;j++) {
int k = p(j);//n
while (k > j) {//n+a
k = p (k);//a
}
if(k == j) {
int y = x[j],l = p[k];//b
while (l != j) {//b+c
x[k] = x[l];//c
k = l;//c
l = p(k);//c
}
x[k] = y;//b
}
}
/*
这里b是变换p中"圈"的个数,c+b=n
a的含义是:对于每个j,在j所在的圈中第一个不大于j的数k距离p(j)的距离之和
*/
最坏情况

最坏的情况如下

\[p=(2,3,\cdots,n,1)\\a=(n-1)+(n-2)+\cdots +0=\frac{n^2-n}{2}\\b=1
\]

此为\(a\)的最坏情况和\(b\)的最好情况。

\[p=(1,2,\cdots,n-1,n)\\a=0\\b=n
\]

此为\(a\)的最好情况和\(b\)的最坏情况。

b的平均值分析

对于上面引用的\(p\)的实例:

\[p=(8,2,7,1,6,9,3,4,5)
\]

把所有的圈按照下述规则排列

1.圈内最小的数排在第一

2.圈内最小的数较大的,排在前面

则以上的\(p\)将变为\((5,6,9)(3,7)(2)(1,8,4)\),设\(q=(5,6,9,3,7,2,1,8,4)\).则这样的\(p\)到\(q\)的变换构成了一个排列到排列的双射。

这样,我们就可以把求\(b\)的值转化为求\(\{1,2,\cdots,n\}\)中满足\(q(j)=\min\{q(i)|i\le i \le j \}\)的\(j\)的个数。使得满足这样条件的\(j\)的个数为\(k\)的\(n\)元排列数共有\(\left[\begin{array}{c}n\\k\end{array}\right]\)种。(第一类Stirling数)

所以:

\[\overline{b}=\frac{\sum_{i=1}^n\left[\begin{array}{c}n\\i\end{array}\right]\times i}{n!}=H_n=\ln n+O(1)
\]

(当\(n\)充分大时,\(O(1)\)的值收敛到欧拉常数)

\[\sigma^2=H_n-H_n^{(2)}
\]

其中

\[H_n=1+\frac{1}{2}+\frac{1}{3}+\cdots+\frac{1}{n}\\H_n^{(2)}=1^2+(\frac{1}{2})^2+(\frac{1}{3})^2+\cdots+(\frac{1}{n})^2
\]

a的平均值分析

\[p=(8,2,7,1,6,9,3,4,5)\\q=(5,6,9,3,7,2,1,8,4)\\
\]

我们定义如下函数

\[y(i,j)=\left\{\begin{array}{l}1,\quad q(i)<q(k),\exist k \in (i,j]\\0,\quad else\end{array}\right.
\]

\[a=\sum_{1\le i<j\le n}y(i,j)
\]

\[\overline{y(i,j)}=\frac1{j-i+1}\\\overline a =\sum_{1\leq i<j\leq n}\overline{y(i,j)}=\sum_{1\leq i<j\leq n}\frac1{j-i+1}=\sum_{2\leq r\leq n}\frac{n+1-r}r
\]

其中,\(r=j-i+1\)

由上式:

\[\begin{aligned}\overline a&=\sum_{2\leq r\leq n}\frac 1r- \sum_{2\leq r\leq n}1\\&=(n+1)(H_n-1)-(n-1)\\&=(n+1)H_n-2n\\&=n\ln n +O(n)\\&=O(n\log n)+O(n)\end{aligned}
\]

\[\sigma^2=2n^2-(n+1)^2H_n^{(2)}-(n+1)H_n+4n
\]

由上面计算的\(b\)的均值\(\overline b=\ln n +O(1)=O(\log n)\)

所以算法的平均时间复杂度是\(O(n\log n)\)

《Mathematical Analysis of Algorithms》中有关“就地排列”(In Situ Permutation)的算法分析的更多相关文章

  1. 《Mathematical Analysis of Algorithms》中有关“选择第t大的数”的算法分析

    开头废话 这个问题是Donald.E.Knuth在他发表的论文Mathematical Analysis of Algorithms中提到的,这里对他的算法分析过程给出了更详细的解释. 问题描述: 给 ...

  2. "Mathematical Analysis of Algorithms" 阅读心得

    "Mathematical Analysis of Algorithms" 阅读心得 "Mathematical Analysis of Algorithms" ...

  3. 算法分析 Analysis of Algorithms -------GeekforGeeker 翻译

    算法分析 Analysis of Algorithms 为什么要做性能分析?Why performance analysis? 在计算机领域有很多重要的因素我们要考虑 比如用户友好度,模块化, 安全性 ...

  4. 《Principles of Mathematical Analysis》-chaper1-实数系与复数系

    今天我们开始简单的介绍数学分析这门课程,参考教材是Walter Rudin著的<Principles of Mathematical Analysis> 对于一门新课你最开始可能会问的是: ...

  5. GridView控件中加自动排列序号

    GridView控件中加自动排列序号 为 Gridview 增加一个新的空白列,如下: <asp:BoundField  HeaderText="序号">    < ...

  6. 6.046 Design and Analysis of Algorithms

    课程信息 6.046 Design and Analysis of Algorithms

  7. Lecture notes of Mathematical analysis

    Lecture notes of Mathematical analysis Preliminary theory Teaching purpose: Mathematical analysis is ...

  8. 排列计数(permutation)

    排列计数(permutation) 题目描述 求有多少种长度为n的序列A,满足以下条件: 1) 1~n这n个数在序列中各出现了一次 2) 若第i个数A[i]的值为i,则称i是稳定的.序列恰好有m个数是 ...

  9. Analysis of Algorithms

    算法分析 Introduction 有各种原因要求我们分析算法,像预测算法性能,比较不同算法优劣等,其中很实际的一条原因是为了避免性能错误,要对自己算法的性能有个概念. 科学方法(scientific ...

随机推荐

  1. 一篇文章带您读懂Map集合(源码分析)

    今天要分享的Java集合是Map,主要是针对它的常见实现类HashMap进行讲解(jdk1.8) 什么是Map核心方法源码剖析1.文档注释2.成员变量3.构造方法4.put()5.get() 什么是M ...

  2. 后渗透之meterpreter使用攻略

    Metasploit中的Meterpreter模块在后渗透阶段具有强大的攻击力,本文主要整理了meterpreter的常用命令.脚本及使用方式.包含信息收集.提权.注册表操作.令牌操纵.哈希利用.后门 ...

  3. 《高性能javascript》阅读摘要

    最近在阅读这本Nicholas C.Zakas(javascript高级程序设计作者)写的最佳实践.性能优化类的书.记录下主要知识. 加载和执行 脚本位置 放在<head>中的javasc ...

  4. C#小游戏—钢铁侠VS太空侵略者

    身为漫威迷,最近又把<钢铁侠>和<复仇者联盟>系列又重温了一遍,真的是印证了那句话:“读书百遍,其意自现”.看电影一个道理,每看一遍,都有不懂的感受~ 不知道大伙是不是也有同样 ...

  5. Ant-design-pro的动态菜单的实现

    页面效果: 如何实现: 1:分别建立SiderMenu和SubMenu组件 2.去and-desingn-vue的官方文档里copy单文件递归菜单的代码https://www.antdv.com/co ...

  6. Python爬虫 - UserAgent列表

    PC端: PC_USER_AGENT = [ 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)', 'Mozilla/4.0 (compatibl ...

  7. javascript中的中介者模式——迪米特法则

    ”迪米特法则“——最少知识原则,不和陌生人说话,就是说,一个对象应当对其他对象有尽可能少的了解.talk only to your immediate friends.初衷是:降低对象之间的耦合度. ...

  8. 基于Ubuntu+Python+Tensorflow+Jupyter notebook搭建深度学习环境

    基于Ubuntu+Python+Tensorflow+Jupyter notebook搭建深度学习环境 前言一.环境准备环境介绍软件下载VMware下安装UbuntuUbuntu下Anaconda的安 ...

  9. go-admin基于Gin + Vue + Element UI的前后端分离权限管理系统

    ✨ 特性 遵循 RESTful API 设计规范 基于 GIN WEB API 框架,提供了丰富的中间件支持(用户认证.跨域.访问日志.追踪ID等) 基于Casbin的 RBAC 访问控制模型 JWT ...

  10. docker redis安装及配置(外网访问 关闭安全限制 设置密码)

    docker run -p 6379:6379 --name redis -v /usr/local/redis/etc/redis.conf:/etc/redis/redis.conf -v /us ...