<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2551258626199289542</id><updated>2026-01-18T15:49:30.208-08:00</updated><category term="Sython"/><category term="Машинное обучение"/><category term="Графы"/><category term="Сортировки"/><category term="алгоритмы"/><category term="Оптимизация"/><category term="Поиск"/><category term="Структуры данных"/><title type='text'>Python алгоритмы</title><subtitle type='html'>Блог про алгоритмы и все что с ними связано. Основной инструмент реализации - Python.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>48</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-1086236035454133014</id><published>2015-04-26T13:35:00.001-07:00</published><updated>2020-05-26T06:59:43.485-07:00</updated><title type='text'>Python Profiling</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;cell border-box-sizing text_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://penandpantsdotcom.files.wordpress.com/2012/09/norm_fit_profile.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;281&quot; src=&quot;https://penandpantsdotcom.files.wordpress.com/2012/09/norm_fit_profile.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;text_cell_render border-box-sizing rendered_html&quot; style=&quot;border-style: none; box-sizing: border-box; outline: none; overflow-x: auto; padding: 0.5em 0.5em 0.5em 0.4em; resize: none; width: inherit;&quot;&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
Здесь рассматриваются методики профилировали в Питоне.&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
Это скорее памятка самому себе, но если кому-то пригодится, буду рад!)&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
Так же доступна интерактивная версия &lt;a href=&quot;https://www.dropbox.com/s/j1tbtg9rb3f6ogb/Python%20Profiling.ipynb?dl=0&quot;&gt;Ipython Notebook&lt;/a&gt;.&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;/div&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing text_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;text_cell_render border-box-sizing rendered_html&quot; style=&quot;border-style: none; box-sizing: border-box; outline: none; overflow-x: auto; padding: 0.5em 0.5em 0.5em 0.4em; resize: none; width: inherit;&quot;&gt;
&lt;div style=&quot;box-sizing: border-box;&quot;&gt;
&lt;a href=&quot;http://pynash.org/2013/03/06/timing-and-profiling.html&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #337ab7;&quot;&gt;http://pynash.org/2013/03/06/timing-and-profiling.html&lt;/a&gt;&amp;nbsp;- По теме&lt;br /&gt;
&lt;a href=&quot;https://ru.wikipedia.org/wiki/%D0%9C%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%BE_%D0%96%D1%8E%D0%BB%D0%B8%D0%B0&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #337ab7;&quot;&gt;https://ru.wikipedia.org/wiki/Множество_Жюлиа&lt;/a&gt;&amp;nbsp;- Рассматриваемый пример&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing code_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;input&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
In&amp;nbsp;[2]:&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;input_area&quot; style=&quot;background-color: #f7f7f7; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(207, 207, 207); box-sizing: border-box; line-height: 1.21429em;&quot;&gt;
&lt;div class=&quot; highlight hl-ipython2&quot; style=&quot;background-color: transparent; background-position: initial initial; background-repeat: initial initial; border: none; box-sizing: border-box; margin: 0.4em; padding: 0px;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: none; box-sizing: border-box; color: #333333; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;#  Перед этим pip install line_profiler, memory_profiler&lt;/span&gt;
&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;load_ext&lt;/span&gt; line_profiler
&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;load_ext&lt;/span&gt; memory_profiler
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing code_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;input&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
In&amp;nbsp;[6]:&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;input_area&quot; style=&quot;background-color: #f7f7f7; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(207, 207, 207); box-sizing: border-box; line-height: 1.21429em;&quot;&gt;
&lt;div class=&quot; highlight hl-ipython2&quot; style=&quot;background-color: transparent; background-position: initial initial; background-repeat: initial initial; border: none; box-sizing: border-box; margin: 0.4em; padding: 0px;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: none; box-sizing: border-box; color: #333333; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;&lt;span class=&quot;kn&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot; style=&quot;box-sizing: border-box; color: blue; font-weight: bold;&quot;&gt;functools&lt;/span&gt; &lt;span class=&quot;kn&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;wraps&lt;/span&gt;

&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot; style=&quot;box-sizing: border-box; color: blue;&quot;&gt;timefn&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;nd&quot; style=&quot;box-sizing: border-box; color: #aa22ff;&quot;&gt;@wraps&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot; style=&quot;box-sizing: border-box; color: blue;&quot;&gt;measure_time&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;t1&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;t2&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #ba2121;&quot;&gt;&quot;@timefn:&quot;&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;func_name&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #ba2121;&quot;&gt;&quot; took &quot;&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;t2&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;t1&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #ba2121;&quot;&gt;&quot; seconds&quot;&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;result&lt;/span&gt;
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;measure_time&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing code_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;input&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
In&amp;nbsp;[5]:&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;input_area&quot; style=&quot;background-color: #f7f7f7; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(207, 207, 207); box-sizing: border-box; line-height: 1.21429em;&quot;&gt;
&lt;div class=&quot; highlight hl-ipython2&quot; style=&quot;background-color: transparent; background-position: initial initial; background-repeat: initial initial; border: none; box-sizing: border-box; margin: 0.4em; padding: 0px;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: none; box-sizing: border-box; color: #333333; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;#@timefn&lt;/span&gt;
&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;#@profile&lt;/span&gt;
&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot; style=&quot;box-sizing: border-box; color: blue;&quot;&gt;calculate_z_serial_purepython&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;maxiter&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;zs&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;cs&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;):&lt;/span&gt; 
    &lt;span class=&quot;sd&quot; style=&quot;box-sizing: border-box; color: #ba2121; font-style: italic;&quot;&gt;&quot;&quot;&quot;Calculate output list using Julia update rule&quot;&quot;&quot;&lt;/span&gt;
    
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;zs&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot; style=&quot;box-sizing: border-box; color: #aa22ff; font-weight: bold;&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;xrange&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;zs&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)):&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;zs&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;cs&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;ow&quot; style=&quot;box-sizing: border-box; color: #aa22ff; font-weight: bold;&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;maxiter&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;c&lt;/span&gt;
            &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;+=&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;n&lt;/span&gt;

    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;output&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing code_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;input&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
In&amp;nbsp;[15]:&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;input_area&quot; style=&quot;background-color: #f7f7f7; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(207, 207, 207); box-sizing: border-box; line-height: 1.21429em;&quot;&gt;
&lt;div class=&quot; highlight hl-ipython2&quot; style=&quot;background-color: transparent; background-position: initial initial; background-repeat: initial initial; border: none; box-sizing: border-box; margin: 0.4em; padding: 0px;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: none; box-sizing: border-box; color: #333333; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;&lt;span class=&quot;kn&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot; style=&quot;box-sizing: border-box; color: blue; font-weight: bold;&quot;&gt;time&lt;/span&gt;

&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x2&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y1&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y2&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;1.8&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;1.8&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;1.8&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;1.8&lt;/span&gt;
&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;c_real&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;c_imag&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0.62772&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;-.&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;42193&lt;/span&gt;

&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot; style=&quot;box-sizing: border-box; color: blue;&quot;&gt;calc_pure_python&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;desired_width&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;max_iterations&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;):&lt;/span&gt; 
    &lt;span class=&quot;sd&quot; style=&quot;box-sizing: border-box; color: #ba2121; font-style: italic;&quot;&gt;&quot;&quot;&quot;Create a list of complex coordinates (zs) and complex parameters (cs), build Julia set, and display&quot;&quot;&quot;&lt;/span&gt;
    
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x_step&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x2&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;desired_width&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y_step&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y1&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y2&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;desired_width&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;ycoord&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y2&lt;/span&gt;
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;ycoord&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y1&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;ycoord&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;ycoord&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y_step&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;xcoord&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x1&lt;/span&gt;
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;xcoord&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x2&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;xcoord&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;xcoord&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x_step&lt;/span&gt;
        
    &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;##################### SHOW PYTHON HEAP&lt;/span&gt;
    &lt;span class=&quot;kn&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot; style=&quot;box-sizing: border-box; color: blue; font-weight: bold;&quot;&gt;guppy&lt;/span&gt; &lt;span class=&quot;kn&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;hpy&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;hp&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;hpy&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #ba2121;&quot;&gt;&quot;heapy after creating y and x lists of floats&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;hp&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;heap&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;h&lt;/span&gt;
    &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;######################&lt;/span&gt;
    
        
    &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;# Build a list of coordinates and the initial condition for each cell.&lt;/span&gt;
    &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;# Note that our initial condition is a constant and could easily be removed; # we use it to simulate a real-world scenario with several inputs to&lt;/span&gt;
    &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;# our function.&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;zs&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;cs&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;[]&lt;/span&gt;
    
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;ycoord&lt;/span&gt; &lt;span class=&quot;ow&quot; style=&quot;box-sizing: border-box; color: #aa22ff; font-weight: bold;&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;xcoord&lt;/span&gt; &lt;span class=&quot;ow&quot; style=&quot;box-sizing: border-box; color: #aa22ff; font-weight: bold;&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;zs&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;complex&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;xcoord&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;ycoord&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;))&lt;/span&gt;
            &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;cs&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;complex&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;c_real&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;c_imag&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;))&lt;/span&gt;
            
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #ba2121;&quot;&gt;&quot;Length of x:&quot;&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #ba2121;&quot;&gt;&quot;Total elements:&quot;&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;zs&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;start_time&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;calculate_z_serial_purepython&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;max_iterations&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;zs&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;cs&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;end_time&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;secs&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;end_time&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;start_time&lt;/span&gt;
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;calculate_z_serial_purepython&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;func_name&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #ba2121;&quot;&gt;&quot; took&quot;&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;secs&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #ba2121;&quot;&gt;&quot;seconds&quot;&lt;/span&gt;
    &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;# This sum is expected for a 1000^2 grid with 300 iterations. # It catches minor errors we might introduce when we&#39;re&lt;/span&gt;
    &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;# working on a fixed set of inputs.&lt;/span&gt;
    &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;#assert sum(output) == 33219980&lt;/span&gt;
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;output&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing code_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;input&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
In&amp;nbsp;[6]:&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;input_area&quot; style=&quot;background-color: #f7f7f7; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(207, 207, 207); box-sizing: border-box; line-height: 1.21429em;&quot;&gt;
&lt;div class=&quot; highlight hl-ipython2&quot; style=&quot;background-color: transparent; background-position: initial initial; background-repeat: initial initial; border: none; box-sizing: border-box; margin: 0.4em; padding: 0px;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: none; box-sizing: border-box; color: #333333; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;&lt;span class=&quot;sd&quot; style=&quot;box-sizing: border-box; color: #ba2121; font-style: italic;&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;sd&quot; style=&quot;box-sizing: border-box; color: #ba2121; font-style: italic;&quot;&gt;При построении с учетом отттенков серого, цвет меняющийся высоким контрастом дал бы нам представление о том, &lt;/span&gt;
&lt;span class=&quot;sd&quot; style=&quot;box-sizing: border-box; color: #ba2121; font-style: italic;&quot;&gt;где стоимость функции медленно меняется, а где быстро. На данном рисунке, мы имеем линейный цветовую карту: &lt;/span&gt;
&lt;span class=&quot;sd&quot; style=&quot;box-sizing: border-box; color: #ba2121; font-style: italic;&quot;&gt;черный дорого вычислять(&amp;gt;300), серый бесплатен (сразу 0) и белый дешевле максимума(0&amp;lt;x&amp;lt;300).&lt;/span&gt;
&lt;span class=&quot;sd&quot; style=&quot;box-sizing: border-box; color: #ba2121; font-style: italic;&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;


&lt;span class=&quot;kn&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot; style=&quot;box-sizing: border-box; color: blue; font-weight: bold;&quot;&gt;PIL&lt;/span&gt; &lt;span class=&quot;kn&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;Image&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;ImageDraw&lt;/span&gt;

&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;1000&lt;/span&gt;

&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;image&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;Image&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #ba2121;&quot;&gt;&quot;RGBA&quot;&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;pixels&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;calc_pure_python&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;desired_width&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;max_iterations&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;#print output&lt;/span&gt;

&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;ow&quot; style=&quot;box-sizing: border-box; color: #aa22ff; font-weight: bold;&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot; style=&quot;box-sizing: border-box; color: #aa22ff; font-weight: bold;&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;height&lt;/span&gt; == 0:
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0&lt;/span&gt;
        
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;125&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;125&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;125&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
        
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;pixels&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;color&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;1&lt;/span&gt;
    
&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;show&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;output_wrapper&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box; position: relative; z-index: 1;&quot;&gt;
&lt;div class=&quot;output&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;output_area&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; padding: 0px; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt&quot; style=&quot;box-sizing: border-box; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0px 0.4em; text-align: right;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;output_subarea output_stream output_stdout output_text&quot; style=&quot;-webkit-box-flex: 1; box-sizing: border-box; line-height: 1.21429em; max-width: calc(100% - 14ex); overflow-x: auto; padding: 0.4em;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; border-top-left-radius: 0px; border-top-right-radius: 0px; border: 0px; box-sizing: border-box; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; vertical-align: baseline; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;heapy after creating y and x lists of floats
Partition of a set of 2125520 objects. Total size = 96975808 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0 2000001  94 64000032  66  64000032  66 complex
     1   1228   0 16507040  17  80507072  83 list
     2  56303   3  4946792   5  85453864  88 str
     3  28739   1  2462944   3  87916808  91 tuple
     4   1701   0  1640952   2  89557760  92 dict (no owner)
     5    420   0  1240416   1  90798176  94 dict of module
     6   7150   0   915200   1  91713376  95 types.CodeType
     7   7023   0   842760   1  92556136  95 function
     8    854   0   769040   1  93325176  96 type
     9    854   0   684560   1  94009736  97 dict of type
&amp;lt;540 more rows. Type e.g. &#39;_.more&#39; to view.&amp;gt;

Length of x: 1000
Total elements: 1000000
calculate_z_serial_purepython took 6.69428300858 seconds
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing text_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;text_cell_render border-box-sizing rendered_html&quot; style=&quot;border-style: none; box-sizing: border-box; outline: none; overflow-x: auto; padding: 0.5em 0.5em 0.5em 0.4em; resize: none; width: inherit;&quot;&gt;
&lt;h2 id=&quot;Приступим-к-профайлингу&quot; style=&quot;box-sizing: border-box; color: inherit; font-family: inherit; font-size: 22px; line-height: 1; margin: 0.636em 0px 0px;&quot;&gt;
Приступим к профайлингу&lt;a class=&quot;anchor-link&quot; href=&quot;file:///Users/tehno/Downloads/Untitled0.html#%D0%9F%D1%80%D0%B8%D1%81%D1%82%D1%83%D0%BF%D0%B8%D0%BC-%D0%BA-%D0%BF%D1%80%D0%BE%D1%84%D0%B0%D0%B9%D0%BB%D0%B8%D0%BD%D0%B3%D1%83&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #337ab7; padding: 0px 20px; text-decoration: none; visibility: hidden;&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing text_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;text_cell_render border-box-sizing rendered_html&quot; style=&quot;border-style: none; box-sizing: border-box; outline: none; overflow-x: auto; padding: 0.5em 0.5em 0.5em 0.4em; resize: none; width: inherit;&quot;&gt;
&lt;h3 id=&quot;Производительность&quot; style=&quot;box-sizing: border-box; color: inherit; font-family: inherit; font-size: 18px; line-height: 1; margin: 0.777em 0px 0px;&quot;&gt;
Производительность&lt;a class=&quot;anchor-link&quot; href=&quot;file:///Users/tehno/Downloads/Untitled0.html#%D0%9F%D1%80%D0%BE%D0%B8%D0%B7%D0%B2%D0%BE%D0%B4%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D1%8C&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #337ab7; padding: 0px 20px; text-decoration: none; visibility: hidden;&quot;&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing code_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;input&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
In&amp;nbsp;[7]:&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;input_area&quot; style=&quot;background-color: #f7f7f7; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(207, 207, 207); box-sizing: border-box; line-height: 1.21429em;&quot;&gt;
&lt;div class=&quot; highlight hl-ipython2&quot; style=&quot;background-color: transparent; background-position: initial initial; background-repeat: initial initial; border: none; box-sizing: border-box; margin: 0.4em; padding: 0px;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: none; box-sizing: border-box; color: #333333; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;calc_pure_python&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;desired_width&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;max_iterations&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;output_wrapper&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box; position: relative; z-index: 1;&quot;&gt;
&lt;div class=&quot;output&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;output_area&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; padding: 0px; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt&quot; style=&quot;box-sizing: border-box; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0px 0.4em; text-align: right;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;output_subarea output_stream output_stdout output_text&quot; style=&quot;-webkit-box-flex: 1; box-sizing: border-box; line-height: 1.21429em; max-width: calc(100% - 14ex); overflow-x: auto; padding: 0.4em;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; border-top-left-radius: 0px; border-top-right-radius: 0px; border: 0px; box-sizing: border-box; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; vertical-align: baseline; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;heapy after creating y and x lists of floats
Partition of a set of 2227318 objects. Total size = 107656256 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0 2000001  90 64000032  59  64000032  59 complex
     1   1191   0 24628920  23  88628952  82 list
     2  57069   3  5003896   5  93632848  87 str
     3  29259   1  2510848   2  96143696  89 tuple
     4 103191   5  2476584   2  98620280  92 int
     5   1711   0  1656808   2 100277088  93 dict (no owner)
     6    427   0  1252360   1 101529448  94 dict of module
     7   7263   0   929664   1 102459112  95 types.CodeType
     8   7129   0   855480   1 103314592  96 function
     9    854   0   769040   1 104083632  97 type
&amp;lt;546 more rows. Type e.g. &#39;_.more&#39; to view.&amp;gt;

Length of x: 1000
Total elements: 1000000
calculate_z_serial_purepython took 6.71625804901 seconds
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing code_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;input&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
In&amp;nbsp;[41]:&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;input_area&quot; style=&quot;background-color: #f7f7f7; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(207, 207, 207); box-sizing: border-box; line-height: 1.21429em;&quot;&gt;
&lt;div class=&quot; highlight hl-ipython2&quot; style=&quot;background-color: transparent; background-position: initial initial; background-repeat: initial initial; border: none; box-sizing: border-box; margin: 0.4em; padding: 0px;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: none; box-sizing: border-box; color: #333333; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;#  in IPython (probably because you’re using %run)&lt;/span&gt;
&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;timeit&lt;/span&gt; calc_pure_python(desired_width=1000, max_iterations=300)
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;output_wrapper&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box; position: relative; z-index: 1;&quot;&gt;
&lt;div class=&quot;output&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;output_area&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; padding: 0px; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt&quot; style=&quot;box-sizing: border-box; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0px 0.4em; text-align: right;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;output_subarea output_stream output_stdout output_text&quot; style=&quot;-webkit-box-flex: 1; box-sizing: border-box; line-height: 1.21429em; max-width: calc(100% - 14ex); overflow-x: auto; padding: 0.4em;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; border-top-left-radius: 0px; border-top-right-radius: 0px; border: 0px; box-sizing: border-box; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; vertical-align: baseline; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;Length of x: 1000
Total elements: 1000000
@timefn:calculate_z_serial_purepython took 6.66308379173 seconds
calculate_z_serial_purepython took 6.66349101067 seconds
Length of x: 1000
Total elements: 1000000
@timefn:calculate_z_serial_purepython took 6.68743419647 seconds
calculate_z_serial_purepython took 6.68781113625 seconds
Length of x: 1000
Total elements: 1000000
@timefn:calculate_z_serial_purepython took 6.79939007759 seconds
calculate_z_serial_purepython took 6.79975104332 seconds
Length of x: 1000
Total elements: 1000000
@timefn:calculate_z_serial_purepython took 6.83708381653 seconds
calculate_z_serial_purepython took 6.83745718002 seconds
1 loops, best of 3: 7.24 s per loop
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing code_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;input&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
In&amp;nbsp;[43]:&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;input_area&quot; style=&quot;background-color: #f7f7f7; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(207, 207, 207); box-sizing: border-box; line-height: 1.21429em;&quot;&gt;
&lt;div class=&quot; highlight hl-ipython2&quot; style=&quot;background-color: transparent; background-position: initial initial; background-repeat: initial initial; border: none; box-sizing: border-box; margin: 0.4em; padding: 0px;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: none; box-sizing: border-box; color: #333333; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;#  cProfile&lt;/span&gt;
&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;#  this time includes the overhead of using cProfile&lt;/span&gt;
&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;prun&lt;/span&gt; calc_pure_python(desired_width=1000, max_iterations=300)
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;output_wrapper&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box; position: relative; z-index: 1;&quot;&gt;
&lt;div class=&quot;output&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;output_area&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; padding: 0px; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt&quot; style=&quot;box-sizing: border-box; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0px 0.4em; text-align: right;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;output_subarea output_stream output_stdout output_text&quot; style=&quot;-webkit-box-flex: 1; box-sizing: border-box; line-height: 1.21429em; max-width: calc(100% - 14ex); overflow-x: auto; padding: 0.4em;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; border-top-left-radius: 0px; border-top-right-radius: 0px; border: 0px; box-sizing: border-box; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; vertical-align: baseline; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;Length of x: 1000
Total elements: 1000000
@timefn:calculate_z_serial_purepython took 9.6828110218 seconds
calculate_z_serial_purepython took 9.68326115608 seconds
 &lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing code_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;input&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
In&amp;nbsp;[21]:&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;input_area&quot; style=&quot;background-color: #f7f7f7; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(207, 207, 207); box-sizing: border-box; line-height: 1.21429em;&quot;&gt;
&lt;div class=&quot; highlight hl-ipython2&quot; style=&quot;background-color: transparent; background-position: initial initial; background-repeat: initial initial; border: none; box-sizing: border-box; margin: 0.4em; padding: 0px;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: none; box-sizing: border-box; color: #333333; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;#  line_profiler&lt;/span&gt;
&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;lprun&lt;/span&gt; -f calculate_z_serial_purepython calc_pure_python(desired_width=1000, max_iterations=300)
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;output_wrapper&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box; position: relative; z-index: 1;&quot;&gt;
&lt;div class=&quot;output&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;output_area&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; padding: 0px; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt&quot; style=&quot;box-sizing: border-box; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0px 0.4em; text-align: right;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;output_subarea output_stream output_stderr output_text&quot; style=&quot;-webkit-box-flex: 1; background-color: #ffdddd; box-sizing: border-box; line-height: 1.21429em; max-width: calc(100% - 14ex); overflow-x: auto; padding: 0.4em;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; border-top-left-radius: 0px; border-top-right-radius: 0px; border: 0px; box-sizing: border-box; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; vertical-align: baseline; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;UsageError: option -l not recognized ( allowed: &quot;rsf:m:D:T:&quot; )&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing code_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;input&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
In&amp;nbsp;[1]:&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;input_area&quot; style=&quot;background-color: #f7f7f7; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(207, 207, 207); box-sizing: border-box; line-height: 1.21429em;&quot;&gt;
&lt;div class=&quot; highlight hl-ipython2&quot; style=&quot;background-color: transparent; background-position: initial initial; background-repeat: initial initial; border: none; box-sizing: border-box; margin: 0.4em; padding: 0px;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: none; box-sizing: border-box; color: #333333; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0j&lt;/span&gt;
&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;timeit&lt;/span&gt; abs(z) &amp;lt; 2

&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;maxiter&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;300&lt;/span&gt;
&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;timeit&lt;/span&gt; n &amp;lt; maxiter

&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;# Тут можно порассуждать, о правильности порядка abs(z) &amp;lt; 2 and n &amp;lt; maxiter или n &amp;lt; maxiter and abs(z) &amp;lt; 2&lt;/span&gt;
&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;# мы знаем, что только 10% точек доходит до 300-го вычисления и при этом проверка n &amp;lt; maxiter в 2 раза дешевле&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;output_wrapper&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box; position: relative; z-index: 1;&quot;&gt;
&lt;div class=&quot;output&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;output_area&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; padding: 0px; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt&quot; style=&quot;box-sizing: border-box; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0px 0.4em; text-align: right;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;output_subarea output_stream output_stdout output_text&quot; style=&quot;-webkit-box-flex: 1; box-sizing: border-box; line-height: 1.21429em; max-width: calc(100% - 14ex); overflow-x: auto; padding: 0.4em;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; border-top-left-radius: 0px; border-top-right-radius: 0px; border: 0px; box-sizing: border-box; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; vertical-align: baseline; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;The slowest run took 66.17 times longer than the fastest. This could mean that an intermediate result is being cached 
10000000 loops, best of 3: 93.7 ns per loop
10000000 loops, best of 3: 44 ns per loop
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing text_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;text_cell_render border-box-sizing rendered_html&quot; style=&quot;border-style: none; box-sizing: border-box; outline: none; overflow-x: auto; padding: 0.5em 0.5em 0.5em 0.4em; resize: none; width: inherit;&quot;&gt;
&lt;h3 id=&quot;Память&quot; style=&quot;box-sizing: border-box; color: inherit; font-family: inherit; font-size: 18px; line-height: 1; margin: 0.777em 0px 0px;&quot;&gt;
Память&lt;a class=&quot;anchor-link&quot; href=&quot;file:///Users/tehno/Downloads/Untitled0.html#%D0%9F%D0%B0%D0%BC%D1%8F%D1%82%D1%8C&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #337ab7; padding: 0px 20px; text-decoration: none; visibility: hidden;&quot;&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing text_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;text_cell_render border-box-sizing rendered_html&quot; style=&quot;border-style: none; box-sizing: border-box; outline: none; overflow-x: auto; padding: 0.5em 0.5em 0.5em 0.4em; resize: none; width: inherit;&quot;&gt;
&lt;div style=&quot;box-sizing: border-box;&quot;&gt;
Основной закон этого мира - это &quot;Закон сохранения энергии&quot; Это он мешает создать нам вечный двигтаель и он же создает проблему перетягивания каната: память - скорость&lt;/div&gt;
&lt;div style=&quot;box-sizing: border-box; margin-top: 1em;&quot;&gt;
Понимание использования памяти вашего кода позволяет вам задать себе два вопроса: • Можем ли мы использовать меньше памяти, переписав эту функцию, чтобы работать более эффективно? • Можем ли мы использовать больше оперативной памяти и сохранить ресурсы процессора за счет кэширования?&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing code_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;input&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
In&amp;nbsp;[14]:&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;input_area&quot; style=&quot;background-color: #f7f7f7; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(207, 207, 207); box-sizing: border-box; line-height: 1.21429em;&quot;&gt;
&lt;div class=&quot; highlight hl-ipython2&quot; style=&quot;background-color: transparent; background-position: initial initial; background-repeat: initial initial; border: none; box-sizing: border-box; margin: 0.4em; padding: 0px;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: none; box-sizing: border-box; color: #333333; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;&lt;span class=&quot;kn&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot; style=&quot;box-sizing: border-box; color: blue; font-weight: bold;&quot;&gt;calc_pure_python&lt;/span&gt; &lt;span class=&quot;kn&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;calc_pure_python2&lt;/span&gt;
&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;#  NOTE: %mprun can only be used on functions defined in physical files, and not in the IPython environment.&lt;/span&gt;
&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;mprun&lt;/span&gt; -f calc_pure_python calc_pure_python2(desired_width=10, max_iterations=300)
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;output_wrapper&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box; position: relative; z-index: 1;&quot;&gt;
&lt;div class=&quot;output&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;output_area&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; padding: 0px; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt&quot; style=&quot;box-sizing: border-box; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0px 0.4em; text-align: right;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;output_subarea output_stream output_stdout output_text&quot; style=&quot;-webkit-box-flex: 1; box-sizing: border-box; line-height: 1.21429em; max-width: calc(100% - 14ex); overflow-x: auto; padding: 0.4em;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; border-top-left-radius: 0px; border-top-right-radius: 0px; border: 0px; box-sizing: border-box; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; vertical-align: baseline; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;Length of x: 11
Total elements: 121
calculate_z_serial_purepython took 0.00995206832886 seconds
(&#39;&#39;,)
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing code_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;input&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
In&amp;nbsp;[15]:&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;input_area&quot; style=&quot;background-color: #f7f7f7; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(207, 207, 207); box-sizing: border-box; line-height: 1.21429em;&quot;&gt;
&lt;div class=&quot; highlight hl-ipython2&quot; style=&quot;background-color: transparent; background-position: initial initial; background-repeat: initial initial; border: none; box-sizing: border-box; margin: 0.4em; padding: 0px;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: none; box-sizing: border-box; color: #333333; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;&lt;span class=&quot;kn&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot; style=&quot;box-sizing: border-box; color: blue; font-weight: bold;&quot;&gt;os&lt;/span&gt;
&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;getcwd&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;())&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;output_wrapper&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box; position: relative; z-index: 1;&quot;&gt;
&lt;div class=&quot;output&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;output_area&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; padding: 0px; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt output_prompt&quot; style=&quot;box-sizing: border-box; color: darkred; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
Out[15]:&lt;/div&gt;
&lt;div class=&quot;output_text output_subarea output_execute_result&quot; style=&quot;-webkit-box-flex: 1; box-sizing: border-box; line-height: 1.21429em; max-width: calc(100% - 14ex); overflow-x: auto; padding: 0.4em;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; border-top-left-radius: 0px; border-top-right-radius: 0px; border: 0px; box-sizing: border-box; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; vertical-align: baseline; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;&#39;/Users&#39;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing code_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;input&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
In&amp;nbsp;[16]:&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;input_area&quot; style=&quot;background-color: #f7f7f7; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(207, 207, 207); box-sizing: border-box; line-height: 1.21429em;&quot;&gt;
&lt;div class=&quot; highlight hl-ipython2&quot; style=&quot;background-color: transparent; background-position: initial initial; background-repeat: initial initial; border: none; box-sizing: border-box; margin: 0.4em; padding: 0px;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: none; box-sizing: border-box; color: #333333; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0j&lt;/span&gt;
&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;memit&lt;/span&gt; abs(z) &amp;lt; 2

&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;maxiter&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;300&lt;/span&gt;
&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;memit&lt;/span&gt; n &amp;lt; maxiter
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;output_wrapper&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box; position: relative; z-index: 1;&quot;&gt;
&lt;div class=&quot;output&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;output_area&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; padding: 0px; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt&quot; style=&quot;box-sizing: border-box; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0px 0.4em; text-align: right;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;output_subarea output_stream output_stdout output_text&quot; style=&quot;-webkit-box-flex: 1; box-sizing: border-box; line-height: 1.21429em; max-width: calc(100% - 14ex); overflow-x: auto; padding: 0.4em;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; border-top-left-radius: 0px; border-top-right-radius: 0px; border: 0px; box-sizing: border-box; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; vertical-align: baseline; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;peak memory: 22.28 MiB, increment: 0.99 MiB
peak memory: 22.34 MiB, increment: 0.05 MiB
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing text_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;text_cell_render border-box-sizing rendered_html&quot; style=&quot;border-style: none; box-sizing: border-box; outline: none; overflow-x: auto; padding: 0.5em 0.5em 0.5em 0.4em; resize: none; width: inherit;&quot;&gt;
&lt;h4 id=&quot;CherryPy-server&quot; style=&quot;box-sizing: border-box; color: inherit; font-family: inherit; line-height: 1; margin: 1em 0px 0px;&quot;&gt;
CherryPy server&lt;a class=&quot;anchor-link&quot; href=&quot;file:///Users/tehno/Downloads/Untitled0.html#CherryPy-server&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #337ab7; padding: 0px 20px; text-decoration: none; visibility: hidden;&quot;&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing code_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;input&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
In&amp;nbsp;[8]:&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;input_area&quot; style=&quot;background-color: #f7f7f7; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(207, 207, 207); box-sizing: border-box; line-height: 1.21429em;&quot;&gt;
&lt;div class=&quot; highlight hl-ipython2&quot; style=&quot;background-color: transparent; background-position: initial initial; background-repeat: initial initial; border: none; box-sizing: border-box; margin: 0.4em; padding: 0px;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: none; box-sizing: border-box; color: #333333; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot; style=&quot;box-sizing: border-box; color: blue;&quot;&gt;launch_memory_usage_server&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;8080&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;):&lt;/span&gt; 
    &lt;span class=&quot;kn&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot; style=&quot;box-sizing: border-box; color: blue; font-weight: bold;&quot;&gt;cherrypy&lt;/span&gt;
    &lt;span class=&quot;kn&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot; style=&quot;box-sizing: border-box; color: blue; font-weight: bold;&quot;&gt;dowser&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;cherrypy&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;mount&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;dowser&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;Root&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;cherrypy&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;({&lt;/span&gt;
        &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #ba2121;&quot;&gt;&#39;environment&#39;&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #ba2121;&quot;&gt;&#39;embedded&#39;&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #ba2121;&quot;&gt;&#39;server.socket_port&#39;&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;port&lt;/span&gt;
    &lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;})&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;cherrypy&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;engine&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing code_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;input&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
In&amp;nbsp;[13]:&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;input_area&quot; style=&quot;background-color: #f7f7f7; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(207, 207, 207); box-sizing: border-box; line-height: 1.21429em;&quot;&gt;
&lt;div class=&quot; highlight hl-ipython2&quot; style=&quot;background-color: transparent; background-position: initial initial; background-repeat: initial initial; border: none; box-sizing: border-box; margin: 0.4em; padding: 0px;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: none; box-sizing: border-box; color: #333333; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;&lt;span class=&quot;kn&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot; style=&quot;box-sizing: border-box; color: blue; font-weight: bold;&quot;&gt;time&lt;/span&gt;

&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x2&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y1&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y2&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;1.8&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;1.8&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;1.8&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;1.8&lt;/span&gt;
&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;c_real&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;c_imag&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;0.62772&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;-.&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;42193&lt;/span&gt;

&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot; style=&quot;box-sizing: border-box; color: blue;&quot;&gt;calc_pure_python_cherry&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;desired_width&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;max_iterations&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;):&lt;/span&gt; 
    &lt;span class=&quot;sd&quot; style=&quot;box-sizing: border-box; color: #ba2121; font-style: italic;&quot;&gt;&quot;&quot;&quot;Create a list of complex coordinates (zs) and complex parameters (cs), build Julia set, and display&quot;&quot;&quot;&lt;/span&gt;
    
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x_step&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x2&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;desired_width&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y_step&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y1&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y2&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;desired_width&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;[]&lt;/span&gt;
    
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;ycoord&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y2&lt;/span&gt;
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;ycoord&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y1&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;ycoord&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;ycoord&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y_step&lt;/span&gt;
    
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;xcoord&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x1&lt;/span&gt;
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;xcoord&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x2&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;xcoord&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;xcoord&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x_step&lt;/span&gt;

        
    &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;# Build a list of coordinates and the initial condition for each cell.&lt;/span&gt;
    &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;# Note that our initial condition is a constant and could easily be removed; # we use it to simulate a real-world scenario with several inputs to&lt;/span&gt;
    &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;# our function.&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;zs&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;cs&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;[]&lt;/span&gt;
    
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;ycoord&lt;/span&gt; &lt;span class=&quot;ow&quot; style=&quot;box-sizing: border-box; color: #aa22ff; font-weight: bold;&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;xcoord&lt;/span&gt; &lt;span class=&quot;ow&quot; style=&quot;box-sizing: border-box; color: #aa22ff; font-weight: bold;&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;zs&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;complex&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;xcoord&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;ycoord&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;))&lt;/span&gt;
            &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;cs&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;complex&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;c_real&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;c_imag&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;))&lt;/span&gt;

    &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;#  тут стартуем сервер&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;launch_memory_usage_server&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;()&lt;/span&gt;
            
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;start_time&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;calculate_z_serial_purepython&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;max_iterations&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;zs&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;cs&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;end_time&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;secs&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;end_time&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;start_time&lt;/span&gt;

    &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #408080; font-style: italic;&quot;&gt;#  делаем так, чтобы сервер не потух&lt;/span&gt;
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #ba2121;&quot;&gt;&quot;now waiting...&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;bp&quot; style=&quot;box-sizing: border-box; color: green;&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;output&lt;/span&gt;
&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;calc_pure_python_cherry&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;desired_width&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;max_iterations&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;output_wrapper&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box; position: relative; z-index: 1;&quot;&gt;
&lt;div class=&quot;output&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;output_area&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; padding: 0px; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt&quot; style=&quot;box-sizing: border-box; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0px 0.4em; text-align: right;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;output_subarea output_stream output_stderr output_text&quot; style=&quot;-webkit-box-flex: 1; background-color: #ffdddd; box-sizing: border-box; line-height: 1.21429em; max-width: calc(100% - 14ex); overflow-x: auto; padding: 0.4em;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; border-top-left-radius: 0px; border-top-right-radius: 0px; border: 0px; box-sizing: border-box; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; vertical-align: baseline; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;INFO:cherrypy.error:[26/Apr/2015:22:31:29] ENGINE Bus STARTING
INFO:cherrypy.error:[26/Apr/2015:22:31:29] ENGINE Monitor thread &#39;_TimeoutMonitor&#39; already started.
INFO:cherrypy.error:[26/Apr/2015:22:31:29] ENGINE Already serving on http://127.0.0.1:8080
INFO:cherrypy.error:[26/Apr/2015:22:31:29] ENGINE Bus STARTED
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;output_area&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; padding: 0px; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt&quot; style=&quot;box-sizing: border-box; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0px 0.4em; text-align: right;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;output_subarea output_text output_error&quot; style=&quot;-webkit-box-flex: 1; box-sizing: border-box; line-height: 1.21429em; max-width: calc(100% - 14ex); overflow-x: auto; padding: 0.4em;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; border-top-left-radius: 0px; border-top-right-radius: 0px; border: 0px; box-sizing: border-box; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; vertical-align: baseline; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;&lt;span class=&quot;ansired&quot; style=&quot;box-sizing: border-box; color: darkred;&quot;&gt;---------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;ansired&quot; style=&quot;box-sizing: border-box; color: darkred;&quot;&gt;KeyboardInterrupt&lt;/span&gt;                         Traceback (most recent call last)
&lt;span class=&quot;ansigreen&quot; style=&quot;box-sizing: border-box; color: darkgreen;&quot;&gt;&amp;lt;ipython-input-13-8b6b3a917280&amp;gt;&lt;/span&gt; in &lt;span class=&quot;ansicyan&quot; style=&quot;box-sizing: border-box; color: steelblue;&quot;&gt;&amp;lt;module&amp;gt;&lt;/span&gt;&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;ansigreen&quot; style=&quot;box-sizing: border-box; color: darkgreen;&quot;&gt;     48&lt;/span&gt; &lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;ansigreen&quot; style=&quot;box-sizing: border-box; color: darkgreen;&quot;&gt;     49&lt;/span&gt;     &lt;span class=&quot;ansigreen&quot; style=&quot;box-sizing: border-box; color: darkgreen;&quot;&gt;return&lt;/span&gt; output&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;ansigreen&quot; style=&quot;box-sizing: border-box; color: darkgreen;&quot;&gt;---&amp;gt; 50&lt;/span&gt;&lt;span class=&quot;ansired&quot; style=&quot;box-sizing: border-box; color: darkred;&quot;&gt; &lt;/span&gt;calc_pure_python_cherry&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;(&lt;/span&gt;desired_width&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;ansicyan&quot; style=&quot;box-sizing: border-box; color: steelblue;&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;,&lt;/span&gt; max_iterations&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;ansicyan&quot; style=&quot;box-sizing: border-box; color: steelblue;&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;&lt;/span&gt;

&lt;span class=&quot;ansigreen&quot; style=&quot;box-sizing: border-box; color: darkgreen;&quot;&gt;&amp;lt;ipython-input-13-8b6b3a917280&amp;gt;&lt;/span&gt; in &lt;span class=&quot;ansicyan&quot; style=&quot;box-sizing: border-box; color: steelblue;&quot;&gt;calc_pure_python_cherry&lt;/span&gt;&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;(desired_width, max_iterations)&lt;/span&gt;
&lt;span class=&quot;ansigreen&quot; style=&quot;box-sizing: border-box; color: darkgreen;&quot;&gt;     38&lt;/span&gt; &lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;ansigreen&quot; style=&quot;box-sizing: border-box; color: darkgreen;&quot;&gt;     39&lt;/span&gt;     start_time &lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;=&lt;/span&gt; time&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;.&lt;/span&gt;time&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;ansigreen&quot; style=&quot;box-sizing: border-box; color: darkgreen;&quot;&gt;---&amp;gt; 40&lt;/span&gt;&lt;span class=&quot;ansired&quot; style=&quot;box-sizing: border-box; color: darkred;&quot;&gt;     &lt;/span&gt;output &lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;=&lt;/span&gt; calculate_z_serial_purepython&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;(&lt;/span&gt;max_iterations&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;,&lt;/span&gt; zs&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;,&lt;/span&gt; cs&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;ansigreen&quot; style=&quot;box-sizing: border-box; color: darkgreen;&quot;&gt;     41&lt;/span&gt;     end_time &lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;=&lt;/span&gt; time&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;.&lt;/span&gt;time&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;ansigreen&quot; style=&quot;box-sizing: border-box; color: darkgreen;&quot;&gt;     42&lt;/span&gt;     secs &lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;=&lt;/span&gt; end_time &lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;-&lt;/span&gt; start_time&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;&lt;/span&gt;

&lt;span class=&quot;ansigreen&quot; style=&quot;box-sizing: border-box; color: darkgreen;&quot;&gt;&amp;lt;ipython-input-5-0ee9a7f0d062&amp;gt;&lt;/span&gt; in &lt;span class=&quot;ansicyan&quot; style=&quot;box-sizing: border-box; color: steelblue;&quot;&gt;calculate_z_serial_purepython&lt;/span&gt;&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;(maxiter, zs, cs)&lt;/span&gt;
&lt;span class=&quot;ansigreen&quot; style=&quot;box-sizing: border-box; color: darkgreen;&quot;&gt;     11&lt;/span&gt;         &lt;span class=&quot;ansigreen&quot; style=&quot;box-sizing: border-box; color: darkgreen;&quot;&gt;while&lt;/span&gt; abs&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;(&lt;/span&gt;z&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;ansicyan&quot; style=&quot;box-sizing: border-box; color: steelblue;&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;ansigreen&quot; style=&quot;box-sizing: border-box; color: darkgreen;&quot;&gt;and&lt;/span&gt; n &lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;&amp;lt;&lt;/span&gt; maxiter&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;ansigreen&quot; style=&quot;box-sizing: border-box; color: darkgreen;&quot;&gt;     12&lt;/span&gt;             z&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;=&lt;/span&gt;z&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;*&lt;/span&gt;z&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;+&lt;/span&gt;c&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;ansigreen&quot; style=&quot;box-sizing: border-box; color: darkgreen;&quot;&gt;---&amp;gt; 13&lt;/span&gt;&lt;span class=&quot;ansired&quot; style=&quot;box-sizing: border-box; color: darkred;&quot;&gt;             &lt;/span&gt;n&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;+=&lt;/span&gt;&lt;span class=&quot;ansicyan&quot; style=&quot;box-sizing: border-box; color: steelblue;&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;ansigreen&quot; style=&quot;box-sizing: border-box; color: darkgreen;&quot;&gt;     14&lt;/span&gt;         output&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;=&lt;/span&gt; n&lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;ansigreen&quot; style=&quot;box-sizing: border-box; color: darkgreen;&quot;&gt;     15&lt;/span&gt; &lt;span class=&quot;ansiblue&quot; style=&quot;box-sizing: border-box; color: darkblue;&quot;&gt;&lt;/span&gt;

&lt;span class=&quot;ansired&quot; style=&quot;box-sizing: border-box; color: darkred;&quot;&gt;KeyboardInterrupt&lt;/span&gt;: &lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing text_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;text_cell_render border-box-sizing rendered_html&quot; style=&quot;border-style: none; box-sizing: border-box; outline: none; overflow-x: auto; padding: 0.5em 0.5em 0.5em 0.4em; resize: none; width: inherit;&quot;&gt;
&lt;h3 id=&quot;Byte-Code&quot; style=&quot;box-sizing: border-box; color: inherit; font-family: inherit; font-size: 18px; line-height: 1; margin: 0.777em 0px 0px;&quot;&gt;
Byte Code&lt;a class=&quot;anchor-link&quot; href=&quot;file:///Users/tehno/Downloads/Untitled0.html#Byte-Code&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #337ab7; padding: 0px 20px; text-decoration: none; visibility: hidden;&quot;&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing text_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;text_cell_render border-box-sizing rendered_html&quot; style=&quot;border-style: none; box-sizing: border-box; outline: none; overflow-x: auto; padding: 0.5em 0.5em 0.5em 0.4em; resize: none; width: inherit;&quot;&gt;
&lt;div style=&quot;box-sizing: border-box;&quot;&gt;
Первый столбец содержит номера строк исполнения.Вторая колонка содержит символы - &amp;gt;&amp;gt;; это направления для точек перехода, в других местах в коде.Третий столбец адрес операции вместе с именем операции.Четвертый столбец содержит параметры для работы.Пятая колонна содержит аннотации, чтобы помочь выстроить байт-код с оригинальными параметрами Python.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing code_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;input&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
In&amp;nbsp;[16]:&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;input_area&quot; style=&quot;background-color: #f7f7f7; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(207, 207, 207); box-sizing: border-box; line-height: 1.21429em;&quot;&gt;
&lt;div class=&quot; highlight hl-ipython2&quot; style=&quot;background-color: transparent; background-position: initial initial; background-repeat: initial initial; border: none; box-sizing: border-box; margin: 0.4em; padding: 0px;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: none; box-sizing: border-box; color: #333333; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;&lt;span class=&quot;kn&quot; style=&quot;box-sizing: border-box; color: green; font-weight: bold;&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot; style=&quot;box-sizing: border-box; color: blue; font-weight: bold;&quot;&gt;dis&lt;/span&gt;
&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;dis&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: #666666;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;dis&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot; style=&quot;box-sizing: border-box;&quot;&gt;calc_pure_python&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;output_wrapper&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box; position: relative; z-index: 1;&quot;&gt;
&lt;div class=&quot;output&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;output_area&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; box-sizing: border-box; display: -webkit-box; padding: 0px; page-break-inside: avoid;&quot;&gt;
&lt;div class=&quot;prompt&quot; style=&quot;box-sizing: border-box; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0px 0.4em; text-align: right;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;output_subarea output_stream output_stdout output_text&quot; style=&quot;-webkit-box-flex: 1; box-sizing: border-box; line-height: 1.21429em; max-width: calc(100% - 14ex); overflow-x: auto; padding: 0.4em;&quot;&gt;
&lt;pre style=&quot;background-color: transparent; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; border-top-left-radius: 0px; border-top-right-radius: 0px; border: 0px; box-sizing: border-box; font-size: inherit; line-height: inherit; overflow: auto; padding: 0px; vertical-align: baseline; white-space: pre-wrap; word-break: break-all; word-wrap: break-word;&quot;&gt;  9           0 LOAD_GLOBAL              0 (float)
              3 LOAD_GLOBAL              1 (x2)
              6 LOAD_GLOBAL              2 (x1)
              9 BINARY_SUBTRACT     
             10 CALL_FUNCTION            1
             13 LOAD_GLOBAL              0 (float)
             16 LOAD_FAST                0 (desired_width)
             19 CALL_FUNCTION            1
             22 BINARY_DIVIDE       
             23 STORE_FAST               2 (x_step)

 10          26 LOAD_GLOBAL              0 (float)
             29 LOAD_GLOBAL              3 (y1)
             32 LOAD_GLOBAL              4 (y2)
             35 BINARY_SUBTRACT     
             36 CALL_FUNCTION            1
             39 LOAD_GLOBAL              0 (float)
             42 LOAD_FAST                0 (desired_width)
             45 CALL_FUNCTION            1
             48 BINARY_DIVIDE       
             49 STORE_FAST               3 (y_step)

 11          52 BUILD_LIST               0
             55 STORE_FAST               4 (x)

 12          58 BUILD_LIST               0
             61 STORE_FAST               5 (y)

 13          64 LOAD_GLOBAL              4 (y2)
             67 STORE_FAST               6 (ycoord)

 14          70 SETUP_LOOP              39 (to 112)
        &amp;gt;&amp;gt;   73 LOAD_FAST                6 (ycoord)
             76 LOAD_GLOBAL              3 (y1)
             79 COMPARE_OP               4 (&amp;gt;)
             82 POP_JUMP_IF_FALSE      111

 15          85 LOAD_FAST                5 (y)
             88 LOAD_ATTR                5 (append)
             91 LOAD_FAST                6 (ycoord)
             94 CALL_FUNCTION            1
             97 POP_TOP             

 16          98 LOAD_FAST                6 (ycoord)
            101 LOAD_FAST                3 (y_step)
            104 INPLACE_ADD         
            105 STORE_FAST               6 (ycoord)
            108 JUMP_ABSOLUTE           73
        &amp;gt;&amp;gt;  111 POP_BLOCK           

 17     &amp;gt;&amp;gt;  112 LOAD_GLOBAL              2 (x1)
            115 STORE_FAST               7 (xcoord)

 18         118 SETUP_LOOP              39 (to 160)
        &amp;gt;&amp;gt;  121 LOAD_FAST                7 (xcoord)
            124 LOAD_GLOBAL              1 (x2)
            127 COMPARE_OP               0 (&amp;lt;)
            130 POP_JUMP_IF_FALSE      159

 19         133 LOAD_FAST                4 (x)
            136 LOAD_ATTR                5 (append)
            139 LOAD_FAST                7 (xcoord)
            142 CALL_FUNCTION            1
            145 POP_TOP             

 20         146 LOAD_FAST                7 (xcoord)
            149 LOAD_FAST                2 (x_step)
            152 INPLACE_ADD         
            153 STORE_FAST               7 (xcoord)
            156 JUMP_ABSOLUTE          121
        &amp;gt;&amp;gt;  159 POP_BLOCK           

 23     &amp;gt;&amp;gt;  160 LOAD_CONST               1 (-1)
            163 LOAD_CONST               2 ((&#39;hpy&#39;,))
            166 IMPORT_NAME              6 (guppy)
            169 IMPORT_FROM              7 (hpy)
            172 STORE_FAST               8 (hpy)
            175 POP_TOP             

 24         176 LOAD_FAST                8 (hpy)
            179 CALL_FUNCTION            0
            182 STORE_FAST               9 (hp)

 25         185 LOAD_CONST               3 (&#39;heapy after creating y and x lists of floats&#39;)
            188 PRINT_ITEM          
            189 PRINT_NEWLINE       

 26         190 LOAD_FAST                9 (hp)
            193 LOAD_ATTR                8 (heap)
            196 CALL_FUNCTION            0
            199 STORE_FAST              10 (h)

 27         202 LOAD_FAST               10 (h)
            205 PRINT_ITEM          
            206 PRINT_NEWLINE       

 34         207 BUILD_LIST               0
            210 STORE_FAST              11 (zs)

 35         213 BUILD_LIST               0
            216 STORE_FAST              12 (cs)

 37         219 SETUP_LOOP              75 (to 297)
            222 LOAD_FAST                5 (y)
            225 GET_ITER            
        &amp;gt;&amp;gt;  226 FOR_ITER                67 (to 296)
            229 STORE_FAST               6 (ycoord)

 38         232 SETUP_LOOP              58 (to 293)
            235 LOAD_FAST                4 (x)
            238 GET_ITER            
        &amp;gt;&amp;gt;  239 FOR_ITER                50 (to 292)
            242 STORE_FAST               7 (xcoord)

 39         245 LOAD_FAST               11 (zs)
            248 LOAD_ATTR                5 (append)
            251 LOAD_GLOBAL              9 (complex)
            254 LOAD_FAST                7 (xcoord)
            257 LOAD_FAST                6 (ycoord)
            260 CALL_FUNCTION            2
            263 CALL_FUNCTION            1
            266 POP_TOP             

 40         267 LOAD_FAST               12 (cs)
            270 LOAD_ATTR                5 (append)
            273 LOAD_GLOBAL              9 (complex)
            276 LOAD_GLOBAL             10 (c_real)
            279 LOAD_GLOBAL             11 (c_imag)
            282 CALL_FUNCTION            2
            285 CALL_FUNCTION            1
            288 POP_TOP             
            289 JUMP_ABSOLUTE          239
        &amp;gt;&amp;gt;  292 POP_BLOCK           
        &amp;gt;&amp;gt;  293 JUMP_ABSOLUTE          226
        &amp;gt;&amp;gt;  296 POP_BLOCK           

 42     &amp;gt;&amp;gt;  297 LOAD_CONST               4 (&#39;Length of x:&#39;)
            300 PRINT_ITEM          
            301 LOAD_GLOBAL             12 (len)
            304 LOAD_FAST                4 (x)
            307 CALL_FUNCTION            1
            310 PRINT_ITEM          
            311 PRINT_NEWLINE       

 43         312 LOAD_CONST               5 (&#39;Total elements:&#39;)
            315 PRINT_ITEM          
            316 LOAD_GLOBAL             12 (len)
            319 LOAD_FAST               11 (zs)
            322 CALL_FUNCTION            1
            325 PRINT_ITEM          
            326 PRINT_NEWLINE       

 44         327 LOAD_GLOBAL             13 (time)
            330 LOAD_ATTR               13 (time)
            333 CALL_FUNCTION            0
            336 STORE_FAST              13 (start_time)

 45         339 LOAD_GLOBAL             14 (calculate_z_serial_purepython)
            342 LOAD_FAST                1 (max_iterations)
            345 LOAD_FAST               11 (zs)
            348 LOAD_FAST               12 (cs)
            351 CALL_FUNCTION            3
            354 STORE_FAST              14 (output)

 46         357 LOAD_GLOBAL             13 (time)
            360 LOAD_ATTR               13 (time)
            363 CALL_FUNCTION            0
            366 STORE_FAST              15 (end_time)

 47         369 LOAD_FAST               15 (end_time)
            372 LOAD_FAST               13 (start_time)
            375 BINARY_SUBTRACT     
            376 STORE_FAST              16 (secs)

 48         379 LOAD_GLOBAL             14 (calculate_z_serial_purepython)
            382 LOAD_ATTR               15 (func_name)
            385 LOAD_CONST               6 (&#39; took&#39;)
            388 BINARY_ADD          
            389 PRINT_ITEM          
            390 LOAD_FAST               16 (secs)
            393 PRINT_ITEM          
            394 LOAD_CONST               7 (&#39;seconds&#39;)
            397 PRINT_ITEM          
            398 PRINT_NEWLINE       

 52         399 LOAD_FAST               14 (output)
            402 RETURN_VALUE        
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;cell border-box-sizing text_cell rendered&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-orient: horizontal; background-color: white; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: thin solid transparent; box-sizing: border-box; display: -webkit-box; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; outline: none; padding: 5px;&quot;&gt;
&lt;div class=&quot;prompt input_prompt&quot; style=&quot;border-top-color: transparent; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; color: navy; font-family: monospace; line-height: 1.21429em; margin: 0px; min-width: 14ex; padding: 0.4em; text-align: right;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;inner_cell&quot; style=&quot;-webkit-box-align: stretch; -webkit-box-flex: 1; -webkit-box-orient: vertical; box-sizing: border-box; display: -webkit-box;&quot;&gt;
&lt;div class=&quot;text_cell_render border-box-sizing rendered_html&quot; style=&quot;border-style: none; box-sizing: border-box; outline: none; overflow-x: auto; padding: 0.5em 0.5em 0.5em 0.4em; resize: none; width: inherit;&quot;&gt;
&lt;div style=&quot;box-sizing: border-box;&quot;&gt;
Простое правило гласит, что несколько строк байт-кода будет выполняться более медленно, чем меньшим количеством эквивалентных линий байт-кода, использующих встроенные функции.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/1086236035454133014/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2015/04/python-profiling.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/1086236035454133014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/1086236035454133014'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2015/04/python-profiling.html' title='Python Profiling'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-6116020445032189005</id><published>2014-10-21T17:19:00.003-07:00</published><updated>2014-10-21T17:25:28.248-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Машинное обучение"/><category scheme="http://www.blogger.com/atom/ns#" term="Оптимизация"/><title type='text'>Оптимизация с учетом предпочтений</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://ard-media.ru/audit.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://ard-media.ru/audit.jpg&quot; height=&quot;234&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 132&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
В прошлый раз, мы &lt;a href=&quot;http://py-algorithm.blogspot.ru/2014/10/blog-post_21.html&quot;&gt;рассмотрели пример&lt;/a&gt; одной задачи, которую можно решить методами оптимизации. Напомним, что для применения оптимизации должны выполняться два основных требования: наличие целевой функции и тот факт, что близкие параметры дают близкие решения. Не каждую задачу, удовлетворяющую этим требованиям, можно решить методами оптимизации, но есть неплохие шансы, что попытка применить эти методы даст интересные результаты, о которых вы даже не подозревали.&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
На этот раз, мы займемся другой задачей, для которой оптимизация просто напрашивается. Общая формулировка такова: распределить ограниченные ресурсы между людьми, у которых есть явно выраженные предпочтения, так чтобы все были максимально счастливы (или, в зависимости от склада характера, минимально недовольны))))&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Оптимизация распределения студентов по комнатам&lt;/h3&gt;
Сегодня мы решим задачу о распределении студентов по комнатам в общежитии с учетом их основного и альтернативного пожеланий. Хотя формулировка довольно специфична, ее можно легко обобщить на похожие задачи, – тот же самый код годится для распределения игроков по столам в онлайновой карточной игре, для распределения ошибок между разработчиками в большом программном проекте и даже для распределения работы по дому между прислугой. Как и раньше, наша цель – собрать информацию об отдельных людях и найти такое сочетание, которое приводит к оптимальному результату. &lt;/div&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
В нашем примере будет пять двухместных комнат и десять претендующих на них студентов. У каждого студента есть основное и альтернативное пожелание.&lt;/div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 132&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;# Двухместные комнаты
dorms = [&#39;Zeus&#39;,&#39;Athena&#39;,&#39;Hercules&#39;,&#39;Bacchus&#39;,&#39;Pluto&#39;]

# Люди и два пожелания у каждого (основное, второстепенное)
prefs = [(&#39;Toby&#39;, (&#39;Bacchus&#39;, &#39;Hercules&#39;)),
       (&#39;Steve&#39;, (&#39;Zeus&#39;, &#39;Pluto&#39;)),
       (&#39;Karen&#39;, (&#39;Athena&#39;, &#39;Zeus&#39;)),
       (&#39;Sarah&#39;, (&#39;Zeus&#39;, &#39;Pluto&#39;)),
       (&#39;Dave&#39;, (&#39;Athena&#39;, &#39;Bacchus&#39;)), 
       (&#39;Jeff&#39;, (&#39;Hercules&#39;, &#39;Pluto&#39;)), 
       (&#39;Fred&#39;, (&#39;Pluto&#39;, &#39;Athena&#39;)), 
       (&#39;Suzie&#39;, (&#39;Bacchus&#39;, &#39;Hercules&#39;)), 
       (&#39;Laura&#39;, (&#39;Bacchus&#39;, &#39;Hercules&#39;)), 
       (&#39;James&#39;, (&#39;Hercules&#39;, &#39;Athena&#39;))]
&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Сразу видно, что удовлетворить основное пожелание каждого человека не удастся, так как на два места в комнате Bacchus имеется три претендента. Поместить любого из этих трех в ту комнату, которую он указал в качестве альтернативы, тоже невозможно, так как в комнате Hercules всего два места. &lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
В приведенном примере общее число вариантов порядка 100 000, то можно перебрать их все и найти оптимальный. Но если комнаты будут четырехместными, то количество вариантов будет исчислять триллионами. &lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Представление решения&lt;/h3&gt;
&lt;div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 134&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
В каждой комнате должно оказаться ровно два студента. Будем считать, что в каждой комнате есть два отсека, то есть всего их в нашем случае будет десять. Каждому студенту по очереди назначается один из незанятых отсеков; первого можно поместить в любой из десяти отсеков, второго – в любой из оставшихся девяти и т. д.&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
Область определения для поиска (смотри &lt;a href=&quot;http://py-algorithm.blogspot.ru/2014/10/blog-post_21.html&quot;&gt;предыдущую статью&lt;/a&gt;):&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;# [9, 8, 7, 6,..., 1]
domain = [i for i in xrange(9, 0, -1)]
&lt;/pre&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Целевая функция&lt;/h3&gt;
Целевая функция работает следующим образом. Создается начальный список отсеков, и уже использованные отсеки из него удаляются. Стоимость вычисляется путем сравнения комнаты, в которую студент помещен, с двумя его пожеланиями. Стоимость не изменяется, если студенту досталась та комната, в которую он больше всего хотел поселиться; увеличивается на 1, если это второе из его пожеланий; и увеличивается на 3, если он вообще не хотел жить в этой комнате. &lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def dorm_cost(vec):
 cost=0

 # Создаем список отсеков, т.е. первые 2 места - 0 отсек и т.д.
 slots = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4]

 # Цикл по студентам, i - порядковый номер студента
 for i in xrange(len(vec)):
  x = int(vec[i])
  dorm = dorms[slots[x]]
  pref = prefs[i][1]
  print x, &#39;-&amp;gt;&#39;, slots[x],&#39;-&amp;gt;&#39;, prefs[i][0], pref, &#39;-&amp;gt;&#39;, dorm

  # Стоимость основного пожелания равна 0, альтернативного – 1
  # Если комната не входит в список пожеланий, стоимость увеличивается на 3
  if pref[0] == dorm: cost += 0
  elif pref[1] == dorm: cost += 1
  else: cost += 3

  # Удалить выбранный отсек
  # Это самое важное действие тут,
  # прошу особо обратить на него внимание и учесть, что элементы сдвигаются
  del slots[x]

 return cost
&lt;/pre&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
При конструировании целевой функции полезно стремиться к тому, чтобы стоимость идеального решения (в данном случае каждый студент заселился в комнату, которую поставил на первое место в своем списке предпочтений) была равна нулю. В рассматриваемом примере мы уже убедились, что идеальное решение недостижимо, но, зная о том, что его стоимость равна нулю, можно оценить, насколько мы к нему приблизились. У этого правила есть еще одно достоинство – алгоритм оптимизации может прекратить поиск, если уже найдено идеальное решение. &lt;/div&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Оптимизация&lt;/h3&gt;
&lt;div&gt;
Всем кто не изучил методы оптимизации в &lt;a href=&quot;http://py-algorithm.blogspot.ru/2014/10/blog-post_21.html&quot;&gt;предыдущей статье&lt;/a&gt;, бегом изучать!) Хорошим мальчикам и может даже девочкам, импортировать любой из методов и запустить!) Я, для примера, попробую на генетическом алгоритме.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;result, score = genetic_optimize(domain, dorm_cost)
print result, score
&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;
Например у меня, нашелся такой результат&amp;nbsp;[7, 1, 2, 0, 0, 1, 2, 1, 0] 1, что соответствует следующему выводу:&lt;br /&gt;
&lt;br /&gt;
7 -&amp;gt; 3 -&amp;gt; Toby (&#39;Bacchus&#39;, &#39;Hercules&#39;) -&amp;gt; Bacchus&lt;br /&gt;
1 -&amp;gt; 0 -&amp;gt; Steve (&#39;Zeus&#39;, &#39;Pluto&#39;) -&amp;gt; Zeus&lt;br /&gt;
2 -&amp;gt; 1 -&amp;gt; Karen (&#39;Athena&#39;, &#39;Zeus&#39;) -&amp;gt; Athena&lt;br /&gt;
0 -&amp;gt; 0 -&amp;gt; Sarah (&#39;Zeus&#39;, &#39;Pluto&#39;) -&amp;gt; Zeus&lt;br /&gt;
0 -&amp;gt; 1 -&amp;gt; Dave (&#39;Athena&#39;, &#39;Bacchus&#39;) -&amp;gt; Athena&lt;br /&gt;
1 -&amp;gt; 2 -&amp;gt; Jeff (&#39;Hercules&#39;, &#39;Pluto&#39;) -&amp;gt; Hercules&lt;br /&gt;
2 -&amp;gt; 4 -&amp;gt; Fred (&#39;Pluto&#39;, &#39;Athena&#39;) -&amp;gt; Pluto&lt;br /&gt;
1 -&amp;gt; 3 -&amp;gt; Suzie (&#39;Bacchus&#39;, &#39;Hercules&#39;) -&amp;gt; Bacchus&lt;br /&gt;
0 -&amp;gt; 2 -&amp;gt; Laura (&#39;Bacchus&#39;, &#39;Hercules&#39;) -&amp;gt; Hercules&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
Т.е. не устроило только Lauru и то, учтен был ее 2й вариант)&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Вместо вывода&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
Итак, надеюсь, я показал, что используя одни алгоритмы, но меняя область определения и принцип расчета целевой функции, мы можем решить абсолютно разные оптимизационные задачи!)&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/6116020445032189005/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2014/10/blog-post_1.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/6116020445032189005'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/6116020445032189005'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2014/10/blog-post_1.html' title='Оптимизация с учетом предпочтений'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-8479902385918767646</id><published>2014-10-21T15:18:00.002-07:00</published><updated>2014-10-21T17:20:05.084-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Машинное обучение"/><category scheme="http://www.blogger.com/atom/ns#" term="Оптимизация"/><title type='text'>Задачи оптимизации</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://uchimatchast.ru/picture/45525712.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://uchimatchast.ru/picture/45525712.jpg&quot; height=&quot;320&quot; width=&quot;256&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Давайте разберемся, как решать задачи со множеством участников, применяя технику&amp;nbsp;&lt;i&gt;стохастической оптимизации&lt;/i&gt;.&amp;nbsp;По существу, оптимизация сводится к поиску наилучшего решения задачи путем апробирования различных решений и сравнения их между собой для оценки качества. Обычно оптимизация применяется в тех случаях, когда число решений слишком велико и перебрать их все невозможно.&lt;br /&gt;
&lt;br /&gt;
У методов оптимизации весьма широкая область применения: в физике они используются для изучения молекулярной динамики, в биологии – для прогнозирования белковых структур, а в информатике – для определения времени работы алгоритма в худшем случае. В НАСА методы оптимизации применяют даже для проектирования антенн с наилучшими эксплуатационными характеристиками. Выглядят они так, как ни один человек не мог бы вообразить.&lt;br /&gt;
&lt;br /&gt;
Мы же, для примера, возьмем классическую задачу группового путешествия!)&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 111&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
Наш пример относится к планированию группового путешествия дружеской компании из разных частей света. Всякий, кто пытался планировать поездку группы людей или даже одного человека, понимает, что нужно учитывать множество исходных данных, например: каким рейсом должен лететь каждый человек, сколько нужно арендовать машин и от какого аэропорта удобнее всего добираться. Также следует принять во внимание ряд выходных переменных: полная стоимость, время ожидания в аэропортах и непроизводительно потраченное время.&amp;nbsp;&lt;span style=&quot;font-family: SchoolBookC-Identity-H; font-size: 10pt;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &#39;SchoolBookC-Identity-H&#39;; font-size: 10pt;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h3&gt;
Формат данных&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 112&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
Планирование путешествия группы людей (в данном примере семейства Сидоровых), которые, отправляясь из разных мест, должны прибыть в одно и то же место.&lt;span style=&quot;font-family: &#39;SchoolBookC-Identity-H&#39;; font-size: 10pt;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Члены семьи живут в разных концах страны и хотят встретиться в Урюпинске. Все они должны вылететь в один день и в один день улететь и при этом в целях экономии хотели бы уехать из аэропорта и приехать в него на одной арендованной машине. Ежедневно, в славный город Урюпинск, из мест проживания любого члена семьи отправляются десятки рейсов, все в разное время. Цена билета и время в пути для каждого рейса разные.&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
Начнем со списка самих Сидоровых:&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;peoples = [(&#39;Seymour&#39;,&#39;BOS&#39;),
    (&#39;Franny&#39;,&#39;DAL&#39;),
    (&#39;Zooey&#39;,&#39;CAK&#39;),
    (&#39;Walt&#39;,&#39;MIA&#39;),
    (&#39;Buddy&#39;,&#39;ORD&#39;),
    (&#39;Les&#39;,&#39;OMA&#39;)]

# место назначения
destination = &#39;LGA&#39;

# словарь рейсов&lt;/pre&gt;
&lt;pre class=&quot;brush: python&quot;&gt;flights = {(&#39;LGA&#39;, &#39;CAK&#39;): [(&#39;6:58&#39;, &#39;9:01&#39;, 238), (&#39;8:19&#39;, &#39;11:16&#39;, 122), (&#39;9:58&#39;, &#39;12:56&#39;, 249), (&#39;10:32&#39;, &#39;13:16&#39;, 139), (&#39;12:01&#39;, &#39;13:41&#39;, 267), (&#39;13:37&#39;, &#39;15:33&#39;, 142), (&#39;15:50&#39;, &#39;18:45&#39;, 243), (&#39;16:33&#39;, &#39;18:15&#39;, 253), (&#39;18:17&#39;, &#39;21:04&#39;, 259), (&#39;19:46&#39;, &#39;21:45&#39;, 214)], (&#39;DAL&#39;, &#39;LGA&#39;): [(&#39;6:12&#39;, &#39;10:22&#39;, 230), (&#39;7:53&#39;, &#39;11:37&#39;, 433), (&#39;9:08&#39;, &#39;12:12&#39;, 364), (&#39;10:30&#39;, &#39;14:57&#39;, 290), (&#39;12:19&#39;, &#39;15:25&#39;, 342), (&#39;13:54&#39;, &#39;18:02&#39;, 294), (&#39;15:44&#39;, &#39;18:55&#39;, 382), (&#39;16:52&#39;, &#39;20:48&#39;, 448), (&#39;18:26&#39;, &#39;21:29&#39;, 464), (&#39;20:07&#39;, &#39;23:27&#39;, 473)], (&#39;LGA&#39;, &#39;BOS&#39;): [(&#39;6:39&#39;, &#39;8:09&#39;, 86), (&#39;8:23&#39;, &#39;10:28&#39;, 149), (&#39;9:58&#39;, &#39;11:18&#39;, 130), (&#39;10:33&#39;, &#39;12:03&#39;, 74), (&#39;12:08&#39;, &#39;14:05&#39;, 142), (&#39;13:39&#39;, &#39;15:30&#39;, 74), (&#39;15:25&#39;, &#39;16:58&#39;, 62), (&#39;17:03&#39;, &#39;18:03&#39;, 103), (&#39;18:24&#39;, &#39;20:49&#39;, 124), (&#39;19:58&#39;, &#39;21:23&#39;, 142)], (&#39;LGA&#39;, &#39;MIA&#39;): [(&#39;6:33&#39;, &#39;9:14&#39;, 172), (&#39;8:23&#39;, &#39;11:07&#39;, 143), (&#39;9:25&#39;, &#39;12:46&#39;, 295), (&#39;11:08&#39;, &#39;14:38&#39;, 262), (&#39;12:37&#39;, &#39;15:05&#39;, 170), (&#39;14:08&#39;, &#39;16:09&#39;, 232), (&#39;15:23&#39;, &#39;18:49&#39;, 150), (&#39;16:50&#39;, &#39;19:26&#39;, 304), (&#39;18:07&#39;, &#39;21:30&#39;, 355), (&#39;20:27&#39;, &#39;23:42&#39;, 169)], (&#39;LGA&#39;, &#39;OMA&#39;): [(&#39;6:19&#39;, &#39;8:13&#39;, 239), (&#39;8:04&#39;, &#39;10:59&#39;, 136), (&#39;9:31&#39;, &#39;11:43&#39;, 210), (&#39;11:07&#39;, &#39;13:24&#39;, 171), (&#39;12:31&#39;, &#39;14:02&#39;, 234), (&#39;14:05&#39;, &#39;15:47&#39;, 226), (&#39;15:07&#39;, &#39;17:21&#39;, 129), (&#39;16:35&#39;, &#39;18:56&#39;, 144), (&#39;18:25&#39;, &#39;20:34&#39;, 205), (&#39;20:05&#39;, &#39;21:44&#39;, 172)], (&#39;OMA&#39;, &#39;LGA&#39;): [(&#39;6:11&#39;, &#39;8:31&#39;, 249), (&#39;7:39&#39;, &#39;10:24&#39;, 219), (&#39;9:15&#39;, &#39;12:03&#39;, 99), (&#39;11:08&#39;, &#39;13:07&#39;, 175), (&#39;12:18&#39;, &#39;14:56&#39;, 172), (&#39;13:37&#39;, &#39;15:08&#39;, 250), (&#39;15:03&#39;, &#39;16:42&#39;, 135), (&#39;16:51&#39;, &#39;19:09&#39;, 147), (&#39;18:12&#39;, &#39;20:17&#39;, 242), (&#39;20:05&#39;, &#39;22:06&#39;, 261)], (&#39;CAK&#39;, &#39;LGA&#39;): [(&#39;6:08&#39;, &#39;8:06&#39;, 224), (&#39;8:27&#39;, &#39;10:45&#39;, 139), (&#39;9:15&#39;, &#39;12:14&#39;, 247), (&#39;10:53&#39;, &#39;13:36&#39;, 189), (&#39;12:08&#39;, &#39;14:59&#39;, 149), (&#39;13:40&#39;, &#39;15:38&#39;, 137), (&#39;15:23&#39;, &#39;17:25&#39;, 232), (&#39;17:08&#39;, &#39;19:08&#39;, 262), (&#39;18:35&#39;, &#39;20:28&#39;, 204), (&#39;20:30&#39;, &#39;23:11&#39;, 114)], (&#39;LGA&#39;, &#39;DAL&#39;): [(&#39;6:09&#39;, &#39;9:49&#39;, 414), (&#39;7:57&#39;, &#39;11:15&#39;, 347), (&#39;9:49&#39;, &#39;13:51&#39;, 229), (&#39;10:51&#39;, &#39;14:16&#39;, 256), (&#39;12:20&#39;, &#39;16:34&#39;, 500), (&#39;14:20&#39;, &#39;17:32&#39;, 332), (&#39;15:49&#39;, &#39;20:10&#39;, 497), (&#39;17:14&#39;, &#39;20:59&#39;, 277), (&#39;18:44&#39;, &#39;22:42&#39;, 351), (&#39;19:57&#39;, &#39;23:15&#39;, 512)], (&#39;LGA&#39;, &#39;ORD&#39;): [(&#39;6:03&#39;, &#39;8:43&#39;, 219), (&#39;7:50&#39;, &#39;10:08&#39;, 164), (&#39;9:11&#39;, &#39;10:42&#39;, 172), (&#39;10:33&#39;, &#39;13:11&#39;, 132), (&#39;12:08&#39;, &#39;14:47&#39;, 231), (&#39;14:19&#39;, &#39;17:09&#39;, 190), (&#39;15:04&#39;, &#39;17:23&#39;, 189), (&#39;17:06&#39;, &#39;20:00&#39;, 95), (&#39;18:33&#39;, &#39;20:22&#39;, 143), (&#39;19:32&#39;, &#39;21:25&#39;, 160)], (&#39;ORD&#39;, &#39;LGA&#39;): [(&#39;6:05&#39;, &#39;8:32&#39;, 174), (&#39;8:25&#39;, &#39;10:34&#39;, 157), (&#39;9:42&#39;, &#39;11:32&#39;, 169), (&#39;11:01&#39;, &#39;12:39&#39;, 260), (&#39;12:44&#39;, &#39;14:17&#39;, 134), (&#39;14:22&#39;, &#39;16:32&#39;, 126), (&#39;15:58&#39;, &#39;18:40&#39;, 173), (&#39;16:43&#39;, &#39;19:00&#39;, 246), (&#39;18:48&#39;, &#39;21:45&#39;, 246), (&#39;19:50&#39;, &#39;22:24&#39;, 269)], (&#39;MIA&#39;, &#39;LGA&#39;): [(&#39;6:25&#39;, &#39;9:30&#39;, 335), (&#39;7:34&#39;, &#39;9:40&#39;, 324), (&#39;9:15&#39;, &#39;12:29&#39;, 225), (&#39;11:28&#39;, &#39;14:40&#39;, 248), (&#39;12:05&#39;, &#39;15:30&#39;, 330), (&#39;14:01&#39;, &#39;17:24&#39;, 338), (&#39;15:34&#39;, &#39;18:11&#39;, 326), (&#39;17:07&#39;, &#39;20:04&#39;, 291), (&#39;18:23&#39;, &#39;21:35&#39;, 134), (&#39;19:53&#39;, &#39;22:21&#39;, 173)], (&#39;BOS&#39;, &#39;LGA&#39;): [(&#39;6:17&#39;, &#39;8:26&#39;, 89), (&#39;8:04&#39;, &#39;10:11&#39;, 95), (&#39;9:45&#39;, &#39;11:50&#39;, 172), (&#39;11:16&#39;, &#39;13:29&#39;, 83), (&#39;12:34&#39;, &#39;15:02&#39;, 109), (&#39;13:40&#39;, &#39;15:37&#39;, 138), (&#39;15:27&#39;, &#39;17:18&#39;, 151), (&#39;17:11&#39;, &#39;18:30&#39;, 108), (&#39;18:34&#39;, &#39;19:36&#39;, 136), (&#39;20:17&#39;, &#39;22:22&#39;, 102)]}

&lt;/pre&gt;
&lt;div class=&quot;column&quot;&gt;
Словарь рейсов имеет следующий формат: {(&#39;LGA&#39;, &#39;CAK&#39;): [(&#39;6:58&#39;, &#39;9:01&#39;, 238), (&#39;8:19&#39;, &#39;11:16&#39;, 122),....], .....} - (аэропорт вылета, прилета), как ключ и (время вылета, время прилета, стоимость), как значение. Заполните его произвольным способом, можно поискать на сайтах авиа и заполнить реальной ситуацией))&lt;br /&gt;
&lt;br /&gt;
Для подобных задач необходимо определиться со способом представления потенциальных решений. Функции оптимизации, с которыми вы вскоре ознакомитесь, достаточно общие и применимы к различным задачам, поэтому так важно выбрать простое представление, которое не было бы привязано к конкретной задаче о групповом путешествии. Очень часто для этой цели выбирают список чисел. Каждое число обозначает рейс, которым решил лететь участник группы.&lt;/div&gt;
&lt;br /&gt;
Например, в решении, представленном списком [1,4,3,2,7,3,6,3,2,4,5,3]&lt;br /&gt;
Сеймур (Seymour) летит первым рейсом из Бостона в Нью-Йорк и четвертым рейсом из Нью-Йорка в Бостон, а Фрэнни (Franny) – третьим рейсом из Далласа в Нью-Йорк и вторым обратно.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;
Целевая функция&lt;/h3&gt;
Ключом к решению любой задачи оптимизации является&amp;nbsp;&lt;i&gt;целевая функция&lt;/i&gt;, и именно ее обычно труднее всего отыскать. Цель оптимизационного алгоритма состоит в том, чтобы найти такой набор входных переменных, который минимизирует целевую функцию. Поэтому целевая функция должна возвращать значение, показывающее, насколько данное решение неудовлетворительно. Возвращаемое значение должно быть тем больше, чем хуже решение.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Рассмотрим несколько параметров, которые можно измерить в примере с групповым путешествием:&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;i&gt;Цена&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Полная стоимость всех билетов или, возможно, среднее значение, взвешенное с учетом финансовых возможностей.&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;i&gt;Время в пути&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Суммарное время, проведенное всеми членами семьи в полете.&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;i&gt;Время ожидания&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Время, проведенное в аэропорту в ожидании прибытия остальных членов группы.&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;i&gt;Время вылета&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Если самолет вылетает рано утром, это может увеличивать общую стоимость из-за того, что путешественники не выспятся.&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;i&gt;Время аренды автомобилей&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Если группа арендует машину, то вернуть ее следует до того часа, когда она была арендована, иначе придется платить за лишний день.&lt;/blockquote&gt;
Определившись с тем, какие переменные влияют на стоимость, нужно решить, как из них составить одно число. В нашем случае можно, например, выразить в деньгах время в пути или время ожидания в аэропорту. Скажем, каждая минута в воздухе эквивалентна $1 (иначе гово- ря, можно потратить лишние $90 на прямой рейс, экономящий полтора часа), а каждая минута ожидания в аэропорту эквивалентна $0,50. Можно было бы также приплюсовать стоимость лишнего дня аренды машины, если для всех имеет смысл вернуться в аэропорт к более поз- днему часу.&lt;br /&gt;
&lt;br /&gt;
Определенная ниже, целевая функция shedule_cost принимает во внимание полную стоимость поездки и общее время ожидания в аэропорту всеми членами семьи. Кроме того, она добавляет штраф $50, если машина возвращена в более поздний час, чем арендована.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;# время в минутах
def get_minutes(t):
 x=time.strptime(t,&#39;%H:%M&#39;)
 return x[3]*60+x[4]

def schedule_cost(sol):
 totalprice = 0
 latestarrival = 0
 earliestdep = 24*60

 for d in xrange(len(sol)/2):
  # Получить список прибывающих и убывающих реисов
  origin = peoples[d][1]
  outbound = flights[(origin, destination)][int(sol[d])]
  returnf = flights[(destination, origin)][int(sol[d+1])]

  # Полная цена равна сумме цен на билет туда и обратно
  totalprice += outbound[2]
  totalprice += returnf[2]

  # Находим самыи позднии прилет и самыи раннии вылет
  if latestarrival &amp;lt; get_minutes(outbound[1]): latestarrival = get_minutes(outbound[1])
  if earliestdep &amp;gt; get_minutes(returnf[0]): earliestdep = get_minutes(returnf[0])

 # Все должны ждать в аэропорту прибытия последнего участника группы.
 # Обратно все прибывают одновременно и должны ждать свои реисы.
 totalwait = 0  
 for d in xrange(len(sol)/2):
  origin = peoples[d][1]
  outbound = flights[(origin, destination)][int(sol[d])]
  returnf = flights[(destination, origin)][int(sol[d+1])]
  totalwait += latestarrival - get_minutes(outbound[1])
  totalwait += get_minutes(returnf[0]) - earliestdep  

 # Для этого решения требуется оплачивать дополнительныи день аренды?
 # Если да, это обоидется в лишние $50!
 if latestarrival &amp;gt; earliestdep: totalprice += 50

 return totalprice + totalwait
&lt;/pre&gt;
Логика этой функции очень проста, но суть вопроса она отражает. Улучшить ее можно несколькими способами. Так, в текущей версии предполагается, что все члены семьи уезжают из аэропорта вместе, когда прибывает самый последний, а возвращаются в аэропорт к моменту вылета самого раннего рейса. Можно поступить по-другому: если человеку приходится ждать два часа или дольше, то он арендует отдельную машину, а цены и время ожидания соответственно корректируются.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;h3&gt;
Случайный поиск&lt;/h3&gt;
Случайный поиск – не самый лучший метод оптимизации, но он позволит нам ясно понять, чего пытаются достичь все алгоритмы, а также послужит эталоном, с которым можно будет сравнивать другие алгоритмы.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Соответствующая функция принимает два параметра. Domain – это список значений, определяющих количество вариантов рейсов каждого из участников путешествия. Важно что они отсортированы в том же порядке, что и сами участники, сначала идут в Урюпинск, потом оттуда. Длина решения совпадает с длиной этого списка.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Второй параметр, costf, – это целевая функция; в нашем примере в этом качестве используется schedule_cost. Она передается в виде параметра, чтобы алгоритм можно было использовать повторно и для других задач оптимизации. Алгоритм случайным образом генерирует 1000 гипотез и для каждой вызывает функцию costf. Возвращается наилучшая гипотеза (с минимальной стоимостью).&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;domain = []
for people in peoples:
 domain.append(len(flights[(people[1], destination)]) - 1)
 domain.append(len(flights[(destination, people[1])]) - 1)
print domain

def random_optimize(domain, costf):
 best=999999999
 bestr=None

 for i in xrange(0, 1000):
  # Выбрать случаиное решение
  r = [random.randint(0, domain[i]) for i in xrange(len(domain))]

  # Get the cost
  cost = costf(r)

  # Сравнить со стоимостью наилучшего наиденного к этому моменту решения
  if cost &amp;lt; best:
   best = cost
   bestr = r
 return r, best

result, score = random_optimize(domain, schedule_cost)
print result, score
&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;
Позапускав, я получил макс хороший вариант (из 10 запусков по 1000 вариантов) 3208$, будем с ним и сравнивать)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Алгоритм спуска с горы&amp;nbsp;&lt;/h3&gt;
&lt;/div&gt;
Случайное апробирование решений очень неэффективно, потому что пренебрегает выгодами, которые можно получить от анализа уже найденных хороших решений. В нашем примере можно предположить, что расписание с низкой полной стоимостью похоже на другие расписания с низкой стоимостью.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Альтернативный метод случайного поиска называется&amp;nbsp;&lt;i&gt;алгоритмом спуска с горы&lt;/i&gt;&amp;nbsp;(hill climbing). Он начинает со случайного решения и ищет лучшие решения (с меньшим значением целевой функции) по соседству. Можно провести аналогию со спуском с горы.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZsReudSJw6XjG227yK32oRt_taFqepGm7AICe0mK6lw2fp8wbapdqDoq1fePgJT2cDf7ITB_4rqucj4WE6Yz3h26XYj2fUxAJWTTGUe0Dy-x2T4gyZ3Xo-A2X9HVFeE6ecNFTAJpA/s1600/2014-10-18+18-59-31+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZsReudSJw6XjG227yK32oRt_taFqepGm7AICe0mK6lw2fp8wbapdqDoq1fePgJT2cDf7ITB_4rqucj4WE6Yz3h26XYj2fUxAJWTTGUe0Dy-x2T4gyZ3Xo-A2X9HVFeE6ecNFTAJpA/s1600/2014-10-18+18-59-31+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; height=&quot;131&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Представьте, что человечек на рисунке – это вы и оказались в этом месте по воле случая. Вы хотите добраться до самой низкой точки, чтобы найти воду. Для этого вы, наверное, осмотритесь и направитесь туда, где склон самый крутой. И будете двигаться в направлении наибольшей крутизны, пока не дойдете до точки, где местность становится ровной или начинается подъем.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 118&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
Применим этот подход. Начнем со случайно выбранного расписания и просмотрим все расписания в его окрестности. В данном случае это означает просмотр таких расписаний, для которых один человек выбирает рейс, вылетающий чуть раньше или чуть позже. Для каждого из соседних расписаний вычисляется стоимость, и расписание с наименьшей стоимостью становится новым решением. Этот процесс повторяется и завершается, когда ни одно из соседних расписаний не дает улучшения стоимости.&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def hill_climb(domain, costf):

 # Выбрать случаиное решение
 sol = [random.randint(0, domain[i]) for i in xrange(len(domain))]
 best = costf(sol)

 # Главныи цикл
 is_stop = False
 while not is_stop:
  # Создать список соседних решении
  neighbors = []
  for j in xrange(len(domain)):

   # Отходим на один шаг в каждом направлении
   if 0 &amp;lt; sol[j] &amp;lt; 9:
    neighbors.append(sol[0:j] + [sol[j]+1] + sol[j+1:])
    neighbors.append(sol[0:j] + [sol[j]-1] + sol[j+1:])

   if 0 == sol[j]:
    neighbors.append(sol[0:j] + [sol[j]+1] + sol[j+1:])

   if sol[j] == domain[j]:
    neighbors.append(sol[0:j] + [sol[j]-1] + sol[j+1:])

  # Ищем наилучшее из соседних решении

  is_stop = True
  for j in xrange(len(neighbors)):
   cost = costf(neighbors[j])
   if cost &amp;lt; best:
    is_stop = False
    best = cost
    sol = neighbors[j]

 return sol, best

result, score = hill_climb(domain, schedule_cost)
print result, score&lt;/pre&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Для выбора начального решения эта функция генерирует случайный список чисел из заданного диапазона. Соседи текущего решения ищутся путем посещения каждого элемента списка и создания двух новых списков, в одном из которых этот элемент увеличен на единицу, а в другом уменьшен на единицу. Лучшее из соседних решений становится новым решением.&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
На самом деле, в данном случае этот мест даст так себе результаты. Хотя, в большинстве случаев, лучше чем 1000 случайных вариантов.&amp;nbsp;Однако у алгоритма спуска с горы, есть один существенный недостаток.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7cf6mEee6_0BSrqn9FHEh0dxYadYyq6ee88vNzKa2NkJB23lP39JDhmOP05BY0wi5b8eJPNX6TUIuvNulYmoKCUZtseNTiCx00QsTztcnL2zMx4x7LpNCxtV6XeHvbXtXrAruw0JQ/s1600/2014-10-18+20-00-52+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7cf6mEee6_0BSrqn9FHEh0dxYadYyq6ee88vNzKa2NkJB23lP39JDhmOP05BY0wi5b8eJPNX6TUIuvNulYmoKCUZtseNTiCx00QsTztcnL2zMx4x7LpNCxtV6XeHvbXtXrAruw0JQ/s1600/2014-10-18+20-00-52+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; height=&quot;140&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Из рисунка видно, что, спускаясь по склону, мы необязательно отыщем наилучшее возможное решение. Найденное решение будет &lt;i&gt;локальным минимумом&lt;/i&gt;, то есть лучшим из всех в ближайшей окрестности, но это не означает, что оно вообще лучшее. Решение, лучшее среди всех возможных, называется глобальным минимумом, и именно его хотят найти все алгоритмы оптимизации. Один из возможных подходов к решению проблемы называется спуском с горы со случайным перезапуском. В этом случае алгоритм спуска выполняется несколько раз со случайными начальными точками в надежде, что какое-нибудь из найденных решений будет близко к глобальному минимуму. Так же, все усугубляется тем, что у такой ф-ии как наша, большая импульсивность (много локальных минимумов и максимумов), очень не линейная скорость роста в разных точках, в общем очень много факторов, с учетом того, что мы рассматриваем ф-ию в 12 мерном пространстве и в каждом из них она ведет себя по-разному...&lt;/div&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Алгоритм имитации отжига&lt;/h3&gt;
Алгоритм имитации отжига навеян физическими аналогиями. Отжигом называется процесс нагрева образца с последующим медленным охлаждением. Поскольку сначала атомы заставляют попрыгать, а затем постепенно «отпускают вожжи», то они переходят в новую низко-энергетичную конфигурацию. &lt;/div&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Алгоритмическая версия отжига начинается с выбора случайного решения задачи. В ней используется переменная, интерпретируемая как температура, начальное значение которой очень велико, но постепенно уменьшается. На каждой итерации случайным образом выбирается один из параметров решения и изменяется в определенном направлении. &lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 118&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Тут есть важная деталь: если новая стоимость ниже, то новое решение становится текущим, как и в алгоритме спуска с горы. Но, даже если новая стоимость выше, новое решение все равно может стать текущим с некоторой вероятностью. Так мы пытаемся избежать ситуации скатывания в локальный минимум.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 121&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
Иногда необходимо перейти к худшему решению, чтобы найти лучшее. Алгоритм имитации отжига работает, потому что всегда готов перейти к лучшему решению, но ближе к началу процесса соглашается принять и худшее. По мере того как процесс развивается, алгоритм соглашается на худшее решение все с меньшей охотой, а в конце работы принимает только лучшее. Вероятность того, что будет принято решение с более высокой стоимостью, рассчитывается по формуле: &lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw22xedpUGQWYzQtz6mTSKQr9UZyyaN-9ctwvImQP6WRnF4qldrmmL5QDq_ykXUsORVihU9UgGgtyDmWxl4rwZGqeX9fBmg_3xKr7Fk00fSWWyo8Kn8BGQU0R5AWxvtkheEmYMNcil/s1600/2014-10-20+02-05-41+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw22xedpUGQWYzQtz6mTSKQr9UZyyaN-9ctwvImQP6WRnF4qldrmmL5QDq_ykXUsORVihU9UgGgtyDmWxl4rwZGqeX9fBmg_3xKr7Fk00fSWWyo8Kn8BGQU0R5AWxvtkheEmYMNcil/s1600/2014-10-20+02-05-41+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; height=&quot;35&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Поскольку температура (готовность принять худшее решение) вначале очень высока, то показатель степени близок к 0, поэтому вероятность равна почти 1. По мере уменьшения температуры разность между высокой стоимостью и низкой стоимостью становится более значимой, а чем больше разность, тем ниже вероятность, поэтому алгоритм из всех худших решений будет выбирать те, что лишь немногим хуже текущего. 
    &lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def annealing_optimize(domain, costf, T=10000.0, cool=0.99, step=1):
 
 # Выбрать случаиное решение
 vec = [random.randint(0, domain[i]) for i in xrange(len(domain))]

 while T &amp;gt; 0.1:
  # Выбрать один из индексов
  i = random.randint(0, len(domain)-1)

  # Выбрать направление изменения
  dir = random.randint(-step, step)

  # Создать новыи список, в котором одно значение изменено
  vecb = vec[:]
  vecb[i] += dir
  if vecb[i] &amp;lt; 0: vecb[i] = 0
  elif vecb[i] &amp;gt; domain[i]: vecb[i] = domain[i]

  # Вычислить текущую и новую стоимость
  ea = costf(vec)
  eb = costf(vecb)
  p = pow(math.e, (-eb-ea)/T)

  # Новое решение лучше? Если нет, метнем кости
  if (eb &amp;lt; ea or random.random() &amp;lt; p):
   vec = vecb      

  # Уменьшить температуру
  T = T * cool
 return vec, eb

result, score = annealing_optimize(domain, schedule_cost)
print result, score&lt;/pre&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
На каждой итерации в качестве i случайно выбирается одна из переменных решения, а dir случайно выбирается между –step и step. Вычисляется стоимость теку- щего решения и стоимость решения, получающегося изменением пе- ременной i на величину step. &lt;/div&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
В p, вычисляется вероятность, которая уменьшается с уменьшением T. Если величина, случайно выбранная между 0 и 1, оказывается меньше вычисленной вероятности или если новое решение лучше текущего, то новое решение становится текущим. Цикл продолжается, пока температура почти не достигнет нуля, причем каждый раз температура умножается на скорость охлаждения. &lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 121&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 121&quot;&gt;
По-поводу лучше или нет результаты, сказать не могу, скорее всего, приблизительно одинаково(&lt;/div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 121&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Генетические алгоритмы&lt;/h3&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;Отцом генетических алгоритмов принято считать ученого-тео- ретика Джона Холланда (John Holland), который в 1975 году написал книгу «Adaptation in Natural and Artificial Systems» (издательство Мичиганского университета). Но корни этих работ восходят к биологам 1950-х годов, которые пытались моделировать эволюцию на компьютерах. С тех пор генетические алгоритмы и другие методы оптимизации использовались для решения широчайшего круга задач, в том числе:&lt;br /&gt; &lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;
&lt;li&gt;Нахождения формы концертного зала с оптимальными акустическими характеристиками.&lt;/li&gt;
&lt;/span&gt;&lt;/ul&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;
&lt;/span&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;
&lt;li&gt;Проектирования оптимальной формы крыла сверхзвукового самолета.&lt;/li&gt;
&lt;/span&gt;&lt;/ul&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Составления оптимальной библиотеки химических веществ для синтеза потенциальных лекарств.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Автоматического проектирования микросхем для распознавания речи.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;Решения этих задач можно представить в виде списков чисел. Это упрощает применение к ним генетических алгоритмов или метода имитации отжига. &lt;/span&gt;&lt;/blockquote&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;Еще&lt;/span&gt; один класс методов оптимизации, также навеянный природой, называется генетическими алгоритмами. Принцип их работы состоит в том, чтобы создать набор случайных решений, который называется популяцией. На каждом шаге оптимизации целевая функция вычисляется для всей популяции, в результате чего получается ранжирован- ный список решений. &lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHSPDxi4YZcYdmQ-aF6AaxE6onpAsBMMMJGpKvemc83wGWuFw6d1gAEQCFdAlnQW7Sj7vusB9Cnc0h1XV5F5-8dwWjzuUTpuqoadnPKSx_uhO9WpTIW80CjWuPQ9Dn47hr1gM_Nfdb/s1600/2014-10-21+01-09-19+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHSPDxi4YZcYdmQ-aF6AaxE6onpAsBMMMJGpKvemc83wGWuFw6d1gAEQCFdAlnQW7Sj7vusB9Cnc0h1XV5F5-8dwWjzuUTpuqoadnPKSx_uhO9WpTIW80CjWuPQ9Dn47hr1gM_Nfdb/s1600/2014-10-21+01-09-19+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; height=&quot;188&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Ранжированный список решений иих стоимостей&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Проранжировав решения, мы создаем новую популяцию, которая называется следующим поколением. Сначала в новую популяцию включаются самые лучшие решения из текущей. Этот процесс называется элитизмом. Кроме них, в следующую популяцию входят совершенно новые решения, получающиеся путем модификации наилучших. &lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Модифицировать решения можно двумя способами. Более простой называется мутацией; обычно это небольшое, простое, случайное изменение существующего решения. В нашем случае для мутации достаточно выбрать одну из переменных решения и уменьшить либо увели- чить ее.  &lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgC_tzNS4Ke0ws1-W9emC6V67ACi8HEmK6Y-U1s6jM6vhFgOigK92yT3t0MJpe5Gq-xP0anB5o1R9K48-cAGNZh4ajc5lpVCL7YI0Bc3l5SKC3TFG0YrxkqxcpGXpsnvb4qjLXqFYV-/s1600/2014-10-21+01-13-09+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgC_tzNS4Ke0ws1-W9emC6V67ACi8HEmK6Y-U1s6jM6vhFgOigK92yT3t0MJpe5Gq-xP0anB5o1R9K48-cAGNZh4ajc5lpVCL7YI0Bc3l5SKC3TFG0YrxkqxcpGXpsnvb4qjLXqFYV-/s1600/2014-10-21+01-13-09+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; height=&quot;105&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Пример мутации&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Другой способ называется скрещиванием (или кроссовером). Состоит он в том, что мы берем какие-нибудь два из лучших решений и как-то комбинируем их. В нашем примере достаточно взять случайное число элементов из одного решения, а остальные – из другого, как показано. &lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgncXW6C3mgCvxkhHriJ0bMz2HOCmpugPHBGiqlGRfDLTpLrFE2pvkUpMd6GcpemNxCqKVcl4eoS5tMU67z8gmYdyCm2sWthI9PukBSF39FH_wVjVfsk6qsgM8N4R6lHlK_JlFmrYUs/s1600/2014-10-21+01-15-12+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgncXW6C3mgCvxkhHriJ0bMz2HOCmpugPHBGiqlGRfDLTpLrFE2pvkUpMd6GcpemNxCqKVcl4eoS5tMU67z8gmYdyCm2sWthI9PukBSF39FH_wVjVfsk6qsgM8N4R6lHlK_JlFmrYUs/s1600/2014-10-21+01-15-12+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; height=&quot;122&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Пример скрещивания&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 123&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
Размер новой популяции обычно совпадает с размером предыдущей, а создается она путем случайных мутаций и скрещиваний лучших решений. Затем этот процесс повторяется – новая популяция ранжируется и создается очередное поколение. Так продолжается заданное число раз или до тех пор, пока на протяжении нескольких поколений не наблюдается никаких улучшений.
    &lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;# pop_size - размер популяции
# mutprob - чем меньше, тем реже берем мутацию и чаще скрещивание
# elite - Доля особеq в популяции, считающихся хорошими решениями и переходящих в следующее поколение
# maxiter - Количество поколений&lt;/pre&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def genetic_optimize(domain, costf, pop_size=50, step=1, mutprob=0.2, elite=0.2, maxiter=100):
 
 # Мутация
 def mutate(vec):
  i = random.randint(0, len(domain)-1)
  if vec[i] &amp;lt; domain[i]:
   return vec[0:i]+[vec[i]+step]+vec[i+1:]
  else:
   return vec[0:i]+[vec[i]-step]+vec[i+1:]

 # Скрещивание
 def crossover(r1, r2):
  i = random.randint(1, len(domain)-2)
  return r1[0:i]+r2[i:]

 # Создаем первую популяцию
 pop = []
 for i in xrange(pop_size):
  vec = [random.randint(0, domain[i]) for i in xrange(len(domain))]
  pop.append(vec)

 # Сколько лучших оставляем из каждого поколения
 topelite = int(elite*pop_size)

 for i in xrange(maxiter):
  scores = [(costf(v), v) for v in pop]
  scores.sort()
  ranked = [v for (s,v) in scores]

  # Сначала включаем только победителеи
  pop = ranked[0:topelite]

  # Добавляем особей, полученных мутацией и скрещиванием победивших родителей
  while len(pop) &amp;lt; pop_size:

   if random.random() &amp;lt; mutprob:
    # Мутация
    c = random.randint(0, topelite)
    pop.append(mutate(ranked[c]))

   else:
    # Скрещивание
    c1 = random.randint(0, topelite)
    c2 = random.randint(0, topelite)
    pop.append(crossover(ranked[c1], ranked[c2]))

 return scores[0][1], scores[0][0]&lt;/pre&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Вместо вывода&lt;/h3&gt;
Будет ли работать конкретный метод оптимизации, в значительной мере зависит от задачи. Метод имитации отжига, генетические алгоритмы и прочие методы оптимизации основаны на том факте, что в большинстве задач оптимальное решение близко к другим хорошим решениям. А на рисунке ниже представлен случай, когда оптимизация может и не сработать. &lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQsdNlvGpnBJGlKxEzlFWuIY6gywqpmMIpRYPKa1hW49l3ODjLDhIoeHuL7ER5U_DNafjJ9CjwkYDVj99XcQ6C3USo2kdUk7aNYOeK9yCPpL5d7E7V527BX_m3bLhlAoLHkP3dnZ9Y/s1600/2014-10-21+03-41-37+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQsdNlvGpnBJGlKxEzlFWuIY6gywqpmMIpRYPKa1hW49l3ODjLDhIoeHuL7ER5U_DNafjJ9CjwkYDVj99XcQ6C3USo2kdUk7aNYOeK9yCPpL5d7E7V527BX_m3bLhlAoLHkP3dnZ9Y/s1600/2014-10-21+03-41-37+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; height=&quot;161&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Оптимальная стоимость соответствует низшей точке очень крутого участка кривой в правой части рисунка. Любое достаточно близкое решение, скорее всего, будет отвергнуто из-за его высокой стоимости, поэтому мы никогда не сможем добраться до глобального минимума. Большинство алгоритмов остановятся в каком-то локальном минимуме в левой части рисунка. &lt;/div&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Пример с составлением расписания полетов работает, потому что выбор второго рейса вместо третьего, скорее всего, изменит стоимость менее значительно, чем выбор восьмого рейса. Если бы рейсы были упорядочены случайным образом, то методы оптимизации работали бы не лучше случайного поиска; на самом деле не существует ни одного метода оптимизации, который в этом случае работал бы устойчиво лучше, чем случайный поиск. &lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/8479902385918767646/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2014/10/blog-post_21.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/8479902385918767646'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/8479902385918767646'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2014/10/blog-post_21.html' title='Задачи оптимизации'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZsReudSJw6XjG227yK32oRt_taFqepGm7AICe0mK6lw2fp8wbapdqDoq1fePgJT2cDf7ITB_4rqucj4WE6Yz3h26XYj2fUxAJWTTGUe0Dy-x2T4gyZ3Xo-A2X9HVFeE6ecNFTAJpA/s72-c/2014-10-18+18-59-31+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-3733609072724037117</id><published>2014-10-12T16:37:00.001-07:00</published><updated>2015-04-26T13:23:27.128-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Машинное обучение"/><title type='text'>Кластеризация данных</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://www.basegroup.ru/files/image/library/analysis/clusterization/datamining/k-means.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://www.basegroup.ru/files/image/library/analysis/clusterization/datamining/k-means.gif&quot; height=&quot;171&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 50&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
Кластеризация данных – это метод обнаружения и визуализации групп связанных между собой предметов. Данный инструмент часто используется в приложениях, обрабатывающих большие объемы данных. Кластеризация – пример обучения без учителя. В отличие от нейронных сетей или деревьев решений, алгоритмам обучения без учителя не сообщаются правильные ответы. Их задача – обнаружить структуру в наборе данных, когда ни один элемент данных не является ответом.&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
Постановка задачи&lt;/h2&gt;
&lt;div&gt;
Совсем недавно, компания Adobe, выпустила на iPhone програмку &lt;a href=&quot;https://itunes.apple.com/ru/app/adobe-color-cc-sohranenie/id632313714?mt=8&quot;&gt;Adobe Color CC&lt;/a&gt;. До меня дошла эта новость и я понял, что пора объяснить, как же это делается!) Метод известный и описан во многих местах, но наше - всегда лучше))) Задача у нас простая, методом K-средних сделать K кластеров цветов картинки и выявив центры кластеров, посмотреть какому цвету он соответствует. Таким образом мы узнаем основные тона картинки ;) Но сначала, немножко теории.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Иерархическая кластеризация&lt;/h3&gt;
&lt;div&gt;
Методоово кластеризации бывает несколько, в основном, мы будем рассматривать метод k-средних, но есть так же и метод иерархической кластеризации.&amp;nbsp;Алгоритм иерархической кластеризации строит иерархию групп, объединяя на каждом шаге две самые похожие группы. В начале каждая группа состоит из одного элемента, в данном случае – одного блога. На каждой итерации вычисляются попарные расстояния между группами, и группы, оказавшиеся самыми близкими, объединяются в новую группу. Так повторяется до тех пор, пока не останется всего одна группа.&lt;/div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 54&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;span style=&quot;font-family: &#39;SchoolBookC-Identity-H&#39;; font-size: 10.000000pt;&quot;&gt;&amp;nbsp;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqAKXsO8VU-lguNf91Dnmc5o9lSEIRwqA8cQER4CtXUYm5_-QEUpTbruIQi2WhyphenhyphenNi7zwuwL5OWjGgsLda9cMLwXvOOpsRbuXyQLnzqKeeg5pyU_cTNuqm_RlHwtx9uOrQ4FF35S_HT/s1600/2014-10-10+00-58-14+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqAKXsO8VU-lguNf91Dnmc5o9lSEIRwqA8cQER4CtXUYm5_-QEUpTbruIQi2WhyphenhyphenNi7zwuwL5OWjGgsLda9cMLwXvOOpsRbuXyQLnzqKeeg5pyU_cTNuqm_RlHwtx9uOrQ4FF35S_HT/s1600/2014-10-10+00-58-14+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; height=&quot;257&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Иерархическая кластеризация в действии&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/span&gt;&lt;br /&gt;
Здесь схожесть элементов представлена их относительным расположением – чем элементы ближе друг к другу, тем более они схожи. В начале каждый элемент – это отдельная группа. На втором шаге два самых лизких элемента A и B объединены в новую группу, расположенную посередине между исходными. На третьем шаге эта новая группа объединяется с элементом C. Поскольку теперь два ближайших элемента – это D и E, то из них образуется новая группа. И на последнем шаге две оставшиеся группы объединяются в одну.  &lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Результаты иерархической кластеризации обычно представляются в виде графа, который называется дендрограммой. На нем изображено, как из узлов формировалась иерархия. &lt;/div&gt;
&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiB36D5V1znrg-BmYyYUtXRk1-ZhO0KhhJ8bxRJGIC_vdTcunVr0ZoTd4qgat372MZPKILFLyQEBkN4P3HMMJILkwkQwg0f7tN-HS5CHCtYnDxSPWBKP5GnsU_F3xLYeZRBTir639Q4/s1600/2014-10-10+01-01-45+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiB36D5V1znrg-BmYyYUtXRk1-ZhO0KhhJ8bxRJGIC_vdTcunVr0ZoTd4qgat372MZPKILFLyQEBkN4P3HMMJILkwkQwg0f7tN-HS5CHCtYnDxSPWBKP5GnsU_F3xLYeZRBTir639Q4/s1600/2014-10-10+01-01-45+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; height=&quot;188&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;div class=&quot;page&quot; title=&quot;Page 55&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;span style=&quot;font-family: &#39;SchoolBookC-Italic-Identity-H&#39;; font-size: 9.000000pt;&quot;&gt;Дендрограмма как способ визуализации
иерархической кластеризации&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
На дендрограмме представлены не только ребра графа, показывающие, из каких элементов составлен каждый кластер, но и расстояния, говорящие о том, как далеко эти элементы отстояли друг от друга. Кластер AB гораздо ближе к составляющим его элементам A и B, чем кластер DE к элементам D и E. Изображение графа таким образом помогает понять, насколько схожи элементы, вошедшие в кластер. Эта характеристика называется теснотой (tightness) кластера. 
    &lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Иерархическая кластеризация дает на выходе симпатичное дерево, но у этого метода есть два недостатка. Древовидное представление само по себе не разбивает данные на группы, для этого нужна дополнительная работа. Кроме того, алгоритм требует очень большого объема вычисле- ний. Поскольку необходимо вычислять попарные соотношения, а затем вычислять их заново после объединения элементов, то на больших наборах данных алгоритм работает медленно. И тут на помощь приходит другой метод!)&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Кластеризация методом k-средних&lt;/h3&gt;
&lt;div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 64&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
Он в корне отличается от иерархической кластеризации, поскольку ему нужно заранее указать, сколько кластеров генерировать. Алгоритм определяет размеры кластеров исходя из структуры данных.&lt;span style=&quot;font-family: &#39;SchoolBookC-Identity-H&#39;; font-size: 10.000000pt;&quot;&gt;&lt;br /&gt;&lt;/span&gt;

  
 
 
  Кластеризация методом K-средних начинается с выбора k случайно расположенных центроидов (точек, представляющих центр кластера). Каждому элементу назначается ближайший центроид. После того как назначение выполнено, каждый центроид перемещается в точку, рассчитываемую как среднее по всем приписанным к нему элементам. Затем назначение выполняется снова. Эта процедура повторяется до тех пор, пока назначения не прекратят изменяться.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvHvoUZcq2jstMgCFLjMpYDrsxIncbDEvD8RkM2DsQ8McpXdLBoqVAwUW5Lb-uWQIdUVOLZ-4AsTbwCEAxuEzpmvXGNR8OvQ-UxUIPO9gSe11bvhEpcHI3lT-3ipTM8JosiZbrwt4D/s1600/2014-10-10+01-11-44+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvHvoUZcq2jstMgCFLjMpYDrsxIncbDEvD8RkM2DsQ8McpXdLBoqVAwUW5Lb-uWQIdUVOLZ-4AsTbwCEAxuEzpmvXGNR8OvQ-UxUIPO9gSe11bvhEpcHI3lT-3ipTM8JosiZbrwt4D/s1600/2014-10-10+01-11-44+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; height=&quot;266&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
На первом шаге случайно размещены два центроида (изображены темными кружками). На втором шаге каждый элемент приписан к ближайшему центроиду. В данном случае A и B приписаны к верхнему центроиду, а C, D и E – к нижнему. На третьем шаге каждый центроид перемещен в точку, рассчитанную как среднее по всем приписанным к нему элементам. После пересчета назначений оказалось, что C теперь ближе к верхнему центроиду, а D и E – по-прежнему ближе к нижнему. Окончательный результат достигается, когда A, B и C помещены в один кластер, а D и E – в другой.
    &lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;
В данном методе, ОЧЕНЬ важен выбор центроидов, т.к. в конечном итоге все точки к ним стянутся, но если все 4 будут очень близкие цвета и из них будут состоять большие области, то в конечном итоге вы и получите приблизительно одинаковые центры. Таким образом центроиды должны быть максимально разнесены (желательно равномерно и равноудаленно).&lt;br /&gt;
&lt;br /&gt;
Для большего понимания приведу пример. Давайте рассмотрим такую картинку.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzQ0o_N8uJndnwCfA-_9oJnSKBYBwTagueui37rRJ8MEjq8auEYICj4o3gJk0ZDMlVlM7nJgHvzAT7QIAmTdNiS8r5QR5w5-fZitJ6JIPCtHaAd2CrHSJjfeHyVNbh5Av2D_2qBdhi/s1600/test2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzQ0o_N8uJndnwCfA-_9oJnSKBYBwTagueui37rRJ8MEjq8auEYICj4o3gJk0ZDMlVlM7nJgHvzAT7QIAmTdNiS8r5QR5w5-fZitJ6JIPCtHaAd2CrHSJjfeHyVNbh5Av2D_2qBdhi/s1600/test2.png&quot; height=&quot;176&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Чтобы решить поставленную задачу в такой, монотонной четко разделенной картинке, достаточно написать небольшой код:&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def k_cluster_by_area(points, k=4):

 clusters_by_area = {}

 for point in points:
  clusters_by_area[point] = clusters_by_area.setdefault(point, 0) + 1

 sorted_x = sorted(clusters_by_area.items(), key=operator.itemgetter(1))

 return sorted_x[-k:]
&lt;/pre&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;
Тут мы просто посчитали, сколько раз, какой цвет встречается, отсортировали и вывели k результатов. Этот метод можно применить к любому изображению, работает достаточно быстро, но есть НО! А именно, мы не получим ТОНАЛЬНОСТЬ картинки! Однако, как я писал выше, в нашей задаче важны центры, вот эту задачу и решает этот код!) Мы берем самые популярные цвета, за изначальные центры кластеров, а потом они постепенно мутируют) На самом деле, желательно брать не просто первые k, а посчитать все комбанации расстояний и выбрать k по макс расстояниям, чтобы центры не оказались рядом (например 2 оттенка серого). Но мне влом и вы сделаете это сами)&lt;br /&gt;
&lt;br /&gt;
Надеюсь, стало яснее. Таким образом, как найти изначальные центры кластеров нам известно, осталось только свести все пиксели в эти точки. &amp;nbsp;А теперь сам код:&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def k_cluster(img, distance=euclidean, k=4):
 
 points = get_points(img)
 clusters = {}

 # центры кластеры
 cluster_centers = k_cluster_by_area(points, k)
 for cluster_center in cluster_centers:
  # avg_sum_coords - список сумм r, g, b координат всех пикселей кластера
  # count_points - кол-во пикселей в кластере
  # какие конкретно пиксели в кластере не запоминаем в целях экономии памяти и времени
  clusters[cluster_center] = {&#39;avg_sum_coords&#39;:list(cluster_center), &#39;count_points&#39;:1}

 while len(points):

  # находим ближайшие точки к центрам кластеров
  bestmatches = {}
  for point in points:

   # расстояние каждой точки до каждого центра кластера
   for cluster_center in clusters:
    d = distance(cluster_center, point)
    if not bestmatches:
     bestmatches = {&#39;distance&#39;:d, &#39;point&#39;: point, &#39;cluster_center&#39;: cluster_center}

    if d &amp;lt; bestmatches[&#39;distance&#39;]:
     bestmatches = {&#39;distance&#39;: d, &#39;point&#39;: point, &#39;cluster_center&#39;: cluster_center}

  # перекидываем ближайшие точки в соответствующий кластер
  bestmatch = bestmatches[&#39;point&#39;]
  cluster_center = bestmatches[&#39;cluster_center&#39;]
  points2 = []
  new_points = []

  for point in points:
   if point == bestmatch:
    new_points.append(point)
   else:
    points2.append(point)


  points = points2[:]

  # меняем центр кластера
  print clusters.keys(), len(points)

  r_avg, g_avg, b_avg = 0, 0, 0
  cluster_avg_coord = clusters[cluster_center][&#39;avg_sum_coords&#39;]

  new_points_len = len(new_points)
  clusters[cluster_center][&#39;count_points&#39;] += new_points_len
  claster_count_points = clusters[cluster_center][&#39;count_points&#39;]

  cluster_avg_coord[0] += bestmatch[0]*new_points_len
  cluster_avg_coord[1] += bestmatch[1]*new_points_len
  cluster_avg_coord[2] += bestmatch[2]*new_points_len


  new_center = cluster_avg_coord[0]/claster_count_points, cluster_avg_coord[1]/claster_count_points, cluster_avg_coord[2]/claster_count_points
  
  # если новый центр кластера отличается от предыдущего
  if not new_center in clusters:
   clusters[new_center] = clusters.pop(cluster_center)

 return clusters.keys()
&lt;/pre&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;
Работает это дело не быстро ;(, поэтому я советую сжимать картинку, хотя бы до разрешения 100 на 100.&lt;br /&gt;
Понятно, что идея не нова и сравнить вы можете, например с данным сайтом &lt;a href=&quot;http://design-seeds.com/&quot;&gt;http://design-seeds.com&lt;/a&gt;&lt;br /&gt;
Давайте разберем пример. С указанного выше сайта взяли картинку и их разбиение на цвета. Здесь можно заметить, что их задача - это выбрать основные центровые цвета, что немного отличается от нашей задачи, но все же.&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRRAqgAFMV6cf28pAL3HNJaYBpM_cMJYGM34OnWCTDObt4bjgIHNjobOqHkUllQWXgHLO1mXpGCaU-HzJeJryr__cj9C0YAPCSfdzwgNpmb71LXV27sRsfq67mzpGn6bNkt3bm1Rjr/s1600/2014-10-13+02-02-55+Design+Seeds%C2%AE+%7C+for+all+who+%E2%9D%A4+color+%7C+dried+hues.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRRAqgAFMV6cf28pAL3HNJaYBpM_cMJYGM34OnWCTDObt4bjgIHNjobOqHkUllQWXgHLO1mXpGCaU-HzJeJryr__cj9C0YAPCSfdzwgNpmb71LXV27sRsfq67mzpGn6bNkt3bm1Rjr/s1600/2014-10-13+02-02-55+Design+Seeds%C2%AE+%7C+for+all+who+%E2%9D%A4+color+%7C+dried+hues.png&quot; height=&quot;378&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Пример с сайта&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Сначала посмотрим на наш метод выбора первоначальных центров, исходя из предположения простого количественного показателя использования цветов. Изначальные центры ниже подписано, сколько раз цвет встречался на картинке.&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiV3mjY2LgN_vVWQoHuCy2V5eTv04UmfJI3QSXWa48EPopzup1FIV4om6jBxdNcEDSaJ5P3p8GYONdnEoIYXvQZSkxJe38Cl4v2H1wIoFJElbNpTaf9vSeL_SngeMrOV1ZUrXpT1XQX/s1600/2014-10-13+02-52-49+%231f1317+Color+Hex.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiV3mjY2LgN_vVWQoHuCy2V5eTv04UmfJI3QSXWa48EPopzup1FIV4om6jBxdNcEDSaJ5P3p8GYONdnEoIYXvQZSkxJe38Cl4v2H1wIoFJElbNpTaf9vSeL_SngeMrOV1ZUrXpT1XQX/s1600/2014-10-13+02-52-49+%231f1317+Color+Hex.png&quot; height=&quot;82&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;7 раз&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; margin-right: 1em; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeTOtXt4UHU4gJYsSED0fOnNQgO5eFBX-JhIXesVDqYUaL3CpKdXQr2td71Yp5L7reE_mjLMFvfEio24UzwkMGI01rnowGDOakrkCkXDyF9ZssLDfcCQSd4HzOMdImImRNd_icWllY/s1600/2014-10-13+02-51-35+%23130b11+Color+Hex.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeTOtXt4UHU4gJYsSED0fOnNQgO5eFBX-JhIXesVDqYUaL3CpKdXQr2td71Yp5L7reE_mjLMFvfEio24UzwkMGI01rnowGDOakrkCkXDyF9ZssLDfcCQSd4HzOMdImImRNd_icWllY/s1600/2014-10-13+02-51-35+%23130b11+Color+Hex.png&quot; height=&quot;83&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;4 раза&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6KB9JERm5EBSrdgCwf0jHg2OkG_fNH1aghSS5owFhVSEk4xp5mdtt8BMAjolXoQaGhlzcaMb4rgGnQNLNmrU8MFx0cq1dkTiywgTRtFby0ivERGR8sbCXga4TCYR9xL4GmfvA0Q7L/s1600/2014-10-13+02-51-51+%231c121d+Color+Hex.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6KB9JERm5EBSrdgCwf0jHg2OkG_fNH1aghSS5owFhVSEk4xp5mdtt8BMAjolXoQaGhlzcaMb4rgGnQNLNmrU8MFx0cq1dkTiywgTRtFby0ivERGR8sbCXga4TCYR9xL4GmfvA0Q7L/s1600/2014-10-13+02-51-51+%231c121d+Color+Hex.png&quot; height=&quot;85&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;4 раза&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; margin-right: 1em; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuf6dlpgMPw-rAN-ccyuBMln9-hCTpGl8tor1TDQ_toz1wwx8mi2o0YRZh55KTdWIid5bMbRRx_P1BPOmE11SJcU5mFv362hsfS85O9Jz0Bpc3h6ORVOvn98H2S-5rfHYmbD_ECgZw/s1600/2014-10-13+02-52-08+%2314161d+Color+Hex.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuf6dlpgMPw-rAN-ccyuBMln9-hCTpGl8tor1TDQ_toz1wwx8mi2o0YRZh55KTdWIid5bMbRRx_P1BPOmE11SJcU5mFv362hsfS85O9Jz0Bpc3h6ORVOvn98H2S-5rfHYmbD_ECgZw/s1600/2014-10-13+02-52-08+%2314161d+Color+Hex.png&quot; height=&quot;85&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;4 раза&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieMTktftpoIWdntEx7UP_ruO81J0g4CtBoKQrV6deq89uqAizV01jN1UdmUUM4tjD_tWmVKFE4o62KUvv6TcUQk_sDL2MDvHPAadu7D6beF3cjZ0y7S7NrcaPLi986KnV73mfe_8tD/s1600/2014-10-13+02-52-24+%23130b0f+Color+Hex.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieMTktftpoIWdntEx7UP_ruO81J0g4CtBoKQrV6deq89uqAizV01jN1UdmUUM4tjD_tWmVKFE4o62KUvv6TcUQk_sDL2MDvHPAadu7D6beF3cjZ0y7S7NrcaPLi986KnV73mfe_8tD/s1600/2014-10-13+02-52-24+%23130b0f+Color+Hex.png&quot; height=&quot;84&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;5 раз&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3v_rwcZZg_18pRMqqghpL2W87LQGLC8LnASE9YOrNWdRee5dJ8pkN8zdnpmBMmspi6SksZOW1fyYVz3XPS4XOphukRbJNFFFN05hctpqQRuEd0mhG8HYGliJ1IcRX_ugPbWeUqUIv/s1600/2014-10-13+02-53-10+%231f161a+Color+Hex.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3v_rwcZZg_18pRMqqghpL2W87LQGLC8LnASE9YOrNWdRee5dJ8pkN8zdnpmBMmspi6SksZOW1fyYVz3XPS4XOphukRbJNFFFN05hctpqQRuEd0mhG8HYGliJ1IcRX_ugPbWeUqUIv/s1600/2014-10-13+02-53-10+%231f161a+Color+Hex.png&quot; height=&quot;85&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;6 раз&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;hr style=&quot;clear: both;&quot; /&gt;
Ммммм, кто бы сказал по картинке, что это самые часто встречающиеся цвета? Понятно, что это вызвано так же и сжатием до 100 пикселей по меньшей из сторон, но все же. Сразу можно сказать, что притягивать к таким центрам остальные цвета сложно. В результате:&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; margin-right: 1em; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPTIiidQ7V4mFM0tLpgTOaQ5WwwUDgTyLn5P5Zco7CxhR1SJWvQyY8fLEY3uD_PxGwyO9urH6LEEAfDBtJbVcuBPxSapcAnBSblOQxtFe0hwpgXSLpPKwUMmOU8xxTsDcy8N-E7Ki4/s1600/2014-10-13+03-13-03+%23200d13+Color+Hex.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPTIiidQ7V4mFM0tLpgTOaQ5WwwUDgTyLn5P5Zco7CxhR1SJWvQyY8fLEY3uD_PxGwyO9urH6LEEAfDBtJbVcuBPxSapcAnBSblOQxtFe0hwpgXSLpPKwUMmOU8xxTsDcy8N-E7Ki4/s1600/2014-10-13+03-13-03+%23200d13+Color+Hex.png&quot; height=&quot;84&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYyU2vdXv6p4JYlhEWwYysMb-JjZDSMIwCoIp69NBoyIjLoE-intvlPmNpWY_abKMV8ts1cOumc1kkbg4AMJhi-2Agnrhyphenhyphenug1BUWkr40y6XQYYEKneH8tfwanJd1VipimgWAN8szrH/s1600/2014-10-13+03-14-00+%23684a44+Color+Hex.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYyU2vdXv6p4JYlhEWwYysMb-JjZDSMIwCoIp69NBoyIjLoE-intvlPmNpWY_abKMV8ts1cOumc1kkbg4AMJhi-2Agnrhyphenhyphenug1BUWkr40y6XQYYEKneH8tfwanJd1VipimgWAN8szrH/s1600/2014-10-13+03-14-00+%23684a44+Color+Hex.png&quot; height=&quot;83&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2VP1_m5bdkO7HIQfEkgfQ943IaCWwbWXFlbMcn2ESYNRWg84a6mRXaQUs0c0YF48yuuUoXk-z636LrSca8VyPzY0lsR_l0cTzxe8sX3nohZSUoakpzHzLSx8fbYTLJpbxqEQgLbpw/s1600/2014-10-13+03-13-42+%231a121c+Color+Hex.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2VP1_m5bdkO7HIQfEkgfQ943IaCWwbWXFlbMcn2ESYNRWg84a6mRXaQUs0c0YF48yuuUoXk-z636LrSca8VyPzY0lsR_l0cTzxe8sX3nohZSUoakpzHzLSx8fbYTLJpbxqEQgLbpw/s1600/2014-10-13+03-13-42+%231a121c+Color+Hex.png&quot; height=&quot;84&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; margin-right: 1em; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5Dswie1UGdAl38HdzLEUyl_AErrjImDmPr2xpKkkcdTK5FfLVt_x1zfX7zUNvOr6Iioey9cKE2rYHxCwHS_Am9a78J9AWiwI4e69p19yZb0t3BAKZo2ElJQWGkqD-6c8YGAvcf8dt/s1600/2014-10-13+03-14-20+%23140b11+Color+Hex.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5Dswie1UGdAl38HdzLEUyl_AErrjImDmPr2xpKkkcdTK5FfLVt_x1zfX7zUNvOr6Iioey9cKE2rYHxCwHS_Am9a78J9AWiwI4e69p19yZb0t3BAKZo2ElJQWGkqD-6c8YGAvcf8dt/s1600/2014-10-13+03-14-20+%23140b11+Color+Hex.png&quot; height=&quot;82&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0CJLGpXDF4fHn5Vrb95AkJJETkwWmwfSCitga718RUBU0ZvfJm8vbtsS9bYn-lwgvqh6e6WGLioRgSp7Xbb62Lm1kNxm_dwAw5gDqy3KsRzPJHR1IjE9wXVfjuXPLKv12oGN9f2Xh/s1600/%D0%9A%D0%BE%D0%BF%D0%B8%D1%8F+2014-10-13+02-42-57+%23130b0f+Color+Hex.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0CJLGpXDF4fHn5Vrb95AkJJETkwWmwfSCitga718RUBU0ZvfJm8vbtsS9bYn-lwgvqh6e6WGLioRgSp7Xbb62Lm1kNxm_dwAw5gDqy3KsRzPJHR1IjE9wXVfjuXPLKv12oGN9f2Xh/s1600/%D0%9A%D0%BE%D0%BF%D0%B8%D1%8F+2014-10-13+02-42-57+%23130b0f+Color+Hex.png&quot; height=&quot;83&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0rt705_L2MC2uwIrvg8_fOOx1MQH2d5cy-TwD74YTbaaU44ZrrjNyPRgN4lV-Vtd94T1O-pruFf2tW-3t62tCMA7B51Ky_ktS3lnujqZzB3N02-OMV6AZKrDrk1WlJqoYIMEbzsW0/s1600/2014-10-13+03-13-25+%2310070d+Color+Hex.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0rt705_L2MC2uwIrvg8_fOOx1MQH2d5cy-TwD74YTbaaU44ZrrjNyPRgN4lV-Vtd94T1O-pruFf2tW-3t62tCMA7B51Ky_ktS3lnujqZzB3N02-OMV6AZKrDrk1WlJqoYIMEbzsW0/s1600/2014-10-13+03-13-25+%2310070d+Color+Hex.png&quot; height=&quot;83&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;hr style=&quot;clear: both;&quot; /&gt;
Все плохо, как и следовало ожидать. А что если попробовать представить спектр цветов в виде прямой от 0 до 255, равномерно разбить его на k отрезков и сделать центры точками с одинаковыми равномерными координатами? По понятным причинам они все будут оттенками серого. Пример для 6:&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; margin-right: 1em; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_0x3doaQbggQZYhNPoiFpwRtNiA5AvOwMeGzVYGqi3YDkis_AkZr8qpuf7x3p56j8kj62sx-0zJb-d2MmNv62lkEgVEeukB8heSNKF6yJIj5Sml28kzBf5MP5RjIuhwtFooJPXfnR/s1600/2014-10-13+03-24-07+%23000000+Color+Hex+Black+%23000.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_0x3doaQbggQZYhNPoiFpwRtNiA5AvOwMeGzVYGqi3YDkis_AkZr8qpuf7x3p56j8kj62sx-0zJb-d2MmNv62lkEgVEeukB8heSNKF6yJIj5Sml28kzBf5MP5RjIuhwtFooJPXfnR/s1600/2014-10-13+03-24-07+%23000000+Color+Hex+Black+%23000.png&quot; height=&quot;83&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHxwfXa1jgEj1iKlNySJSv2z3oaBvw9MyMwrJcb9jXgA4Xm87gm-1pIUJoPIzqrT1hJUnX6NjgYmNnxs8iCl5dvmcLEgMBLKEwlgOcz0sj78L11GXFX8tTlLBLsMN5wDcAvC3c9tLT/s1600/2014-10-13+03-24-37+%23333333+Color+Hex+Gray20+%23333.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHxwfXa1jgEj1iKlNySJSv2z3oaBvw9MyMwrJcb9jXgA4Xm87gm-1pIUJoPIzqrT1hJUnX6NjgYmNnxs8iCl5dvmcLEgMBLKEwlgOcz0sj78L11GXFX8tTlLBLsMN5wDcAvC3c9tLT/s1600/2014-10-13+03-24-37+%23333333+Color+Hex+Gray20+%23333.png&quot; height=&quot;85&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; margin-right: 1em; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwue-0JYcZlFhYGTyiJTuXSb3RX9h8fxdY2kXY3JIlaIagHOMAdqtcP8-6C6w1uQzblxAb_8IxtkRdBtUG5BeQI-I3IVWZwP6vtuEP4oVhNQnjfHgWWfWwYDcyVKnvrJH_B3UaObqK/s1600/2014-10-13+03-24-22+%23ffffff+Color+Hex+White+%23FFF.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwue-0JYcZlFhYGTyiJTuXSb3RX9h8fxdY2kXY3JIlaIagHOMAdqtcP8-6C6w1uQzblxAb_8IxtkRdBtUG5BeQI-I3IVWZwP6vtuEP4oVhNQnjfHgWWfWwYDcyVKnvrJH_B3UaObqK/s1600/2014-10-13+03-24-22+%23ffffff+Color+Hex+White+%23FFF.png&quot; height=&quot;84&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzqtFEudCFeMJgC1tlHXgUXNLTH2q-jyfAw2ZZuCc5w5Va9Qa3b8UX_kudLBmjO6P2ClnTjlllYu5liyreRlCf_htbxSkbRsasadeal4oQ6WSa9lFvmsgdcs1GVHKKB4TW5Zx0lE55/s1600/2014-10-13+03-24-54+%23666666+Color+Hex+Gray40+%23666.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzqtFEudCFeMJgC1tlHXgUXNLTH2q-jyfAw2ZZuCc5w5Va9Qa3b8UX_kudLBmjO6P2ClnTjlllYu5liyreRlCf_htbxSkbRsasadeal4oQ6WSa9lFvmsgdcs1GVHKKB4TW5Zx0lE55/s1600/2014-10-13+03-24-54+%23666666+Color+Hex+Gray40+%23666.png&quot; height=&quot;81&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRuFN4gzOFHU2aScMiBP1levC9f3mERuTfpoYom79zCmwpkVJoeJwXX_IOiSBLTHcoh5QmvgQHJc1IGUKRT4VuNwdrqZCAPGJWT_VrPqAU7siOuXj08K19mLwEzmVM4aBwgfa80F_M/s1600/2014-10-13+03-25-10+%23999999+Color+Hex+Gray60+%23999.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRuFN4gzOFHU2aScMiBP1levC9f3mERuTfpoYom79zCmwpkVJoeJwXX_IOiSBLTHcoh5QmvgQHJc1IGUKRT4VuNwdrqZCAPGJWT_VrPqAU7siOuXj08K19mLwEzmVM4aBwgfa80F_M/s1600/2014-10-13+03-25-10+%23999999+Color+Hex+Gray60+%23999.png&quot; height=&quot;83&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTTdueqG47c28LLoVwxyAqThXacwwo_-FBrlTbaW5ZnWqIWvzFtj2ZXcWE-aC7S12Dss0uCx8zImatyljaEWZ44MISOxZWlVqfWp7It-DKuUjzGfNLrZwzj5vTh20iNv-nXF9ySNP7/s1600/2014-10-13+03-25-28+%23cccccc+Color+Hex+Gray80+%23CCC.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTTdueqG47c28LLoVwxyAqThXacwwo_-FBrlTbaW5ZnWqIWvzFtj2ZXcWE-aC7S12Dss0uCx8zImatyljaEWZ44MISOxZWlVqfWp7It-DKuUjzGfNLrZwzj5vTh20iNv-nXF9ySNP7/s1600/2014-10-13+03-25-28+%23cccccc+Color+Hex+Gray80+%23CCC.png&quot; height=&quot;85&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;hr style=&quot;clear: both;&quot; /&gt;
В результате:&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; margin-right: 1em; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMlEqsqHijKDU5TFohyXaXBgg3_z-h_WhNiXUCHxDFLZbFXHUNsVuE8grRNpINmIAAA28oW6T6NNRrBgoGHkvMdmHg3G7ok66ESjnkO5fy7uvUSr3QVeIer6sEUzeZEd_aAMN9PJHp/s1600/2014-10-13+03-21-46+%23332026+Color+Hex.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMlEqsqHijKDU5TFohyXaXBgg3_z-h_WhNiXUCHxDFLZbFXHUNsVuE8grRNpINmIAAA28oW6T6NNRrBgoGHkvMdmHg3G7ok66ESjnkO5fy7uvUSr3QVeIer6sEUzeZEd_aAMN9PJHp/s1600/2014-10-13+03-21-46+%23332026+Color+Hex.png&quot; height=&quot;83&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEho9BCCLSkkusZ-tTUPekNwQ-reAJT4pDp_Z3iYzTtfmsWE2SnkmkI3bVdfSyca7RjfqcFHAzWnyNGX5Zw90_NSyONeuQ8ye2C9yZgPbFEkg64Ce0PNZSFgn3LIKGbfBW4RtMlueBj8/s1600/2014-10-13+03-22-20+%23fae8cb+Color+Hex.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEho9BCCLSkkusZ-tTUPekNwQ-reAJT4pDp_Z3iYzTtfmsWE2SnkmkI3bVdfSyca7RjfqcFHAzWnyNGX5Zw90_NSyONeuQ8ye2C9yZgPbFEkg64Ce0PNZSFgn3LIKGbfBW4RtMlueBj8/s1600/2014-10-13+03-22-20+%23fae8cb+Color+Hex.png&quot; height=&quot;85&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5Q-8CjAF0y5UvQ4n0jXEOi6qSrKIjJCS-UqIE5sBpT5BQxH5CXv0gHNS_b72fJy0cEyyk-6ADVh5ivZuPerI114laae1-K7Ov1C_6SSqwZ0vx4nDfvQVqYH3yq5aTqWtACaS2GhYB/s1600/2014-10-13+03-22-42+%23694644+Color+Hex.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5Q-8CjAF0y5UvQ4n0jXEOi6qSrKIjJCS-UqIE5sBpT5BQxH5CXv0gHNS_b72fJy0cEyyk-6ADVh5ivZuPerI114laae1-K7Ov1C_6SSqwZ0vx4nDfvQVqYH3yq5aTqWtACaS2GhYB/s1600/2014-10-13+03-22-42+%23694644+Color+Hex.png&quot; height=&quot;83&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; margin-right: 1em; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw0iN1UfUih8i-Hf3kJcugOMhN87IhgHy-fADZe0qWmFMywq_UcCAeVecXrLaJzeL6b1JDUhqispdHjH1ZkjNhFMD-RmlMPk_jXRaUzvG9VTuVQIa0OC12vuHbsWxKK5eOB0b3kpUu/s1600/2014-10-13+03-22-03+%23d3774d+Color+Hex.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw0iN1UfUih8i-Hf3kJcugOMhN87IhgHy-fADZe0qWmFMywq_UcCAeVecXrLaJzeL6b1JDUhqispdHjH1ZkjNhFMD-RmlMPk_jXRaUzvG9VTuVQIa0OC12vuHbsWxKK5eOB0b3kpUu/s1600/2014-10-13+03-22-03+%23d3774d+Color+Hex.png&quot; height=&quot;83&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiokFSZr_s6AFkpFQS2pvng0dBoh8JDn2zuX6XFF20VK5u8eO0CIIuTFfHP3JSQe2I8E8kFHibcvRQucjF4xsVuA73mQXS6uHLbCBvgS5veESSN_0PsuJfP4eLaIdTSbE7ug7i4Pm_w/s1600/2014-10-13+03-23-11+%23180d13+Color+Hex.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiokFSZr_s6AFkpFQS2pvng0dBoh8JDn2zuX6XFF20VK5u8eO0CIIuTFfHP3JSQe2I8E8kFHibcvRQucjF4xsVuA73mQXS6uHLbCBvgS5veESSN_0PsuJfP4eLaIdTSbE7ug7i4Pm_w/s1600/2014-10-13+03-23-11+%23180d13+Color+Hex.png&quot; height=&quot;81&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYTRrdTCkQCDDazVGh9TVZse2YlK9I0s49JpA0qINRTD1jCoJxAya7atQqHoy2uBiWtF4nVzjqqyN0ttlK8VPpJ1o5iZPTBAVxZWoN_HlnWvsrtkTpoKh2tbPJ7rJNHg9iMtFW4igN/s1600/2014-10-13+03-23-27+%237d7a70+Color+Hex.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYTRrdTCkQCDDazVGh9TVZse2YlK9I0s49JpA0qINRTD1jCoJxAya7atQqHoy2uBiWtF4nVzjqqyN0ttlK8VPpJ1o5iZPTBAVxZWoN_HlnWvsrtkTpoKh2tbPJ7rJNHg9iMtFW4igN/s1600/2014-10-13+03-23-27+%237d7a70+Color+Hex.png&quot; height=&quot;82&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;hr style=&quot;clear: both;&quot; /&gt;
Вот, уже лучше) Однако, чем плох этот метод? А тем, что этих цветов может и не быть на картинке (она может просто красная), получается, что изначально мы как бы сбиваем мишень(&lt;br /&gt;
&lt;br /&gt;
Как вывод, могу сказать, что метод k-средних очень чувствителен к этим самы центроидам. И их поиск - это не менее важная задача, которую я Вам и предлагаю решить) Например, представьте что вы как бы объединяете точки, расширяя территории. Объединяя их в 3х мерном пространстве линейно увеличивая координаты. И без учета количественных показателей весов!)&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/3733609072724037117/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2014/10/blog-post_12.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/3733609072724037117'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/3733609072724037117'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2014/10/blog-post_12.html' title='Кластеризация данных'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqAKXsO8VU-lguNf91Dnmc5o9lSEIRwqA8cQER4CtXUYm5_-QEUpTbruIQi2WhyphenhyphenNi7zwuwL5OWjGgsLda9cMLwXvOOpsRbuXyQLnzqKeeg5pyU_cTNuqm_RlHwtx9uOrQ4FF35S_HT/s72-c/2014-10-10+00-58-14+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-2061651443807496676</id><published>2014-10-08T15:09:00.001-07:00</published><updated>2014-10-14T03:13:32.885-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Машинное обучение"/><title type='text'>Обучение нейронной сети</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://www.zankov.ru/images/_user/otcratka/Start/UUD2_1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://www.zankov.ru/images/_user/otcratka/Start/UUD2_1.jpg&quot; height=&quot;320&quot; width=&quot;225&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 99&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
Одно из основных достоинств онлайновых приложений состоит в том, что они все время получают обратную связь в виде поведения пользователей. В случае поисковой машины каждый пользователь тут же сообщает о том, насколько ему понравились результаты поиска, щелкая по одному результату и игнорируя остальные. Мы рассмотрим способ регистрации действий пользователя после получения результатов и то, как собранную таком образом информацию можно применить для более качественного ранжирования результатов. &lt;span style=&quot;font-family: &#39;SchoolBookC-Identity-H&#39;; font-size: 10.000000pt;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Итак, для тех, кто справился с &lt;a href=&quot;http://py-algorithm.blogspot.ru/2014/10/blog-post.html&quot;&gt;предыдущей статьей&lt;/a&gt;, создал и запустил своего поискового робота, сегодня мы построим и обучим&amp;nbsp;&lt;i&gt;искусственную нейронную сеть. &lt;/i&gt;Предлагая ей поисковой запрос, &amp;nbsp;результаты обработки запроса и ту ссылку, по которой пользователь пе- решел, мы научим нейронную сеть, как использовать для упорядочения результатов поиска, реальный выбор пользователя.&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Проектирование сети отслеживания переходов&lt;/h3&gt;
Есть много разновидностей нейронных сетей, но все они состоят из множества узлов (нейронов) и связей между ними (синапсов). Мы собираемся построить MLP сеть (multilayer perceptron). Такая сеть состоит из нескольких уровней нейронов, первый из которых принимает входные данные – в данном случае поисковой запрос. Последний уровень возвращает результаты – список весов найденных URL. 
   &lt;/div&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Промежуточных уровней может быть много, но мы ограничимся только одним. Он называется скрытым уровнем, так как не взаимодействует напрямую с внешним миром, а реагирует на комбинации входных данных.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMyJf1NQI6Jrzc6JnR1lfEr8spaIaRmG_IiSGEYwJWkmyNWVjfAkZvQTGPlIv2kfyAFvkh1xFVbSe0epVhipkQhnS_fxdHh1OcmdSfv9L9BjxETwz2lggaFOdOiQHVht9rfD_HXYwz/s1600/2014-10-06+22-12-44+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMyJf1NQI6Jrzc6JnR1lfEr8spaIaRmG_IiSGEYwJWkmyNWVjfAkZvQTGPlIv2kfyAFvkh1xFVbSe0epVhipkQhnS_fxdHh1OcmdSfv9L9BjxETwz2lggaFOdOiQHVht9rfD_HXYwz/s1600/2014-10-06+22-12-44+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; height=&quot;127&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Общий принцип таков, значения входных узлов для указанных в запросе слов устанавливают равными 1. Включаются выходы этих узлов, и они пытаются активировать скрытый слой. В свою очередь, узлы скрытого слоя, получающие достаточно сильный входной сигнал, включают свои выходы и пытаются активировать узлы выходного уровня.&amp;nbsp;
  
 
 
  Узлы выходного уровня оказываются активны в разной степени, и по уровню их активности можно судить, как сильно данный URL ассоциирован со словами исходного запроса.&amp;nbsp;
  
 
 
  Разумеется, для этого необходимо, чтобы сила связей была установлена правильно. Это достигается обучением сети всякий раз, как кто-то выполняет поиск и выбирает один из результатов.&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjawLtPZJ4sSCaUZhLB76nsE01BfGqkqL4QqvbCr9M1GQUao0YtVLVAQVrWplBdv345SJhewVCEvaFJQhMWlj1xTdCRur4Cog1e269W8vGiHJhYiR1TymeQf7b1d8P01SJ1G8yur41/s1600/2014-10-06+22-23-07+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjawLtPZJ4sSCaUZhLB76nsE01BfGqkqL4QqvbCr9M1GQUao0YtVLVAQVrWplBdv345SJhewVCEvaFJQhMWlj1xTdCRur4Cog1e269W8vGiHJhYiR1TymeQf7b1d8P01SJ1G8yur41/s1600/2014-10-06+22-23-07+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; height=&quot;210&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Уровни в БД: &amp;nbsp; &amp;nbsp; &amp;nbsp;word_list &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; word_hidden &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; hidden_node &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; hidden_urls &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;url_list &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;. &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div&gt;
Как пример,&amp;nbsp;
  
 
 
  в сети, изображенной на рисунке выше, сколько-то человек переходили на сайт Всемирного банка (World Bank) после запроса world bank, и это усилило ассоциацию между данными словами и URL.&amp;nbsp;Сплошными линиями показаны сильные связи, а полужирный текст говорит о том, что узел стал очень активным.&lt;/div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 100&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
Мы будем обучать сеть с помощью алгоритма обратного распространения &lt;i&gt;backpropagation&lt;/i&gt;. &amp;nbsp; &lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Прошу обратить внимание на подпись под картинкой. Каждый уровень (прямоугольничек или стрелочка) имеет свое отображение в БД. Я подписал названия таблиц им соответствующих, для большего понимания, что мы будем делать, но если сейчас Вам что-то не очень понятно, вернитесь к прочтению данного принципа, после описания механизма работы и все встанет на свои места!)&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Подготовка базы данных&lt;/h3&gt;
&lt;div&gt;
У тех, кто осилил &lt;a href=&quot;http://py-algorithm.blogspot.ru/2014/10/blog-post.html&quot;&gt;прошлую статью&lt;/a&gt;, уже есть 2 таблицы - это word_list и url_list, где хранятся списки слов и урлов, соответственно. Теперь нужно еще 3: 1 - hidden_node (скрытый слой) и 2 таблицы связи с ним&amp;nbsp;(одна hidden_word – для связей между слоем слов и скрытым слоем, другая hidden_url – для связей между скрытым и выходным слоем).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Нам потребуется два метода для доступа к базе данных. Первый, get_strength, определяет текущую силу связи. Поскольку новые связи создаются только по мере необходимости, этот метод должен возвращать некое специальное значение, если связей еще нет. Для связей между словами и скрытым слоем мы выберем в качестве такого значения –0,2, так что по умолчанию дополнительные слова будут несколько снижать уровень активации скрытого узла. Для связей между скрытым слоем и URL метод по умолчанию будет возвращать значение 0.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt; def get_strength(self, from_id, to_id, layer):

  if layer == 0: 
   table = &#39;word_hidden&#39;
  else: 
   table = &#39;hidden_url&#39;

  self.cur.execute(&#39;select strength from %s where from_id = %d and to_id = %d&#39; % (table, from_id, to_id))
                res = self.cur.fetchone()

  if res == None: 
   if layer == 0: 
    return -0.2

   if layer == 1: 
    return 0
    
  return res[0]
&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 101&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
Еще необходим метод set_strength, который выясняет, существует ли уже связь, и создает либо обновляет связь, приписывая ей заданную силу. Он будет использоваться в коде для обучения сети:
  
 
 
  &lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt; def set_strength(self, from_id, to_id, table, strength):

  self.cur.execute(&#39;select id from %s where from_id = %d and to_id = %d&#39; % (table, from_id, to_id))
  res = self.cur.fetchone()

  if res == None: 
   self.cur.execute(&#39;insert into %s (from_id, to_id, strength) values (%d, %d, %f)&#39; % (table, from_id, to_id, strength))
  else:
   row_id = res[0]
   self.cur.execute(&#39;update %s set strength = %f where id = %d&#39; % (table, strength, row_id))

  self.db_commit()
&lt;/pre&gt;
Можно было бы предварительно создать гигантскую сеть с тысячами узлов в скрытом слое и уже готовыми связями, но мы с Вами будем создавать скрытые узлы, когда в них возникает надобность. &lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Следующая функция создает новый скрытый узел всякий раз, как ей передается не встречавшаяся ранее комбинация слов. Затем она создает связи с весами по умолчанию (для url сила маленькая, т.к. сеть не обучена, пусть 0.1, а для слов в сумме = 1) между этими словами и скрытым узлом и между узлом запроса и URL, который этот запрос возвращает. &lt;/div&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt; def generate_hidden_node(self, word_ids, urls):

                # Для простоты ограничимся 2-х словными фразами
  if len(word_ids) &amp;gt; 3: 
   return None

  # Проверить, создавали ли мы уже узел для данного набора слов
  sorted_words = map(str, word_ids)
  sorted_words.sort()
  create_key = &#39;_&#39;.join(sorted_words)
  self.cur.execute(&quot;select count(id) from hidden_node where create_key = &#39;%s&#39;&quot; % create_key)
  count_hidden_id = self.cur.fetchone()

  # Если нет, создадим сейчас
  if not count_hidden_id:
   self.cur.execute(&quot;insert into hidden_node (create_key) values (&#39;%s&#39;)  returning hidden_node.id&quot; % create_key)
   hidden_id = self.cur.fetchone()[0]

   # Задать веса по умолчанию
   for word_id in word_ids:
    self.set_strength(word_id, hidden_id, &#39;word_hidden&#39;, 1.0/len(word_ids))

   for url_id in urls:
    self.set_strength(hidden_id, url_id, &#39;hidden_url&#39;, 0.1)

   self.db_commit()
&lt;/pre&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Прямой проход&lt;/h3&gt;
Теперь все готово для написания функций, которые принимают на входе слова, активируют связи в сети и формируют выходные сигналы для URL. &lt;/div&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Для начала выберем функцию, которая описывает, с какой силой каждый узел должен реагировать на входной сигнал. В нашем примере сети мы воспользуемся для этого функцией гиперболического тангенса (tanh), график которой изображен ниже.&lt;/div&gt;
&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLxzpMlf618H5znuDbwRYK9jTHcapYMay17qeIHaTeLgIYWPdxhdS6A36Hm8xZIOQqK84jC0M_pNff63itef3PTrRoYaOshx1dj8Jb8KtxMwNzp6MN4RraWsUQ2PVkXnr-31McYfXq/s1600/2014-10-08+01-14-38+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLxzpMlf618H5znuDbwRYK9jTHcapYMay17qeIHaTeLgIYWPdxhdS6A36Hm8xZIOQqK84jC0M_pNff63itef3PTrRoYaOshx1dj8Jb8KtxMwNzp6MN4RraWsUQ2PVkXnr-31McYfXq/s1600/2014-10-08+01-14-38+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; height=&quot;282&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Функция tanh&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
По оси X откладывается входной сигнал, подаваемый узлу. В окрестности 0 выходной сигнал быстро нарастает. Когда сила входного сигнала равна 2, выходной сигнал почти равен 1 и дальше уже почти не растет. Функции такого типа называются сигмоидными, они имеют форму буквы S. Для вычисления силы выходного сигнала нейронов в нейронных сетях почти всегда используются сигмоидные функции. &lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Прежде чем вызывать алгоритм feedforward (прямо-ходящий), наш класс должен прочитать из базы информацию об узлах и связях и построить в памяти часть сети, релевантную конкретному запросу. Первым делом мы напишем функцию, которая ищет все узлы из скрытого слоя, релевантные запросу; в нашем случае это узлы, связанные с любым из слов запроса или с каким-нибудь URL, принадлежащим множеству результатов поиска. Так как никакие другие узлы не участвуют в определении выхода или в обучении сети, то и включать их необязательно. &lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt; def get_all_hidden_ids(self, word_ids, url_ids):

  l1 = {}
  for word_id in word_ids:

   self.cur.execute(&#39;select to_id from word_hidden where from_id = %d&#39; % word_id)
   cur = self.cur.fetchall()

   for row in cur:
    l1[row[0]] = 1

  for url_id in url_ids:

   cur = self.cur.execute(&#39;select from_id from hidden_url where to_id = %d&#39; % url_id)
   cur = self.cur.fetchall()
   
   for row in cur:

    l1[row[0]] = 1

  return l1.keys()
&lt;/pre&gt;
Нам также понадобится метод для конструирования релевантной сети с текущими весами из базы данных. Эта функция инициализирует различные переменные экземпляра класса: список слов, относящиеся к запросу узлы и URL, уровень выходного сигнала для каждого узла и веса всех связей между узлами. Веса считываются из базы данных с помощью ранее разработанных функций. &lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt; def setup_network(self, word_ids, url_ids):

  # списки значений
  self.word_ids = word_ids
  self.hidden_ids = self.get_all_hidden_ids(word_ids, url_ids)
  self.url_ids = url_ids

  # выходные сигналы узлов
  self.hidden_word_output = [1.0]*len(self.word_ids)
  self.hidden_layer_output = [1.0]*len(self.hidden_ids)
  self.hidden_url_output = [1.0]*len(self.url_ids)

  # создаем матрицу весов
  self.word_layer_weights = [
     [self.get_strength(word_id, hidden_id, 0) for hidden_id in self.hidden_ids] for word_id in self.word_ids
       ]

  self.layer_url_weights = [
     [self.get_strength(hidden_id, url_id, 1) for url_id in self.url_ids] for hidden_id in self.hidden_ids
     ]
&lt;/pre&gt;
Вот теперь все готово для реализации алгоритма feedforward. Он принимает список входных сигналов, пропускает их через сеть и возвращает выходные сигналы от всех узлов на выходном уровне. Поскольку в данном случае мы сконструировали сеть только для слов, входящих в запрос, то выходной сигнал от всех входных узлов равен 1: &lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt; def feed_forward(self):

  # единственные входные сигналы – слова из запроса
  for i in xrange(len(self.word_ids)):
   self.hidden_word_output[i] = 1.0

  # возбуждение скрытых узлов
  for j in xrange(len(self.hidden_ids)):
   sum = 0.0
   for i in xrange(len(self.word_ids)):
    sum = sum + self.hidden_word_output[i] * self.word_layer_weights[i][j]
   self.hidden_layer_output[j] = tanh(sum)

  # возбуждение выходных узлов
  for k in xrange(len(self.url_ids)):
   sum = 0.0
   for j in range(len(self.hidden_ids)):
    sum = sum + self.hidden_layer_output[j] * self.layer_url_weights[j][k]
   self.hidden_url_output[k] = tanh(sum)

  return self.hidden_url_output[:]
&lt;/pre&gt;
Алгоритм feedforward в цикле обходит все узлы скрытого слоя и для каждого из них вычисляет сумму величин выходных сигналов от узлов входного слоя, помноженных на вес соответствующей связи. Выходной сигнал каждого скрытого узла – это результат применения функции tanh к взвешенной сумме входных сигналов. Этот сигнал передается на выходной уровень. Выходной уровень делает то же самое – умножает полученные от предыдущего уровня сигналы на веса связей и применяет функцию tanh для получения окончательного результата. Сеть можно легко обобщить, введя дополнительные уровни, которые будут преобразовывать выходные сигналы от предыдущего уровня во входные сигналы следующему. &lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Теперь можно написать небольшую функцию, которая подготовит сеть и вызовет метод feedforward для получения реакции на заданный набор слов и URL: &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt; def get_result(self, word_ids, url_ids):

  self.setup_network(word_ids, url_ids)
  return self.feed_forward()
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
Числа в полученном списке обозначают релевантность поданных на вход URL. Не удивляйтесь, что для всех URL нейронная сеть выдает один и тот же ответ, ведь она еще не прошла обучения!)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
Обучение с обратным распространением &lt;/h2&gt;
А вот теперь начинаются самое интересное. Сеть принимает вход- ные сигналы и генерирует выходные, но, поскольку ее не научили, какой результат считать хорошим, выдаваемые ею ответы практически бесполезны. Сейчас мы это исправим!)&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Чтобы это сделать, нам необходим алгоритм, который будет изменять веса связей между узлами, так чтобы сеть поняла, как выглядит пра- вильный ответ. Веса следует подстраивать постепенно, поскольку нельзя предполагать, что ответ, выбранный одним пользователем, устроит и всех остальных. Описанный ниже алгоритм называется обратным распространением, поскольку в процессе подстройки весов он продвигается по сети в обратном направлении. &lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Во время обучения сети вы в каждый момент знаете желаемый выходной сигнал. В данном случае необходимо получить 1, если пользователь перешел по ссылке, и 0 в противном случае. Изменить выходной сигнал узла можно только одним способом – изменить сигнал, поданный ему на вход. &lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Чтобы определить, насколько следует изменить суммарный входной сигнал, алгоритм обучения должен знать наклон функции tanh для текущего уровня выходного сигнала. В средней точке графика, когда выходной сигнал равен 0, функция изменяется очень круто, поэтому небольшое изменение входного сигнала приводит к большому изменению выходного. По мере того как уровень выходного сигнала приближается к –1 или к 1, изменение входного сигнала меньше сказывается на выходном. Наклон нашей функции для любого значения выходного сигнала вычисляется с помощью следующей функции:&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def dtanh(y):
 return 1.0 - y*y
&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Прежде чем запускать метод обратного распространения, следует вызвать функцию feedforward, чтобы сохранить в переменных экземпляра текущий уровень выходного сигнала от каждого узла. Затем алгоритм обратного распространения выполняет следующие шаги. &lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Для каждого узла из выходного слоя необходимо:&lt;br /&gt;
&lt;div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 106&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Вычислить разность между текущим и желательным уровнем выходного сигнала.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;С помощью функции dtanh определить, насколько должен измениться суммарный входной сигнал для этого узла.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Изменить вес каждой входящей связи пропорционально ее текущему весу и скорости обучения.&lt;/li&gt;
&lt;/ol&gt;
Для каждого узла в скрытом слое необходимо:
&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Изменить выходной сигнал узла на сумму весов каждой выходной связи, умноженных на величину требуемого изменения выходного сигнала конечного узла этой связи.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;С помощью функции dtanh вычислить, насколько должен измениться суммарный входной сигнал для этого узла.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Изменить вес каждой входящей связи пропорционально ее текущему весу и скорости обучения.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt; def back_propagate(self, targets, N=0.5):

  # вычислить поправки для выходного слоя
  output_deltas = [0.0] * len(self.urlids)
  for k in xrange(len(self.urlids)):
   error = targets[k] - self.hidden_url_output[k]
   output_deltas[k] = dtanh(self.hidden_url_output[k]) * error

  # вычислить поправки для скрытого слоя
  hidden_deltas = [0.0] * len(self.hiddenids)
  for j in xrange(len(self.hiddenids)):
   error = 0.0
   for k in xrange(len(self.urlids)):
    error = error + output_deltas[k]*self.layer_url_weights[j][k]
   hidden_deltas[j] = dtanh(self.hidden_layer_output[j]) * error

  # обновить веса связеи между узлами скрытого и выходного слоя
  for j in xrange(len(self.hiddenids)):
   for k in xrange(len(self.urlids)):
    change = output_deltas[k]*self.hidden_layer_output[j]
    self.layer_url_weights[j][k] = self.layer_url_weights[j][k] + N*change

  # обновить веса связей между узлами входного и скрытого слоя
  for i in xrange(len(self.wordids)):
   for j in xrange(len(self.hiddenids)):
    change = hidden_deltas[j]*self.hidden_word_output[i]
    self.word_layer_weights[i][j] = self.word_layer_weights[i][j] + N*change
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
Осталось только написать простой метод, который подготовит сеть, вызовет алгоритм feed_forward и запустит обратное распространение. Этот метод принимает в качестве параметров списки word_ids, url_ids и выбранный URL: &lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt; def train_query(self, word_ids, url_ids, selected_url_id): 

  # сгенерировать скрытыи узел, если необходимо
  self.generate_hidden_node(word_ids, url_ids)

  self.setup_network(word_ids, url_ids)      
  self.feed_forward()
  targets = [0.0]*len(urlids)
  targets[urlids.index(selected_url_id)] = 1.0
  error = self.back_propagate(targets)
  self.update_database()
&lt;/pre&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Для сохранения результатов понадобится метод записи в базу данных новых весов, которые хранятся в переменных экземпляра word_layer_weights&amp;nbsp;и layer_url_weights: &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt; def update_database(self):
  
  for i in xrange(len(self.word_ids)):
   for j in xrange(len(self.hidden_ids)):
    self.set_strength(self.word_ids[i], self. hidden_ids[j], 0, self.word_layer_weights[i][j])

  for j in xrange(len(self.hidden_ids)):
   for k in xrange(len(self.url_ids)):
    self.set_strength(self.hidden_ids[j], self.url_ids[k], 1, self.layer_url_weights[j][k])
&lt;/pre&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 106&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Поздравляю, теперь можно прогнать простой тест, подав на вход тот же запрос, что и раньше, и посмотреть, как сеть отреагировала на обучение. На этот раз, веса не будут одинаковыми, а больше будет у того, по которому кликнули (вы выбрали). При этом, чем чаще по нему будут кликать, тем сильнее будет возростать вес этой ссылки и падать других!&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 106&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Подключение к поисковой машине&lt;/h3&gt;
&lt;div&gt;
Ну вот и все!) Нам осталось только подключить результаты работы сети к поисковой машине. Это для тех, кто читал прошлую статью).&amp;nbsp;&amp;nbsp;Соответствующая функция похожа на все остальные весовые функции.&lt;/div&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def neiron_net_score(self, rows, word_ids):

  # Get unique URL IDs as an ordered list
  url_ids = [row[0] for row in rows]

  nn_res = self.neiron_net.get_result(word_ids, url_ids)
  scores = {url_ids[i]: nn_res[i] for i in xrange(len(url_ids))}
  return self.normalize_scores(scores)
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
Включите его в список weights и поэкспериментируйте с заданием разных весов. На практике следует повременить с привлечением этого метода к реальному ранжированию до тех пор, пока сеть не обучится на большом числе примеров. &lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Мы не уделяли внимание вопросам производительности, но безусловно - это очень острый вопрос в таких системах. Тут я полностью доверяю Вам!) &lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/2061651443807496676/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2014/10/blog-post_8.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/2061651443807496676'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/2061651443807496676'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2014/10/blog-post_8.html' title='Обучение нейронной сети'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMyJf1NQI6Jrzc6JnR1lfEr8spaIaRmG_IiSGEYwJWkmyNWVjfAkZvQTGPlIv2kfyAFvkh1xFVbSe0epVhipkQhnS_fxdHh1OcmdSfv9L9BjxETwz2lggaFOdOiQHVht9rfD_HXYwz/s72-c/2014-10-06+22-12-44+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-8254404714698589072</id><published>2014-10-05T14:44:00.002-07:00</published><updated>2014-10-13T13:55:15.797-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Машинное обучение"/><title type='text'>Поиск и ранжирование</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://ru.eduarea.com/img/pics/feature-005.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://ru.eduarea.com/img/pics/feature-005.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
Сегодня мы рассмотрим систему полнотекстового поиска, она позволяют искать слова в большом наборе документов и сортируют результаты поиска по релевантности найденных документов запросу.&amp;nbsp;
  
 
 
  Алгоритмы полнотекстового поиска относятся к числу важнейших среди алгоритмов коллективного разума. Новые идеи в этой области помогли сколотить целые состояния. Широко распространено мнение, что своей быстрой эволюцией от академического проекта к самой популярной поисковой машине в мире система Google обязана прежде всего алгоритму ранжирования страниц PageRank. &lt;br /&gt;
&lt;div&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;div class=&quot;page&quot; title=&quot;Page 77&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;/h3&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Что такое поисковая машина&lt;/h3&gt;
Итак, давайте же создадим здоровую конкуренцию мировым поисковикам!) Статья так же будет полезна начинающим SEO специалистам, т.к. покажет некоторые величины, которые могут влиять на позиции вашего сайта в поиске.&lt;br /&gt;
&lt;br /&gt;
Первый шаг при создании поисковой машины – разработать методику сбора документов. Иногда для этого применяется ползание (начинаем с небольшого набора документов и переходим по имеющимся в них&amp;nbsp;ссылкам), а иногда отправной точкой служит фиксированный набор документов, быть может, хранящихся в корпоративной сети интранет.&lt;br /&gt;
&lt;br /&gt;
Далее собранные документы необходимо проиндексировать. Обычно для этого строится большая таблица, содержащая список документов и вхождений различных слов. В зависимости от конкретного приложения сами документы могут и не храниться в базе данных; в индексе находится лишь ссылка (путь в файловой системе или URL) на их местонахождение &lt;br /&gt;
&lt;br /&gt;
Ну и последний шаг – это, конечно, возврат ранжированного списка документов в ответ на запрос. Имея индекс, найти документы, содержащие заданные слова, сравнительно несложно; хитрость заключается в том, как отсортировать результаты. Можно придумать огромное количество метрик, и недостатков в них. &lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
Итак, для данной задачи нам потребуется DB (PostgreSQL) и Python (библиотека Grab). А за источник индексирования, новостную ленту &lt;a href=&quot;http://rambler.ru/&quot;&gt;rambler&#39;а&lt;/a&gt;.&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;
Все функции, описаные ниже, у меня являются методами классов, с такой инициализацией:&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;class Indexer:

 def __init__(self):
   
  self.conn = psycopg2.connect(&quot;dbname=&#39;postgres&#39; user=&#39;postgres&#39; password=&#39;120789&#39; host=&#39;localhost&#39;&quot;)

  self.cur = self.conn.cursor()
  self.cur.execute(&quot;set search_path to &#39;rambler_search&#39;&quot;)

  self.grab = Grab()

 def __del__(self):
  self.conn.close()

 def dbcommit(self):
  self.conn.commit()
&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Код паука&lt;/h3&gt;
&lt;div&gt;
Для начала, рассмотрим код функции, которая будет забирать страницу статьи, разбивать ее на текст, вычленяя ссылки и передавать их индексирующим функциям. На вход подается список ссылок, являющихся вхождением для паука.&lt;br /&gt;
&lt;br /&gt;
Эта функция в цикле обходит список страниц, вызывая для каждой функцию addtoindex. Далее она получает все ссылки на данной странице и добавляет их URL в список newpages. В конце цикла newpages присваивается pages, и процесс повторяется. &lt;br /&gt;
&lt;br /&gt;
Эту функцию можно было бы определить рекурсивно, так что при обработке каждой ссылки она вызывала бы сама себя. Но, реализовав поиск в ширину, мы упростим модификацию кода в будущем, позволив пауку ползать непрерывно или сохранять список неиндексированных страниц для последующего индексирования. Кроме того, таким образом мы избегаем опасности переполнить стек. &lt;br /&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 81&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;  
  # Начинаем со списка страниц для индексации
  # опускаемся в глубину на 2 уровня
 def crawl(self, pages, depth=2):

  rambler_news_href_pattern = re.compile(r&#39;(^http:\/\/news\.rambler\.ru\/[\d]+)&#39;)

  for i in range(depth):
   newpages={}

   for page in pages:

    try:
      self.grab.go(page)

    except:
      print &quot;Could not open %s&quot; % page
      continue

    try:
      article_text = &#39;&#39; # текст статьи
      for paragraph in self.grab.tree.xpath(&quot;//p[contains(@class, &#39;b-article__paragraph&#39;)]&quot;):
      article_text += paragraph.text_content()

      self.addtoindex(page, article_text) # записываем в базу текст статьи с индексацией

      links = self.grab.tree.xpath(&quot;//a&quot;)
      for link in links:

     if (&#39;href&#39; in link.attrib):
       url = urljoin(page, link.attrib[&#39;href&#39;]).split(&#39;#&#39;)[0]# делаем полную ссылку и удаляем часть за # если она есть

       match = rambler_news_href_pattern.findall(url)
       if match:
        url = match[0]

      if url[0:4] == &#39;http&#39; and not self.isindexed(url):
       newpages[url] = 1

      linkText = link.text_content() # текст ссылки
      self.addlinkref(page, url, linkText) # записываем в базу текст ссылки с индексацией

      self.dbcommit()

    except Exception, e:
      print &quot;Could not parse page %s&quot; % page, e

   pages = newpages
&lt;/pre&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Построение индекса&lt;/h3&gt;
Наш следующий шаг – подготовка базы данных для хранения полнотекстового индекса. Я уже говорил, что такой индекс представляет собой список слов, с каждым из которых ассоциировано множество документов, где это слово встречается, и место вхождения слова в документ. В данном примере мы анализируем только текст на странице, игнорируя все нетекстовые элементы. Кроме того, индексируются только сами слова, а все знаки препинания удаляются. Такой метод выделения слов несовершенен, но для построения простой поисковой машины сойдет. &lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Создание схемы&lt;/h3&gt;
Подождите запускать программу – нужно сначала подготовить базу данных. Схема простого индекса состоит из пяти таблиц. Первая (url_list) – это список проиндексированных URL. Вторая (word_list) – список слов, а третья (word_location) – список мест вхождения слов в документы. В оставшихся двух таблицах хранятся ссылки между документами. В таблице link хранятся идентификаторы двух URL, связанных ссылкой, а в таблице link_words есть два столбца – word_id и link_id – для хранения слов, составляющих ссылку. Вся схема изображена на рисунке ниже. Код запросов приводить не буду, должны ведь и вы поработать)))&lt;br /&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 78&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC6T7iPMECKlinljAdPAOPuYITmv24Ksf73h7xbEotJbn1cPSrAlez0wNHzBqF9QmRTUHwG75KtCglsZKoEVZdlSxPO8FUfYM-erOsOg1nkLA0ew8b4x58Pkxys74TWoFcLLlM8TA9/s1600/2014-10-03+00-57-59+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC6T7iPMECKlinljAdPAOPuYITmv24Ksf73h7xbEotJbn1cPSrAlez0wNHzBqF9QmRTUHwG75KtCglsZKoEVZdlSxPO8FUfYM-erOsOg1nkLA0ew8b4x58Pkxys74TWoFcLLlM8TA9/s1600/2014-10-03+00-57-59+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; height=&quot;224&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;/h3&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Выделение слов на странице&lt;/h3&gt;
&lt;div&gt;
Для решения данной задачи, воспользуемся простейшей функцией. Мы не будем вводить стоп слова, которые не нужно индексировать, а просто введем ограничение на длину слова в 3 символа, тем самым убрав предлоги и другой мусор (хоть и пострадают всякие мелкие слова, типа &quot;мир&quot;, &quot;тир&quot;, &quot;пир&quot;).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def getwords(html):
    words = []
    for split_str in html.split():
        t = re.split(&quot;[\s;:\-_*\&quot;.,?!()&#39;&amp;amp;#«»]&quot;, split_str)
        words += [a.lower() for a in t if a != &#39;&#39; and len(a) &amp;gt; 3]
    return words
&lt;/pre&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Добавление в индекс&lt;/h3&gt;
Теперь мы готовы написать код метода addtoindex. Он вызывает две функции, написанные в предыдущем разделе, чтобы получить список слов на странице. Затем эта страница и все найденные на ней слова добавляются в индекс и создаются ссылки между словами и их вхождениями в документ. В нашем примере адресом вхождения будет считаться номер слова в списке слов. &lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 77&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;  
        def addtoindex(self, url, text):

  if self.isindexed(url): return # если уже индексирована - пропускаем
  print &#39;Indexing %s&#39; % url

  # Получаем слова из текста
  words = getwords(text)

  # Получаем id url&#39;а
  url_id = self.getentryid(&#39;url_list&#39;, &#39;url&#39;, url)

  # Связываем слова с этим урлом
  for i, word in enumerate(words): # пронумеруем слова
    word_id = self.getentryid(&#39;word_list&#39;, &#39;word&#39;, word)
    self.cur.execute(&quot;insert into word_location(url_id, word_id, location) values (%d, %d, %d)&quot; % (url_id, word_id, i))
    self.dbcommit()
&lt;/pre&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 77&quot;&gt;
&lt;br /&gt;
Хорошо, теперь нужно описать функцию getentryid - возвращающую id записи из бд и isindexed - проверяющую, не индексировали ли мы эту страницу раньше.&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;  
        # Узнаем id записи в БД, если нет
        # иначе записываем и возвращаем новый
 def getentryid(self, table, field, value, createnew=True):

  self.cur.execute(&quot;select id from %s where %s = &#39;%s&#39;&quot; % (table, field, value))
  cur = self.cur.fetchone()

  if not cur:
   # print (table, field, value)
   self.cur.execute(&quot;insert into %s (%s) values (&#39;%s&#39;) returning %s.id&quot; % (table, field, value, table))
   cur = self.cur.fetchone()
   self.dbcommit()

   return cur[0]

  else:
    return cur[0]

       # Возвращаем True, если посещали страницу
 def isindexed(self, url):
  self.cur.execute(&quot;select id from url_list where url = &#39;%s&#39;&quot; % url)
  u = self.cur.fetchone()

  if u:
   # Проверяем, что паук посещал страницу
   self.cur.execute(&quot;select count(1) from word_location where url_id = %d&quot; % u[0])
   v = self.cur.fetchone()

   if v[0]:
    return True

  return False
&lt;/pre&gt;
&lt;br /&gt;
Последняя функция, необходимая нам для начала индексирования - это&amp;nbsp;addlinkref. Как следует из ее названия, она заносит ссылки и слова из которых они состоят к нам в БД.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt; def addlinkref(self, urlFrom, urlTo, linkText):

  words = getwords(linkText)
  from_id = self.getentryid(&#39;url_list&#39;, &#39;url&#39;, urlFrom)
  to_id = self.getentryid(&#39;url_list&#39;, &#39;url&#39;, urlTo)

  if from_id == to_id: return

  self.cur.execute(&quot;insert into link(from_id, to_id) values (%d, %d) returning link.id&quot; % (from_id, to_id))
  link_id = self.cur.fetchone()[0]

  for word in words:

    word_id = self.getentryid(&#39;word_list&#39;, &#39;word&#39;, word)
    self.cur.execute(&quot;insert into link_words(link_id, word_id) values (%d, %d)&quot; % (link_id, word_id))
&lt;/pre&gt;
&lt;br /&gt;
Ну что же, на этом этапе мы можем запустить паука и создать базу данных)&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Запросы&lt;/h3&gt;
&lt;div&gt;
Теперь, когда у нас есть материал, с которым можно работать, необходимо написать сам поисковик. Начнем мы с малого, грубого поиска, по абсолютному вхождению фразы в новость.&lt;/div&gt;
Таблица word_location обеспечивает простой способ связать слова с документами, так что мы можем легко найти, какие страницы содержат данное слово. Однако поисковая машина была бы довольно слабой, если бы не позволяла задавать запросы с несколькими словами. Чтобы исправить это упущение, нам понадобится функция, которая принимает строку запроса, разбивает ее на слова и строит SQL-запрос для поиска URL тех документов, в которые входят все указанные слова.  &lt;/div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 77&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt; def get_match_rows(self, query):

  select_query_add = []
  join_query_add = []
  where_query_add = []

  main_search_query = &quot;&quot;&quot; 
     SELECT wl0.url_id, %s
     FROM word_location wl0
     %s 
     WHERE %s
    &quot;&quot;&quot;

  query_words = getwords(query)

  query_word_ids = []
  for query_word in query_words:

   self.cur.execute(&quot;select id from word_list where word = &#39;%s&#39;&quot; % query_word)
   query_word_id = self.cur.fetchone()

   if query_word_id:
    query_word_ids.append(query_word_id[0])

  if query_word_ids:
   for position, query_word_id in enumerate(query_word_ids):

    if position:
     join_query_add.append(&#39;JOIN word_location wl%d ON wl%d.url_id = wl%d.url_id&#39; % (position, position-1, position))

    select_query_add.append(&#39;wl%d.location&#39; % position)
    where_query_add.append(&#39;wl%d.word_id = %d&#39; % (position, query_word_id))

   main_search_query = main_search_query % (&#39;, &#39;.join(select_query_add), &#39; &#39;.join(join_query_add), &#39; and &#39;.join(where_query_add))

   self.cur.execute(main_search_query)
   search_results = self.cur.fetchall()
   
   return search_results, query_word_ids
&lt;/pre&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 77&quot;&gt;
Данная функция всего лишь создает строгий JOIN, типа такого:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt; 
 SELECT wl0.url_id, wl0.location, wl1.location
 FROM word_location wl0
 JOIN word_location wl1 ON wl0.url_id = wl1.url_id 
 WHERE wl0.word_id = 2734 and wl1.word_id = 2698
&lt;/pre&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;&lt;/pre&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn_jtowjC8eWcB58Q7ec6UxX9vvMnzDlQeb1Poza2KFLK26cmRhmzbvDo61YrNJqKsUo6Hl0zON3QloRuugSdjCJP-QeDobm3gA3oIAVfiDq3r3oSTdPnL3EbnkJvNRLv6Ry4jDLKo/s1600/2014-10-04+17-25-54+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn_jtowjC8eWcB58Q7ec6UxX9vvMnzDlQeb1Poza2KFLK26cmRhmzbvDo61YrNJqKsUo6Hl0zON3QloRuugSdjCJP-QeDobm3gA3oIAVfiDq3r3oSTdPnL3EbnkJvNRLv6Ry4jDLKo/s1600/2014-10-04+17-25-54+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; height=&quot;104&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
В результате, получаем список кортежей и список с id слов. Каждый кортеж - это сто список вида (id новости, позиция 1го слова, позиция 2го слова...)&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Ранжирование по содержимому&lt;/h3&gt;
&lt;div&gt;
Итак, худо-бедно, но мы научились искать по индексу. Однако&lt;span style=&quot;font-family: SchoolBookC-Identity-H; font-size: 10pt;&quot;&gt;&amp;nbsp;&lt;/span&gt;возвращаем мы их в том порядке, в котором они посещались пауком. Чтобы решить эту проблему, необходимо как-то присвоить страницам ранг относительно данного запроса и уметь возвращать их в порядке убывания рангов.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
В этом разделе мы рассмотрим несколько способов вычисления ранга &lt;br /&gt;
на основе самого запроса и содержимого страницы, а именно: &lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;i&gt;Частота слов&amp;nbsp;&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Количество вхождений в документ слова, указанного в запросе, помогает определить степень релевантности документа.&lt;/blockquote&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;i&gt;
&lt;li&gt;&lt;i&gt;Расположение в документе&amp;nbsp;&lt;/i&gt;&lt;/li&gt;
&lt;/i&gt;&lt;/ul&gt;
&lt;i&gt;
&lt;/i&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Основная тема документа, скорее всего, раскрывается ближе к его началу.&lt;/blockquote&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;i&gt;
&lt;li&gt;&lt;i&gt;Расстояние между словами&amp;nbsp;&lt;/i&gt;&lt;/li&gt;
&lt;/i&gt;&lt;/ul&gt;
&lt;i&gt;
&lt;/i&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Если в запросе несколько слов, то они должны встречаться в документе рядом.&lt;/blockquote&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 88&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 89&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
Самые первые поисковые машины (кстати &lt;a href=&quot;http://rambler.ru/&quot;&gt;rambler.ru&lt;/a&gt;) часто работали только с подобными метриками и тем не менее давали пристойные результаты. Давайте добавим следующие методы:&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt; # Функция, которая взвешивает результаты
 def get_scored_list(self, rows, word_ids):

  total_scores = {row[0]: 0 for row in rows}

  if rows:
   # Список весовых функций
   weight_functions = [
      ]

   for (weight, scores) in weight_functions:
     for url in total_scores:
    total_scores[url] += weight * scores[url]

  return total_scores

 # Возвращает полный урл по id
 def get_url_name(self, url_id):

  self.cur.execute(&quot;select url from url_list where id = %d&quot; % url_id)

  return self.cur.fetchone()[0]

 # Основная функция поиска
 def search(self, search_sentence):

  search_results, word_ids = self.get_match_rows(search_sentence)
  scores = self.get_scored_list(search_results, word_ids)

  ranked_scores = [(score, url) for (url, score) in scores.items()]
  ranked_scores.sort()
  ranked_scores.reverse()

  for (score, url_id) in ranked_scores[0:10]:
    print &#39;%f\t%s&#39; % (score, self.get_url_name(url_id))

  return word_ids, [r[1] for r in ranked_scores[0:10]]
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
Наиболее важна здесь функция get_scored_list, код которой мы будем постепенно уточнять. По мере добавления функций ранжирования мы будем вводить их в список weight_functions  и начнем взвешивать полученные результаты.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Функция нормализации&lt;/h3&gt;
&lt;div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 90&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
Все рассматриваемые ниже функции ранжирования возвращают словарь, в котором ключом является идентификатор URL, а значением – числовой ранг. Иногда лучшим считается больший ранг, иногда – меньший. Чтобы сравнивать результаты, получаемые разными методами, необходимо как-то нормализовать их, то есть привести к одному и тому же диапазону и направлению.&lt;span style=&quot;font-family: &#39;SchoolBookC-Identity-H&#39;; font-size: 10.000000pt;&quot;&gt;&lt;br /&gt;&lt;/span&gt;

  
 
 
  Функция нормализации принимает на входе словарь идентификаторов и рангов и возвращает новый словарь, в котором идентификаторы те же самые, а ранг находится в диапазоне от 0 до 1. Ранги масштабируются по близости к наилучшему результату, которому всегда припи- сывается ранг 1. От вас требуется лишь передать функции список рангов и указать, какой ранг лучше – меньший или больший: 
    &lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt; def normalize_scores(self, scores, smallIsBetter=0):

  vsmall = 0.00001 # Avoid division by zero errors

  if smallIsBetter:
   minscore = min(scores.values())
   return {u: float(minscore)/max(vsmall, l) for (u,l) in scores.items()}

  else:
   maxscore = max(scores.values())
   if maxscore == 0: maxscore = vsmall
   return {u: float(c)/maxscore for (u,c) in scores.items()}

  return scores
&lt;/pre&gt;
&lt;div class=&quot;column&quot;&gt;
Отлично! Пора заняться весовыми функциями, для которых мы и придумали эту нормализацию.&lt;br /&gt;
&lt;br /&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
Весовые функции&lt;/h2&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Частота слов&lt;/h3&gt;
Метрика, основанная на частоте слов, ранжирует страницу исходя из того, сколько раз в ней встречаются слова, упомянутые в запросе. Если я выполняю поиск по слову python, то в начале списка скорее получу страницу, где это слово встречается много раз, а не страницу о музыканте, который где-то в конце упомянул, что у него дома живет питон. &lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def frequency_score(self, rows):

  counts = {row[0]:0 for row in rows}
  for row in rows: 
   counts[row[0]] += 1

  return self.normalize_scores(counts)
&lt;/pre&gt;
Чтобы активировать ранжирование документов по частоте слов, измените строку функции get_scored_list, где определяется список weight_functions, следующим образом: &lt;/div&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;weight_functions = [(1.0,self.frequency_score(rows))]
&lt;/pre&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
Запустите поиск снова и радуйтесь!)&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Расположение в документе&lt;/h3&gt;
Еще одна простая метрика для определения релевантности страницы запросу – расположение поисковых слов на странице. Обычно, если страница релевантна поисковому слову, то это слово расположено близко к началу страницы, быть может, даже находится в заголовке.&lt;/div&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def location_score(self, rows):

  locations = {}
  for row in rows:
   loc = sum(row[1:])
   if locations.has_key(row[0]):
    if loc &amp;lt; locations[row[0]]:
     locations[row[0]] = loc
   else:
    locations[row[0]] = loc

  return self.normalizescores(locations, smallIsBetter=1)
&lt;/pre&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Расстояние между словами&lt;/h3&gt;
Если запрос содержит несколько слов, то часто бывает полезно ранжировать результаты в зависимости от того, насколько близко друг к другу встречаются поисковые слова. Как правило, вводя запрос из нескольких слов, человек хочет найти документы, в которых эти слова концептуально связаны. Рассматриваемая метрика допускает изменение порядка и наличие дополнительных слов между поисковыми. &lt;/div&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt; def distance_score(self, rows):

  mindistance = {}

  # Если только 1 слово, любой документ выигрывает
  if len(rows[0]) &amp;lt;= 2:
   return {row[0]: 1.0 for row in rows}

  mindistance = {}

  for row in rows:
   dist = sum([abs(row[i]-row[i-1]) for i in xrange(2, len(row))])

   if mindistance.has_key(row[0]):
    if dist &amp;lt; mindistance[row[0]]:
     mindistance[row[0]] = dist
   else:
    mindistance[row[0]] = dist

  return self.normalize_scores(mindistance, smallIsBetter=1)
&lt;/pre&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
Использование внешних ссылок на сайт&lt;/h2&gt;
Все обсуждавшиеся до сих пор метрики ранжирования были основаны на содержимом страницы. Часто результаты можно улучшить, приняв во внимание, что говорят об этой странице другие, а точнее те сайты, на которых размещена ссылка на нее. Особенно это полезно при индексировании страниц сомнительного содержания или таких, которые могли быть созданы спамерами, поскольку маловероятно, что на такие страницы есть ссылки с настоящих сайтов.&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Простой подсчет ссылок&lt;/h3&gt;
Простейший способ работы с внешними ссылками заключается в том, чтобы подсчитать, сколько их ведет на каждую страницу, и использовать результат в качестве метрики. Так обычно оцениваются научные работы; считается, что их значимость тем выше, чем чаще их цитируют. &lt;/div&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def inbound_link_score(self, rows):

  unique_urls = {row[0]: 1 for row in rows}
  inbound_count = {}
  
  for url_id in unique_urls:
   self.cur.execute(&#39;select count(*) from link where to_id = %d&#39; % url_id)
   inbound_count[url_id] = self.cur.fetchone()[0]

  return self.normalize_scores(inbound_count)
&lt;/pre&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 90&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Описанный алгоритм трактует все внешние ссылки одинаково, но такой уравнительный подход открывает возможность для манипулирования, поскольку кто угодно может создать несколько сайтов, указывающих на страницу, ранг которой он хочет поднять. Также возможно, что людям более интересны страницы, которые привлекли внимание каких-то популярных сайтов. Далее мы увидим, как придать ссылкам с популярных сайтов больший вес при вычислении ранга страницы. &lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 90&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Алгоритм PageRank&lt;/h3&gt;
&lt;div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 94&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
Алгоритм PageRank был придуман основателями компании Google, и вариации этой идеи теперь применяются во всех крупных поисковых машинах. Этот алгоритм приписывает каждой странице ранг, оценивающий ее значимость. Значимость страницы вычисляется исходя из значимостей ссылающихся на нее страниц и общего количества ссылок, имеющихся на каждой из них.&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;Теоретически алгоритм PageRank (названный по фамилии одного из его изобретателей Лари Пейджа (Larry Page)) рассчитывает вероятность того, что человек, случайно переходящий по ссылкам, доберется до некоторой страницы. Чем больше ссылок ведет на данную страницу с других популярных страниц, тем выше вероятность, что экспериментатор чисто случайно наткнется на нее. Разумеется, если пользователь будет щелкать по ссылкам бесконечно долго, то в конце концов он посетит каждую страницу, но большинство людей в какой-то момент останавливаются. Чтобы учесть это, в алгоритм PageRank введен коэффициент затухания 0,85, означающий, что пользователь продолжит переходить по ссылкам, имеющимся на текущей странице, с вероятностью 0,85. &lt;/i&gt;&lt;/blockquote&gt;
Давайте рассмотрим пример:&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4Y2f6FSWqGZ_UH9fjYDsmfOEP2p-R9MTamuwPeYo8wwhEhbBGN_uqtRptEGYBntZsfsHieTBCLhK0E5dss-nulQdvldF7zm6jbF7Tst27ypUTsQPM3CtKGONRK3S9H-GPM6FlbfBt/s1600/2014-10-05+23-55-10+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4Y2f6FSWqGZ_UH9fjYDsmfOEP2p-R9MTamuwPeYo8wwhEhbBGN_uqtRptEGYBntZsfsHieTBCLhK0E5dss-nulQdvldF7zm6jbF7Tst27ypUTsQPM3CtKGONRK3S9H-GPM6FlbfBt/s1600/2014-10-05+23-55-10+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png&quot; height=&quot;226&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Вычисление PageRank страницы A&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
Каждая из страниц B, C и D ссылается на A, и для них ранг уже вычис- лен. На странице B есть ссылки еще на три страницы, а на странице C – на четыре. D ссылается только на A. Чтобы вычислить ранг A, берем ранги (PR) каждой ссылающейся на A страницы, делим их на общее число ссылок на этой странице, складываем получившиеся значения, затем умножаем результат на коэффициент затухания 0,85 и добавляем минимальную величину 0,15. Вот как&amp;nbsp;производится вычисление PR(A): &lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;PR(A) = 0,15 + 0,85 × (PR(B)/ссылки(B) + PR(C)/ссылки(C) + + PR(D)/ссылки(D))&lt;br /&gt; = 0,15 + 0,85 × (0,5/4 + 0,7/5 + 0,2/1) = 0,15 + 0,85 × (0,125 + 0,14 + 0,2)&lt;br /&gt; = 0,15 + 0,85 × 0,465&lt;br /&gt; = 0,54525&lt;/i&gt;&lt;/blockquote&gt;
Обратите внимание, что D дает больший вклад в ранг A, чем B или C, хотя ее собственный ранг меньше. Это вызвано тем, что D ссылается только на A и, значит, привносит в результат свой ранг целиком.
  
 
 
  &lt;br /&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 96&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;
&lt;br /&gt;
Несложно, да? Увы, имеется тут небольшая ловушка – в данном при- мере для всех страниц, ссылающихся на A, уже вычислен ранг. Но невозможно вычислить ранг страницы, пока неизвестны ранги ссылающихся на нее страниц, а эти ранги можно вычислить, только зная ранги страницы, которые ссылаются на них. Так как же вычислить значение PageRank для множества страниц, ранги которых еще неизвестны? 
    &lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Решение состоит в том, чтобы присвоить всем страницам произвольный начальный ранг (в программе ниже взято значение 1,0, но на самом деле точная величина несущественна) и провести несколько итераций. После каждой итерации ранг каждой страницы будет все ближе к истинному значению PageRank, как бы сходиться к некоему пределу, который и есть действительный PR. Количество необходимых итераций зависит от числа страниц. 
   &lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://compendium.su/mathematics/algebra10/algebra10.files/image2110.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://compendium.su/mathematics/algebra10/algebra10.files/image2110.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Поскольку вычисление значения PageRank занимает много времени, а вычисленный ранг не зависит от запроса, то мы напишем функцию, которая заранее вычисляет ранг каждого URL и сохраняет его в таблице. При каждом вызове эта функция будет пересчитывать ранги всех страниц.  
  &lt;/div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 96&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt; # Вычисляем PageRank страниц
 def calculate_page_rank(self, iterations=20):

  START_PR = 1
  self.cur.execute(&#39;update url_list set page_rank = %d&#39; % START_PR)
  self.db_commit()

  for i in range(iterations):
   print &quot;Iteration %d&quot; % (i)
   self.cur.execute(&#39;select id from url_list&#39;)
   for url_id,  in self.cur.fetchall():

    # Конечный PR зависит от START_PR и этого базового pr
    pr = 0.15

    self.cur.execute(&#39;select distinct from_id from link where to_id = %d&#39; % url_id)
    # Перебираем все страницы, ссылающиеся на данную
    for linker, in self.cur.fetchall():

     # Получаем PR ссылающейся страницы
     self.cur.execute(&#39;select page_rank from url_list where id = %d&#39; % linker)
     linking_pr = self.cur.fetchone()[0]

     # Получаем общее количество ссылок на ссылающейся странице
     self.cur.execute(&#39;select count(*) from link where from_id = %d&#39; % linker)
     linking_count = self.cur.fetchone()[0]
     pr += 0.85 * (linking_pr/linking_count)

     self.cur.execute(&#39;update url_list set page_rank = %f where id = %d&#39; % (pr, url_id))
    self.db_commit()
&lt;/pre&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 96&quot;&gt;
&lt;br /&gt;
Итак, запустили - вычислили, пора написать весовую функцию, использующую данную величину.&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt; def page_rank_score(self, rows):

  page_ranks = {row[0]: 0 for row in rows}

  for row in rows:
   self.cur.execute(&#39;select page_rank from url_list where id = %d&#39; % row[0])
   page_ranks[row[0]] = self.cur.fetchone()[0]

  return self.normalize_scores(page_ranks)
&lt;/pre&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Использование текста ссылки&lt;/h3&gt;
&lt;div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 98&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
Еще один полезный способ ранжирования результатов – использование текста ссылок на страницу при определении степени ее релевантности запросу. Часто удается получить более качественную информацию из того, что сказано в ссылках, ведущих на страницу, чем из самой страницы, поскольку авторы сайтов обычно включают краткое описание того, на что ссылаются.&lt;span style=&quot;font-family: &#39;SchoolBookC-Identity-H&#39;; font-size: 10.000000pt;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt; def link_text_score(self, rows, word_ids):

  link_scores = {row[0]: 0 for row in rows}

  word_ids_string = &#39;,&#39;.join(map(str, word_ids))
  url_ids_string =  &#39;,&#39;.join(set([str(row[0]) for row in rows]))

  self.cur.execute(&#39;&#39;&#39; select sum(u_l.page_rank), l.to_id
        from link l
        join link_words l_w on l.id = l_w.link_id
        join url_list u_l on u_l.id = l.from_id 
        where word_id IN (%s) and l.to_id IN (%s)
        group by l.to_id&#39;&#39;&#39; % (word_ids_string, url_ids_string))

  for sum_pr_url_from, url_id in self.cur.fetchall():
   link_scores[&#39;url_id&#39;] = sum_pr_url_from

  return self.normalize_scores(link_scores)
&lt;/pre&gt;
&lt;br /&gt;
Функция выбирает ссылки со словами поиска, которые ведут на новости, в которых они употребляются. Суммирует их PageRank&#39;s и возвращет этот навесок.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Вывод в продолжение&lt;/h3&gt;
&lt;br /&gt;
&lt;div class=&quot;column&quot;&gt;
Поздравляю, вот мы и написали своего поискового робота!&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Не существует стандартных весов для всех рассмотренных метрик, которые были бы одинаково хороши во всех случаях. Даже самые крупные поисковые машины часто изменяют методы ранжирования результатов. Метрики и назначаемые им веса сильно зависят от конкретного приложения. &lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
Стоит заметить, что таких метрик может быть целая уйма (учет жирности написания слов, кол-во времени проведенного на странице и т.д.)! Не зря поисковики и их браузеры, так пристально следят за нашими действиями). Так что и Вы, придумывайте и улучшайте качество поиска! А в &lt;a href=&quot;http://py-algorithm.blogspot.ru/2014/10/blog-post_8.html&quot;&gt;следующей статье&lt;/a&gt;, мы попробуем его немного поучить.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 95&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/8254404714698589072/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2014/10/blog-post.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/8254404714698589072'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/8254404714698589072'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2014/10/blog-post.html' title='Поиск и ранжирование'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC6T7iPMECKlinljAdPAOPuYITmv24Ksf73h7xbEotJbn1cPSrAlez0wNHzBqF9QmRTUHwG75KtCglsZKoEVZdlSxPO8FUfYM-erOsOg1nkLA0ew8b4x58Pkxys74TWoFcLLlM8TA9/s72-c/2014-10-03+00-57-59+book.uz+wp-content+uploads+2010+10+kol_razum.pdf.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-1252331563376953717</id><published>2014-08-12T15:42:00.001-07:00</published><updated>2014-08-13T15:37:33.598-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Машинное обучение"/><title type='text'>Подбор предметов</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://itc.ua/wp-content/uploads/2014/02/Nokia-Treasure-Tag.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://itc.ua/wp-content/uploads/2014/02/Nokia-Treasure-Tag.jpg&quot; height=&quot;200&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 37&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
Теперь вы знаете, как &lt;a href=&quot;http://py-algorithm.blogspot.ru/2014/08/blog-post_10.html&quot;&gt;искать похожих людей&lt;/a&gt; и &lt;a href=&quot;http://py-algorithm.blogspot.ru/2014/08/blog-post_11.html&quot;&gt;рекомендовать предметы&lt;/a&gt; данному человеку. Но что если нужно узнать, какие предметы похожи друг на друга?  В данном случае вы можете определить степень сходства, выявив людей, которым понравился данный товар, и посмотрев, что еще им понравилось. По существу, это тот же метод, которым мы уже пользовались для определения похожести людей, – нужно лишь вместо людей всюду подставить товары. Излогаясь математическим языком - транспонировать)&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h2 style=&quot;text-align: center;&quot;&gt;
Подбор схожих предметов&lt;/h2&gt;
&lt;div class=&quot;column&quot;&gt;
Произвидя поиск таким образом логика будет следующей: сравниваем 2 фильма и находим всех людей, которые смотрели оба фильма и смотрим оценки выставленные второму, если они хорошие, а лучше все 10ки)&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Практика Евклида&lt;/h4&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;select
v1.film_id, v2.film_id,
1/(1+(|/sum((v1.vote-v2.vote)^2))),--евклидово не взвешенное расстояние
count(1)--кол-во общих фильмов(вес для ф-ии)
from votes v1
join votes v2 on v1.user_id=v2.user_id 
where v1.film_id &amp;lt;&amp;gt; v2.film_id 
and v2.film_id=326
group by v1.film_id, v2.film_id
--having count(1)&amp;gt;10
order by 1/(1+(|/sum((v1.vote-v2.vote)^2))) desc, count(1) desc
&lt;/pre&gt;
&lt;br /&gt;
Для сравнения возьмем фильм &quot;Побег из Шоушенка&quot;. Метод Евклида посчитал, что на него больше всего похож фильм &quot;Реал Мадрид&quot;. Спросите чем? Отвечу:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:sql&quot;&gt;select
v1.film_id, v2.film_id,
v1.vote vote1, v2.vote vote2, v1.user_id, v2.user_id 
from votes v1
join votes v2 on v1.user_id=v2.user_id 
where v1.film_id &amp;lt;&amp;gt; v2.film_id 
and v2.film_id=326
and v1.film_id=155080&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
5 разных людей смотрели оба фильма и поставили не много не мало все 10ки!!! Но конечно, данный алгоритм никак не учитывает жанры, режиссеров или актеров. Однако никто не мешает ввести вам такие дополнительные фильтрующие весовые функции.&lt;br /&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Практика Пирсона&lt;/h4&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;select
v1.film_id,
case when ((sum(v1.vote^2)+1)-(sum(v1.vote)^2)/count(1)::float)*((sum(v2.vote^2)+1)-(sum(v2.vote)^2)/count(1)::float) &amp;lt;&amp;gt; 0
then
	(sum(v1.vote*v2.vote)-(sum(v1.vote)*sum(v2.vote))/count(1)::float)/(|/((sum(v1.vote^2)+1)-(sum(v1.vote)^2)/count(1)::float)*((sum(v2.vote^2)+1)-(sum(v2.vote)^2)/count(1)::float))
else
	0
end,
count(1)--кол-во общих критиков(вес для ф-ии)
from votes v1
join votes v2 on v1.user_id=v2.user_id 
where v1.film_id &amp;lt;&amp;gt; v2.film_id 
and v2.film_id=326 --фильм для сравнения
group by v1.film_id, v2.film_id
--having count(1)&amp;gt;10
order by 
case when ((sum(v1.vote^2)+1)-(sum(v1.vote)^2)/count(1)::float)*((sum(v2.vote^2)+1)-(sum(v2.vote)^2)/count(1)::float) &amp;lt;&amp;gt; 0
then
	(sum(v1.vote*v2.vote)-(sum(v1.vote)*sum(v2.vote))/count(1)::float)/(|/((sum(v1.vote^2)+1)-(sum(v1.vote)^2)/count(1)::float)*((sum(v2.vote^2)+1)-(sum(v2.vote)^2)/count(1)::float))
else
	0
end
desc,
count(1) desc
&lt;/pre&gt;
&lt;br /&gt;
Запустив пирсона, получим совсем другой фильм - &quot;Крезанутые&quot;. И это всего при 2х общих критиках. В общем советую Вам обратить внимание на закомментированную строку с having, считаю что нужно ее применить для более точного совпадения)&lt;br /&gt;
&lt;div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 43&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/1252331563376953717/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2014/08/blog-post_12.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/1252331563376953717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/1252331563376953717'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2014/08/blog-post_12.html' title='Подбор предметов'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-8970987251883687769</id><published>2014-08-11T16:11:00.001-07:00</published><updated>2014-08-13T16:26:52.206-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Машинное обучение"/><title type='text'>Рекомендование предметов</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhu8SEQeF3miPQmcHLG6ab0FYi6MAZYXxrwbBSbn6M0KQ8x20krpnW7EQnC-svSdb0nqifQCPL7tVB0LmDIwJWtW_CmAFU6FZSFD-hYqcWnbET5V6b5ZuFjZxmyDvm9WzWmCTqbD9pscifD/s320/like%252Bbutton.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhu8SEQeF3miPQmcHLG6ab0FYi6MAZYXxrwbBSbn6M0KQ8x20krpnW7EQnC-svSdb0nqifQCPL7tVB0LmDIwJWtW_CmAFU6FZSFD-hYqcWnbET5V6b5ZuFjZxmyDvm9WzWmCTqbD9pscifD/s320/like%252Bbutton.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
В прошлом посте мы с Вами разобрались, как ранжировать людей по вкусам и говорить кто на нас похож больше всех. Теперь займемся связанной задачей - рекомендацией фильмов!&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;
Рекомендование предметов&lt;/h3&gt;
Найти подходящего критика – это, конечно, неплохо, но в действительности-то я хочу, чтобы мне порекомендовали фильм. Можно было бы посмотреть, какие фильмы понравились человеку с похожими на мои вкусами, и выбрать из них те, что я еще не смотрел. Но при таком подходе можно было бы пропустить много классных фильмов. Или посмотреть фильм, который понравился только ему. &lt;br /&gt;
&lt;br /&gt;
Чтобы разрешить эти проблемы, необходимо ранжировать сами фильмы, вычислив взвешенную сумму оценок критиков. Берем каждого из отобранных критиков и умножаем его оценку подобия со мной на оценку, которую он выставил каждому фильму. Вот пример из книжки, надеюсь будет понятно)&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://crypto.pp.ua/img/ai2008_image008.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://crypto.pp.ua/img/ai2008_image008.jpg&quot; height=&quot;205&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Смысл в том, чтобы мнение критика с похожими на мои вкусами вносило больший вклад в общую оценку, чем мнение критика, не похожего на меня. В строке «Итого» приведены суммы вычисленных таким образом величин. &lt;br /&gt;
&lt;div&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 35&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
Можно было бы использовать для ранжирования сами эти суммы, но тогда фильм, который просмотрело больше людей, получил бы преимущество. Чтобы исправить эту несправедливость, необходимо разделить полученную величину на сумму коэффициентов подобия для всех критиков, которые рецензировали фильм (строка «S подоб.» в таблице)&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
По мере решения этой задачи, можно столкнуться с интересными закономерностями.&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
Например, я сделал ранжирование фильмов, которым я ставил оценку. Что это значит? Представьте, что вы поставили всем фильмам 7 баллов. На страницу вашего профиля заходит Ваш друг, чтобы выбрать что посмотреть и натыкается на то, что все фильмы имеют одинаковые оценки. Чтобы этого не возникло, можно ему показывать не просто оценки, а взвешенные(с учетом вкусов друга, а не ваших), т.е. с учетом оценок других критиков.&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;column&quot;&gt;
Привожу скриптик. &amp;nbsp;Примеры приведены с Евклидовым &lt;a href=&quot;http://py-algorithm.blogspot.ru/2014/08/blog-post_10.html&quot;&gt;коэффициентом подобия&lt;/a&gt;, исходя из его лаконичности, но так мне больше нравится Пирса.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;select v1.film_id, 
count(1),--количество людей тоже ставивших голоса фильму кроме меня
evkl.sum_koef -- сумма подобия людей(со мной) голосовавших за этот фильм
from votes v1
join votes v2 on v1.film_id=v2.film_id 
join (
 select sum(evkl.vote*evkl.koef)/sum(evkl.koef) sum_koef, evkl.film_id
 from(
  select
  v1.user_id,
  v1.vote,
  v1.film_id,
  1/(1+(|/sum((v1.vote-v2.vote)^2))) koef--евклидово не взвешенное расстояние
  from votes v1
  join votes v2 on v1.film_id=v2.film_id 
  where v1.user_id &amp;lt;&amp;gt; v2.user_id 
  and v2.user_id=4722023 -- мой id
  group by v1.user_id, v1.film_id, v1.vote
 ) evkl
  group by evkl.film_id
) evkl on v1.film_id=evkl.film_id
where v1.user_id &amp;lt;&amp;gt; v2.user_id 
and v2.user_id=4722023 -- мой id
group by v1.film_id, evkl.sum_koef
order by evkl.sum_koef desc
&lt;/pre&gt;
&lt;br /&gt;
Таким образом фильмы с одинаковыми оценками(которые поставил я), стали взвешенными и выстроились в порядке, которые по идее мне понравились чуточку больше)))&lt;br /&gt;
&lt;br /&gt;
Ну что же - это уже, как минимум не плохо) Но и основная задача, рекомендации фильмов, решается не сложнее).&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;select
v1.film_id,
sum(v1.vote*evkl.koef)/sum(evkl.koef)
from votes v1
join (
 select
 v1.user_id,
 1/(1+(|/sum((v1.vote-v2.vote)^2))) koef--евклидово не взвешенное расстояние
 from votes v1
 join votes v2 on v1.film_id=v2.film_id 
 where v1.user_id &amp;lt;&amp;gt; v2.user_id 
 and v2.user_id=4722023
 group by v1.user_id
 order by v1.user_id
) evkl on evkl.user_id=v1.user_id
--фильтруем, чтобы за фильм голосовало не менее 10 человек
join (
 select film_id, count(1) from votes group by film_id having count(1)&amp;gt;10
) flms on flms.film_id=v1.film_id
group by v1.film_id
order by sum(v1.vote*evkl.koef)/sum(evkl.koef)
&lt;/pre&gt;
&lt;br /&gt;
Вот и все!) Что нам нужно знать об этой ф-ии. Ну во первых мы ввели ограничение на минимальное кол-во голосов за фильм в 10, чтобы не вышло так, что кому-то понравился фильм, у вас с этим критиком коэффициент близкий у 1 и соответственно фильм имеет хороший вес.&lt;br /&gt;
&lt;br /&gt;
И теперь про отличие этой цифры от той, что выставлена на самом сайте &lt;a href=&quot;http://kinopoisk.ru/&quot;&gt;kinopoisk.ru&lt;/a&gt;. А отличие простое: там просто средне арифметическая по голосам и кол-ву голосовавших, а эта чисто ваша, рассчитанная исходя из сходства вкусов Вас и тех кто голосовал. Поэтому при таком подходе, у разных людей у одного и того же фильма будут разные оценки, иногда абсолютно разные!)))&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: center;&quot;&gt;
Фильтрация по схожести образцов&lt;/h3&gt;
&lt;div&gt;
Мы реализовали механизм рекомендования таким образом, что для создания набора данных необходимы оценки, выставленные каждым пользователем. Для нескольких тысяч людей или предметов это, возможно, и будет работать, но на таком большом сайте, как&amp;nbsp;&lt;a href=&quot;http://kinopoisk.ru/&quot;&gt;kinopoisk.ru&lt;/a&gt;,&amp;nbsp;сравнение каждого пользователя со всеми другими, а затем сравнение товаров, которым каждый пользователь выставил оценки, займет недопустимо много времени.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Техника, которую мы применяли до сих пор, называется&amp;nbsp;&lt;i&gt;&lt;a href=&quot;http://py-algorithm.blogspot.ru/2014/08/blog-post_11.html&quot;&gt;коллаборативной фильтрацией по схожести пользователей&lt;/a&gt;&lt;/i&gt;. Альтернатива известна под названием&amp;nbsp;&lt;i&gt;«коллаборативная фильтрация по схожести образцов»&lt;/i&gt;. Когда набор данных очень велик, коллаборативная фильтрация по схожести образцов может давать лучшие результаты, причем многие вычисления можно выполнить заранее, поэтому пользователь получит рекомендации быстрее.&lt;br /&gt;
&lt;div class=&quot;page&quot; title=&quot;Page 43&quot;&gt;
&lt;div class=&quot;layoutArea&quot;&gt;
&lt;div class=&quot;column&quot;&gt;
&lt;br /&gt;
Процедура фильтрации по схожести образцов во многом основана на уже рассмотренном материале. Основная идея заключается в том, чтобы для каждого образца заранее вычислить большинство похожих на него, при помощи запроса выше. Тогда для выработки рекомендаций пользователю достаточно будет найти те образцы, которым он выставил наивысшие оценки, и создать взвешенный список образцов, максимально похожих на эти. Отметим одно существенное отличие: хотя на первом шаге необходимо исследовать все данные, результаты сравнения образцов изменяются не так часто, как результаты сравнения пользователей. Это означает, что не нужно постоянно пересчитывать для каждого образца список похожих на него; это можно делать, когда нагрузка на сайт невелика, или вообще на отдельном компьютере.&lt;br /&gt;
&lt;br /&gt;
Итак, создадим табличку, куда будем записывать коэффициенты схожести фильмов между собой.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;CREATE TABLE movies_similarity
(
  id serial NOT NULL,
  film_id1 integer NOT NULL,
  film_id2 integer NOT NULL,
  pirson_koef double precision NOT NULL,
  CONSTRAINT movies_similarity_pk PRIMARY KEY (id)
)&lt;/pre&gt;
&lt;br /&gt;
Туда при помощи &lt;a href=&quot;http://py-algorithm.blogspot.ru/2014/08/blog-post_12.html&quot;&gt;запроса&lt;/a&gt; и конструкции&amp;nbsp;&lt;a href=&quot;http://stackoverflow.com/questions/6083132/postgresql-insert-into-select&quot;&gt;INSERT INTO&lt;/a&gt;&amp;nbsp;запишем данные фильмов, которые мы оценили уже на сайте.&lt;br /&gt;
&lt;h3 style=&quot;text-align: center;&quot;&gt;

&lt;span style=&quot;font-family: &#39;FreeSetC-Bold-Identity-H&#39;; font-size: 13.000000pt;&quot;&gt;Выдача рекомендаций&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;br /&gt;
Теперь вы готовы выдавать рекомендации, пользуясь словарем данных о схожести образцов без обращения ко всему набору данных. Необходимо получить список всех образцов, которым пользователь выставлял оценки, найти похожие и взвесить их с учетом коэффициентов подобия. Давайте разберем пример:&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdMM45DzmfzjC3T8H3wO2c7kZzRyoQD4-gwWtQAwzEsE7vLM-Z_x73AcBHEkZOmGdk5_PDbbmJ4fnHILzGy4rwInuJcxK-FgOzvaBG_iY37yq4CBaqgZs4086s1xzlRsP0Gu_9J3_V/s1600/2014-08-14+02-50-01+%E2%80%8Ebook.uzwp-contentuploads201010kol_razum.pdf.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdMM45DzmfzjC3T8H3wO2c7kZzRyoQD4-gwWtQAwzEsE7vLM-Z_x73AcBHEkZOmGdk5_PDbbmJ4fnHILzGy4rwInuJcxK-FgOzvaBG_iY37yq4CBaqgZs4086s1xzlRsP0Gu_9J3_V/s1600/2014-08-14+02-50-01+%E2%80%8Ebook.uzwp-contentuploads201010kol_razum.pdf.png&quot; height=&quot;156&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
В каждой строке указан фильм, который я смотрел, и оценка, которую я ему выставил. Для каждого фильма, который я не смотрел, имеется столбец, где показано, насколько он похож на виденные мной фильмы. Например, коэффициент подобия между фильмами «Superman» и «The Night Listener» равен 0,103. В столбцах с названиями, начинающимися с О.x, показана моя оценка, умноженная на коэффициент подобия; поскольку я поставил фильму «Superman» оценку 4,0, то, умножая число на пересечении строки «Superman» и столбца «Night» на 4,0, получаем: 4,0 × 0,103 = 0,412. &lt;br /&gt;
&lt;br /&gt;
В строке «Итого» просуммированы коэффициенты подобия и значения в столбцах «О.x» для каждого фильма. Чтобы предсказать мою оценку фильма, достаточно разделить итог для колонки «О.x» на суммарный коэффициент подобия. Так, для фильма «The Night Listener» прогноз моей оценки равен 1,378/0,433 = 3,183.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Если алгоритм понятен, давайте реализуем его: &lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;select
ms.film_id1, 
case when sum(ms.pirson_koef)&amp;lt;&amp;gt;0
then
 sum(v.vote*ms.pirson_koef)/sum(ms.pirson_koef) 
else 
 0
end
from votes v
join movies_similarity ms on ms.film_id2=v.film_id
where v.user_id=4722023
group by ms.film_id1
order by case when sum(ms.pirson_koef)&amp;lt;&amp;gt;0
then
 sum(v.vote*ms.pirson_koef)/sum(ms.pirson_koef) 
else 
 0
end desc
&lt;/pre&gt;
&lt;br /&gt;
В общем из тех 14 фильмов, что я лайкнул мне посоветовали посмотреть - &lt;a href=&quot;http://www.kinopoisk.ru/film/15780/&quot;&gt;&quot;Голова-ластик&quot;&lt;/a&gt;&lt;br /&gt;
Ну что же...думаю этим и займусь) А вы найдите себе фильм на вечер!)&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/8970987251883687769/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2014/08/blog-post_11.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/8970987251883687769'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/8970987251883687769'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2014/08/blog-post_11.html' title='Рекомендование предметов'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhu8SEQeF3miPQmcHLG6ab0FYi6MAZYXxrwbBSbn6M0KQ8x20krpnW7EQnC-svSdb0nqifQCPL7tVB0LmDIwJWtW_CmAFU6FZSFD-hYqcWnbET5V6b5ZuFjZxmyDvm9WzWmCTqbD9pscifD/s72-c/like%252Bbutton.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-3915132747707560</id><published>2014-08-10T06:29:00.001-07:00</published><updated>2014-08-11T15:56:30.303-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Машинное обучение"/><title type='text'>Оценка подобия </title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://www.ankolpakov.ru/wp-content/uploads/2012/07/%D0%9F%D0%BE%D0%B4%D0%B3%D0%BE%D1%82%D0%BE%D0%B2%D0%BA%D0%B0-%D1%80%D0%B5%D0%BF%D0%B5%D1%82%D0%B8%D1%82%D0%BE%D1%80%D0%B0-%D0%BF%D0%BE-%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B5-%D0%BA-%D0%B2%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D1%8E-%D0%BF%D0%BE%D0%B4%D0%BE%D0%B1%D0%B8%D1%8F.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://www.ankolpakov.ru/wp-content/uploads/2012/07/%D0%9F%D0%BE%D0%B4%D0%B3%D0%BE%D1%82%D0%BE%D0%B2%D0%BA%D0%B0-%D1%80%D0%B5%D0%BF%D0%B5%D1%82%D0%B8%D1%82%D0%BE%D1%80%D0%B0-%D0%BF%D0%BE-%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B5-%D0%BA-%D0%B2%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D1%8E-%D0%BF%D0%BE%D0%B4%D0%BE%D0%B1%D0%B8%D1%8F.jpg&quot; height=&quot;114&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: center;&quot;&gt;
Ищем похожих пользователей&lt;/h3&gt;
&lt;div&gt;
&lt;a href=&quot;http://py-algorithm.blogspot.ru/2014/08/blog-post.html&quot;&gt;Собрав данные&lt;/a&gt; о том, что людям нравится, нужно как-то определить, насколько их вкусы схожи. Для этого каждый человек сравнивается со всеми другими и вычисляется коэффициент подобия (или оценка подобия). Для этого есть несколько способов, я расскажу о двух из них: евклидовом расстоянии и коэффициенте корреляции Пирсона. Примеры будем разбирать, отталкиваясь от задачи поиска схожести вкусов людей к фильмам, исходя из их оценок.&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: center;&quot;&gt;
Оценка по евклидову расстоянию&lt;/h3&gt;
&lt;div&gt;
Один из самых простых способов вычисления оценки подобия – это евклидово расстояние. В этом случае предметы, которые люди оценивали сообща, представляются в виде координатных осей. Теперь в этой системе координат можно расположить точки, соответствующие людям, и посмотреть, насколько они оказались близки.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://habr.habrastorage.org/post_images/bf5/e28/f41/bf5e28f41e267ff3e34dc34fedbb9b21.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://habr.habrastorage.org/post_images/bf5/e28/f41/bf5e28f41e267ff3e34dc34fedbb9b21.png&quot; height=&quot;251&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Я думаю, некоторые из вас вспомнили формулу нахождения расстояния в пространстве между 2мя точками. Да-да) Это оно и есть, и не важно, сколь мерно наше пространство, формула легко модифицируется, добавлением квадратов разностей других координат.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://dcs.isa.ru/www/vladimirv/Geometry/dshar/sco_11.1.2/ch11.1.2-1.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://dcs.isa.ru/www/vladimirv/Geometry/dshar/sco_11.1.2/ch11.1.2-1.gif&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Расстояние, вычисленное по этой формуле, будет тем меньше, чем больше сходства между людьми. Однако нам нужна функция, значение которой тем больше, чем люди более похожи друг на друга. Этого можно добиться, добавив к вычисленному расстоянию 1 (чтобы никогда не делить на 0) и взяв обратную величину.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: center;&quot;&gt;
Коэффициент корреляции Пирсона&lt;/h3&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Чуть более сложный способ определить степень схожести интересов людей дает коэффициент корреляции Пирсона. Коэффициент корреляции – это мера того, насколько хорошо два набора данных ложатся на прямую. Формула сложнее, чем для вычисления евклидова расстояния, но она дает лучшие результаты, когда данные плохо нормализованы, например если некоторый человек устойчиво выставляет фильмам более низкие оценки, чем в среднем.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://www.neural.forekc.ru/dm1/images/1_image028.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://www.neural.forekc.ru/dm1/images/1_image028.jpg&quot; height=&quot;200&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
На картинке изображена прямая линия. Она называется линией наилучшего приближения, поскольку проходит настолько близко ко всем точкам на диаграмме, насколько возможно. В данном случае оценки одного человека, являются абсциссами точек, а оценки другого ординатами. Если бы оба человека выставили всем фильмам одинаковые оценки, то эта линия оказалась бы диагональной и прошла бы через все точки. В этом случае получилась бы идеальная корреляция с коэффициентом 1.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://rudocs.exdat.com/data/8/7212/7212_html_68bc3cf4.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://rudocs.exdat.com/data/8/7212/7212_html_68bc3cf4.gif&quot; height=&quot;104&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
У коэффициента корреляции Пирсона есть одно интересное свойство, которое можно наблюдать на рисунке – он корректирует обесценивание оценок! Что я имею ввиду? А то, что представьте. 2 человека сравнивают цены и 2й всегда ставит на 1-2 бала ниже(ну пессимист он эдакий)))) А теперь начертите прямую в голове(или листочке)) и увидите, что прямая все равно проходит почти по диагонали, а значит считает, что они могут понравиться друг-другу (сугубо с точки зрения вкусов к фильмам...а может и нет))))!&lt;br /&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
&lt;a href=&quot;&quot; name=&quot;normalize_problem&quot;&gt;&lt;/a&gt;
Проблема нормализации&lt;/h4&gt;
Но также у данного коэффициента есть одна плохая сторона. Он рассчитан наприменение к данным с нормальным распределением. А что будет, если какой то пользователь ставит всем фильмам одинаковые оценки? Можете подставить в формулу, например за место X и увидите, что в таком случае и знаменатель и числитель вырождаются в 0! Ведь это не правильно! Бывает так, что вы смотрели вместе 10 великолепных картин и он и вы ставили только 10ки и получается, что заместо коэффициента=1 мы получим 0! Геометрически такое поведение можно объяснить вырождением прямой в точку. Не знаю, как эта проблема решается правильно, а я предлагаю сделать искусственную нормализацию распределения оценок. Каким образом, а просто добавим и тому и другому оценку за несуществующий фильм отличную от тех, что они ставят, но одинаковые между собой. Причем опытным путем было замечено. что чем оценка меньше, тем меньше она влияет на коэффициент.&lt;/div&gt;
&lt;h3 style=&quot;text-align: center;&quot;&gt;
Какой оценкой подобия воспользоваться&lt;/h3&gt;
&lt;div&gt;
Я ознакомил вас с двумя разными метриками, но есть и много других способов измерить подобие двух наборов данных. Какой из них оптимален – зависит от конкретного приложения. Имеет смысл попробовать и коэффициент Пирсона, и евклидово расстояние, и другие методы, а потом посмотреть, какой дает наилучшие результаты.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Для вычисления подобия можно брать и различные другие функции, например коэффициент Жаккарда или манхэттенское расстояние, при условии что у них такая же сигнатура и возвращаемое значение с плавающей точкой тем больше, чем выше сходство.&lt;/div&gt;
&lt;h3 style=&quot;text-align: center;&quot;&gt;
Практика Евклида&lt;/h3&gt;
&lt;div&gt;
Все читали &lt;a href=&quot;http://py-algorithm.blogspot.ru/2014/08/blog-post.html&quot;&gt;предыдущую статью&lt;/a&gt;? Если да то база готова и туда пишутся данные(у меня уже 12000 пользователей Ж) И пока их не много, можно запустить секретный скрипт прям в postgre и получить результатик) Если скрипт запустить как есть, то он будет сравнивать всех со всеми в поисках идеальных пар) Если же закомментить строку 7 и наоборот раскомментить 9(подставив нужный user_id) будем искать идеал только для кого то конкретного (например для себя любимого))))&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;select
v1.user_id, v2.user_id,
1/(1+(|/sum((v1.vote-v2.vote)^2))),--евклидово не взвешенное расстояние
count(1)--кол-во общих фильмов(вес для ф-ии)
from votes v1
join votes v2 on v1.film_id=v2.film_id 
and v1.user_id &amp;lt; v2.user_id --гениально и просто убираем дубли self джойна))
where v1.user_id &amp;lt;&amp;gt; v2.user_id
--and v2.user_id=113
group by v1.user_id, v2.user_id
order by 1/(1+(|/sum((v1.vote-v2.vote)^2))) desc, count(1) desc&lt;/pre&gt;
&lt;br /&gt;
У меня он выдал 197184 результата за 703882 ms. Короче чуть не уснул и это тысячах на 6 юзверях, но если вы подождете, то будете вознаграждены) Поиск же для кого-то конкретного проходит на ура и в миллисекунды :) Нужно сразу сказать, что здесь ф-ия евклида вычисляется для мнений по одному и тому же фильму и по этому эта оценка не взвешенная! Например есть люди, которые идеально друг другу подходят (т.е. 1 выдало ;) и все потому, что у них всего 1 общий фильм из 1000 и каждый поставил по 2 балла)))) Не думаю, что таких людей можно рекомендовать друг-дружке, как братьев по вкусу))) Поэтому результаты нужно взвесть и чем больше общих фильмов оценено - тем лучше(если что count(1) именно это и считает)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;#Для ярых питонистов плюющих в души sql ворую код
# на вход prefs - словарь {чел1:{фильм1:оценка1, фильм2:оценка2,...}, чел2:{фильм?:оценка?,...}}
# кто-то может расширить ф-ию сравнения не 2х челов, а N :)
from math import sqrt

def sim_distance(prefs):
    
  person1, person2 = prefs.keys()
    
  # Получаем список фильмов, оцененных обоими
  si={item:1 for item in prefs[person1] if item in prefs[person2]}

  if si:

      # сложить квадраты разностей оценок
      sum_of_squares=sum([pow(prefs[person1][item]-prefs[person2][item],2) 
                          for item in prefs[person1] if item in prefs[person2]])

      return 1/(1+sqrt(sum_of_squares))#sqrt добавил сам, кажись автор забыл)

  # если нет ни одной общей оценки, return 0
  return 0&lt;/pre&gt;
&lt;h3 style=&quot;text-align: center;&quot;&gt;
Практика Пирсона&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
Прочитали описание коэффициента чуть выше? Тогда поехали)&lt;/div&gt;
&lt;div&gt;
Для начала скрипт sql, без &lt;a href=&quot;https://www.blogger.com/blogger.g?blogID=2551258626199289542#normalize_problem&quot;&gt;искусственной нормализации!!!&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;select
    v1.user_id, v2.user_id,
    case when (sum(v1.vote^2)-(sum(v1.vote)^2)/count(1)::float)*(sum(v2.vote^2)-(sum(v2.vote)^2)/count(1)::float) &amp;lt;&amp;gt; 0
    then
        (sum(v1.vote*v2.vote)-(sum(v1.vote)*sum(v2.vote))/count(1)::float)/(|/((sum(v1.vote^2)-(sum(v1.vote)^2)/count(1)::float)*(sum(v2.vote^2)-(sum(v2.vote)^2)/count(1)::float)))
    else
        0
    end,
    count(1)--кол-во общих фильмов(вес для ф-ии)
from votes v1
join votes v2 on v1.film_id=v2.film_id 
where v1.user_id &amp;lt;&amp;gt; v2.user_id 
and v2.user_id=113 --ищем для конкретного пользователя(так быстрее)
group by v1.user_id, v2.user_id
order by 
    case when (sum(v1.vote^2)-(sum(v1.vote)^2)/count(1)::float)*(sum(v2.vote^2)-(sum(v2.vote)^2)/count(1)::float) &amp;lt;&amp;gt; 0
    then
        (sum(v1.vote*v2.vote)-(sum(v1.vote)*sum(v2.vote))/count(1)::float)/(|/((sum(v1.vote^2)-(sum(v1.vote)^2)/count(1)::float)*(sum(v2.vote^2)-(sum(v2.vote)^2)/count(1)::float)))
    else
        0
    end
    desc,
    count(1) desc&lt;/pre&gt;
&lt;br /&gt;
Снова сворую чужую функцию для Питонистов, но теперь с решением &lt;a href=&quot;https://www.blogger.com/blogger.g?blogID=2551258626199289542#normalize_problem&quot;&gt;проблемы нормализации&lt;/a&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot; style=&quot;text-align: left;&quot;&gt;#На вход тоже, что и раньше
def sim_pearson(prefs):

  #вспомогательная ф-ия для удаления повторяющейся оценки
  def rem_vote(votes, choice_list):
 vote_for_rem = votes.pop()
 if vote_for_rem in choice_list:
  choice_list.remove(vote_for_rem)
 return choice_list#это не обязательно, т.к. элемент и так удален по ссылке, но явное лучше не явного)))

  # Получаем список фильмов, оцененных обоими
  si={}
  p1, p2 = prefs.keys()

  for item in prefs[p1]: 
    if item in prefs[p2]: si[item]=1

  #делаем нормализацию, если кто-то ставит одинаковые оценки всем фильмам
  #опытным путем пришел к тому, что чем меньше число добавляем, тем меньше его влияние
  votes1 = set([prefs[p1][it] for it in si])
  votes2 = set([prefs[p2][it] for it in si])

  if len(votes1) == 1 or len(votes2) == 1:

   choice_list = range(1, 4)#список возможных оценок от 1 до 4
   #удаляем повторяющиеся оценки
   if len(votes1) == 1:
    choice_list = rem_vote(votes1, choice_list)
   if len(votes2) == 1:
    choice_list = rem_vote(votes2, choice_list)

   it = 0#id несуществующего фильма 
   si[it] = 1#говорим, что оба оценивали фильм с этим id
   rand_vote = random.choice(choice_list)
   prefs[p1][it] = prefs[p2][it] = rand_vote
 ##############################

  # Число общих фильмов
  n=len(si)
        
  # Если общих фильмов нет
  if n==0: return 0
  
  # Суммы всех предпочтений
  sum1=sum([prefs[p1][it] for it in si])
  sum2=sum([prefs[p2][it] for it in si])
  
  # Суммы квадратов предпочтений
  sum1Sq=sum([pow(prefs[p1][it],2) for it in si])
  sum2Sq=sum([pow(prefs[p2][it],2) for it in si]) 
  
  # Сумма произведений
  pSum=sum([prefs[p1][it]*prefs[p2][it] for it in si])
  
  # Вычисляем коэффициент
  num=pSum-(sum1*sum2/n)
  den=sqrt((sum1Sq-pow(sum1,2)/n)*(sum2Sq-pow(sum2,2)/n))
  if den==0: return 0

  r=num/den

  return r
&lt;/pre&gt;
&lt;h3 style=&quot;text-align: center;&quot;&gt;
Немного о чувствительности критериев&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
К слову о том, каким критерием пользоваться, не стоит забывать об их чувствительности к деградации. О чем я? Например я сравнил себя с другим пользователем и оказалось, что мы оценили 5 общих фильмов. Причем он всем поставил 10 баллов, а я двум 9ки. Таким образом я потерял 2/50 не взвешенных баллов от 1. Но если мы вычислим реальные коэффициенты, то получим следующие результаты: Евклид=0.414, Пирса=0.981. Таким образом видно, что ф-ия Евклида очень чувствительна при малом кол-ве общих оценок.&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Советую почитать&lt;/h4&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://forexaw.com/TERMs/Economic_terms_and_concepts/Exchange_Terminology/l675_%D0%9A%D0%BE%D1%80%D1%80%D0%B5%D0%BB%D1%8F%D1%86%D0%B8%D1%8F_Correlation_%D1%8D%D1%82%D0%BE&quot;&gt;http://forexaw.com/TERMs/Economic_terms_and_concepts/Exchange_Terminology/l675_Корреляция_Correlation_это&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/3915132747707560/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2014/08/blog-post_10.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/3915132747707560'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/3915132747707560'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2014/08/blog-post_10.html' title='Оценка подобия '/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-6895407166886563171</id><published>2014-08-10T05:40:00.001-07:00</published><updated>2014-08-10T10:09:17.560-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Машинное обучение"/><title type='text'>Машинное обучение. Начало.</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://diason.ru/images/img/643.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://diason.ru/images/img/643.jpg&quot; height=&quot;195&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h2 style=&quot;text-align: center;&quot;&gt;
Предисловие&lt;/h2&gt;
&lt;div&gt;
Итак, начнем цикл статей про машинное обучение) В основном он будет основан на материале из различных книг, но основная идея цикла - это подача!) А подавать будем, попытавшись написать реальный проектик и попрактиковавшись в различных интересных штукенциях)&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: center;&quot;&gt;
В поисках данных&lt;/h3&gt;
Итак, нам нужны данные - много данных!) И желательно интересных. Не знаю, как вы, но я долго думать не стал и воспользовался сайтом &lt;a href=&quot;http://www.kinopoisk.ru/&quot;&gt;kinopoisk.ru&lt;/a&gt;, надеюсь сильно бить не будут, ведь мы будем взращивать их будущие кадры(т.е. Вас!)))
&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;
Начнем с конфигурации. В разных книгах примеры данных хранятся во всяких rss, plain files и прочей не современной чепухе) Мы то с Вами живем в то время, когда даже слово sql стыдно произносить в приличном обществе, без приставки no!) Но мы произнесем - &lt;a href=&quot;http://www.postgresql.org/&quot;&gt;PostgreSQL&lt;/a&gt;! Начнем с установки(ищем, где ищется)) а закончим созданием таблички votes.
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;CREATE TABLE votes
(
  id serial NOT NULL, --уникальный идентификатор
  user_id integer NOT NULL, --id пользователя с сайта
  film_id integer NOT NULL, --id фильма с сайта
  vote smallint NOT NULL, --оценка фильму пользователем от 1 до 10
  CONSTRAINT vote_id PRIMARY KEY (id)
)&lt;/pre&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;&lt;/pre&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;&lt;/pre&gt;
Объяснять столбцы не буду!!!))) Если все получилось, давайте добавим данных. Бить меня не нужно, можно только корректировать, я для Вас написал следующее чудо, запускаем и...не ждем, а приступаем к работе, он и сам справится, за несколько лет)) У меня на момент написания этих строк обработано 9000 пользователей из как минимум 4722023 (спалился:)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;import re, psycopg2
from lxml.html import parse
from lxml.cssselect import CSSSelector

def get_user_voites():

 user_start_num = 200
 user_end_num = 4722023

 try:
  conn=psycopg2.connect(&quot;dbname=&#39;postgres&#39; user=&#39;postgres&#39; password=&#39;120789&#39; host=&#39;localhost&#39;&quot;)
  cur = conn.cursor()
  page_num_sel = CSSSelector(&#39;div.pagesFromTo&#39;)

  for user_num in xrange(user_start_num, user_end_num):

   vote_film_list = []
   loop_bool = True
   page_num = 1

   while loop_bool:
    try:
     page = parse(&#39;http://www.kinopoisk.ru/user/%s/votes/list/ord/date/page/%s/&#39; % (user_num, page_num))

     vote_count_div = int(page_num_sel(page)[0].text.split()[-1])

     items = page.xpath(&quot;//div[contains(@class, &#39;item&#39;)]&quot;)
     for item in items:
      try:
       film_div = item.find(&quot;div[@class=&#39;info&#39;]&quot;).find(&quot;div[@class=&#39;nameRus&#39;]&quot;).find(&quot;a&quot;)

       vote_num = int(item.find(&quot;div[@class=&#39;num&#39;]&quot;).text)
       film_id = re.search(&#39;film\/(\d)+\/$&#39;, film_div.values()[0]).group(0)[5:-1]
       film_name = film_div.text
       vote = item.find(&quot;div[@class=&#39;vote&#39;]&quot;).text

       if vote and film_id:
        vote_film_list.append({&#39;vote&#39;: vote, &#39;user_id&#39;: user_num, &#39;film_id&#39;: film_id})
      except:
       pass

     if vote_num &amp;lt;= vote_count_div:
      page_num += 1

     print vote_num, page_num, vote_count_div, len(vote_film_list)
     cur.executemany(&quot;&quot;&quot;INSERT INTO votes(user_id, film_id, vote) VALUES (%(user_id)s, %(film_id)s, %(vote)s)&quot;&quot;&quot;, vote_film_list)
     conn.commit()
     vote_film_list = []

    except Exception, e:
     print e
     loop_bool = False


 except Exception, e:
  print &quot;I am unable to connect to the database.&quot;, e

 finally:
  if conn:
   conn.close()
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/6895407166886563171/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2014/08/blog-post.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/6895407166886563171'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/6895407166886563171'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2014/08/blog-post.html' title='Машинное обучение. Начало.'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-7569328126418528073</id><published>2013-04-25T03:53:00.000-07:00</published><updated>2013-04-25T03:53:16.688-07:00</updated><title type='text'>Алгоритм Бойера - Мура</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBarJkTzY20BbAjVwdk7HhiLreD35umMJgDQuhyphenhyphenpZs4G01kwshbZ4NtPg7p_3QsYUjAwXBPBRS7JxMNMpI7PnwkH5LkXGflUSV8Rz__sh-LkiZH8z6UguzyXieDcfZxW5YRh4CkjfX/s1600/39_03.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBarJkTzY20BbAjVwdk7HhiLreD35umMJgDQuhyphenhyphenpZs4G01kwshbZ4NtPg7p_3QsYUjAwXBPBRS7JxMNMpI7PnwkH5LkXGflUSV8Rz__sh-LkiZH8z6UguzyXieDcfZxW5YRh4CkjfX/s1600/39_03.png&quot; height=&quot;156&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Алгоритм поиска строки Бойера — Мура считается наиболее быстрым среди алгоритмов общего назначения, предназначенных для &lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%B8%D1%81%D0%BA_%D0%BF%D0%BE%D0%B4%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8&quot;&gt;поиска подстроки в строке&lt;/a&gt;. Был разработан &lt;a href=&quot;http://ru.wikipedia.org/w/index.php?title=%D0%91%D0%BE%D0%B9%D0%B5%D1%80,_%D0%A0%D0%BE%D0%B1%D0%B5%D1%80%D1%82&amp;amp;action=edit&amp;amp;redlink=1&quot;&gt;Робертом Бойером&lt;/a&gt;&amp;nbsp;и &lt;a href=&quot;http://ru.wikipedia.org/w/index.php?title=%D0%9C%D1%83%D1%80,_%D0%94%D0%B6%D0%B5%D0%B9&amp;amp;action=edit&amp;amp;redlink=1&quot;&gt;Джеем Муром&lt;/a&gt; в 1977 году. Преимущество этого алгоритма в том, что ценой некоторого количества предварительных вычислений над шаблоном (но не над строкой, в которой ведётся поиск) шаблон сравнивается с исходным текстом не во всех позициях — часть проверок пропускаются как заведомо не дающие результата.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Мы с Вами уже рассмотрели 2 подхода поиска подстроки: &lt;a href=&quot;http://py-algorithm.blogspot.ru/2013/04/blog-post.html&quot;&gt;в лоб&lt;/a&gt; и &lt;a href=&quot;http://py-algorithm.blogspot.ru/2013/04/blog-post_19.html&quot;&gt;Кнута - Морриса - Пратта&lt;/a&gt;.&lt;br /&gt;
И хотя последний можно отнести к правильным, сегодня мы разберем подход, являющийся классикой в решении данной задачи.&lt;br /&gt;
Простота, является характеристикой правильного решения и тривиальность данного подхода это подтверждает.&lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритм - начать поиск не с начала, а с конца подстроки. Наткнувшись на несовпадение, мы просто смещаем подстроку до самого правого вхождения данного символа.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пример можете посмотреть в картинке заголовка :)&lt;br /&gt;
&lt;br /&gt;
Можно заметить, что, как и в случае Кнута-Морриса-Пратта, мы так же можем осуществить предкомпиляцию выражения.&lt;br /&gt;
&lt;br /&gt;
Для этого удобно в словарь заносить пары ключ = числовое значение символа(ord), значение = порядковый номер в подстроке.&lt;br /&gt;
&lt;br /&gt;
А вот и реализация:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def bmPredCompil(x):
    d = {}
    lenX = len(x)
    for i in xrange(len(x)):
        # сколько символов с правого края до этой буквы
        d[ord(x[i])] = lenX - i
    return d

Осталось осуществить сам поиск со сдвигом:

def boyerMurSearch(s, x):
    d = bmPredCompil(x)
    # k - проход по s
    # j - проход по x
    # i - место начала прохода по s
    lenX = i = j = k = len(x)
    while j &amp;gt; 0 and i&amp;lt;=len(s):
     # совпали, двигаемся дальше (от конца к началу)
        if s[k-1] == x[j-1]:
            k -= 1
            j -= 1
        # иначе, продвигаемся по строке на d и начинаем с правого конца подстроки снова
        else:
            i += d[ord(s[i])]
            j = lenX
            k = i
    if j &amp;lt;= 0:# нашли
        return k
    return None # не нашли&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
Вот собственно и все! :)&lt;br /&gt;
Реализация, как и сама идея, достаточно прозрачна.&lt;br /&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/7569328126418528073/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2013/04/blog-post_4517.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/7569328126418528073'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/7569328126418528073'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2013/04/blog-post_4517.html' title='Алгоритм Бойера - Мура'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBarJkTzY20BbAjVwdk7HhiLreD35umMJgDQuhyphenhyphenpZs4G01kwshbZ4NtPg7p_3QsYUjAwXBPBRS7JxMNMpI7PnwkH5LkXGflUSV8Rz__sh-LkiZH8z6UguzyXieDcfZxW5YRh4CkjfX/s72-c/39_03.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-1828211878050860297</id><published>2013-04-25T02:48:00.002-07:00</published><updated>2013-04-25T03:06:59.292-07:00</updated><title type='text'>Задача о путешествии шахматного коня</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_W46UfpFqTIIHGhFE0MKuq6VSglrZGidfx4NdyT8Vb87EMvoKPTbYPz7_oKEvoGYkJ3P1XUtXz5bQxS2546EmD6pis9vGVF1rZZ-1BKv4eCiuH9aEY7KLnfiPn2WmF2DFJM3SefkP/s1600/images.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_W46UfpFqTIIHGhFE0MKuq6VSglrZGidfx4NdyT8Vb87EMvoKPTbYPz7_oKEvoGYkJ3P1XUtXz5bQxS2546EmD6pis9vGVF1rZZ-1BKv4eCiuH9aEY7KLnfiPn2WmF2DFJM3SefkP/s1600/images.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19.1875px; margin-bottom: 0.5em; margin-top: 0.4em;&quot;&gt;
&lt;b&gt;Задача о ходе коня&lt;/b&gt;&amp;nbsp;— задача о нахождении маршрута&amp;nbsp;шахматного коня, проходящего через все поля&amp;nbsp;доски&amp;nbsp;по одному разу.&lt;/div&gt;
&lt;div style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19.1875px; margin-bottom: 0.5em; margin-top: 0.4em;&quot;&gt;
Эта задача известна по крайней мере с&amp;nbsp;XVIII века.&amp;nbsp;Леонард Эйлер&amp;nbsp;посвятил ей большую работу «Решение одного любопытного вопроса, который, кажется, не подчиняется никакому исследованию» (датируется&amp;nbsp;26 апреля&amp;nbsp;1757 года).&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Когда то давно, мы уже рассматривали пример решения задачи рекурсивным образом, на примере &lt;a href=&quot;http://py-algorithm.blogspot.ru/2011/04/blog-post_20.html&quot;&gt;задачи по размену денег&lt;/a&gt;. Пришло время вспомнить некоторые классические подходы и начать хотелось бы с задачи&amp;nbsp;о путешествии шахматного коня.&lt;br /&gt;
&lt;br /&gt;
Решение приведенное ниже относится к так называемым алгоритмам с возвратом.&lt;br /&gt;
Разделяй и властвуй -основная идея рекурсии. Т.е. мы сложную задачу делим на маленькие простые &amp;nbsp;решаем их по отдельности в цепочке. В случае данной задачи, можно рассмотреть подзадачу, которая состоит в том, чтобы либо выполнить какой-либо очередной ход, либо обнаружить, что дальнейшие ходы невозможны.&lt;br /&gt;
&lt;br /&gt;
Итак, каждый ход мы будем характеризовать 3-мя числами: его порядковым номером i и парой координат x, y. История ходов будет храниться в матрице списков, в соответствующей ячейке записываем порядковый номер хода. Соответственно, если в ячейке 0, значит туда мы еще не ходили.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglluQw3yk2m0tlS4ZcyBvlgMuwMj38mVfbhoQXyzIdkPL5Ikm5jZnb9hW-aLDzu_PaZDhzv1tpcqKMZuTcKzBQUc-U78FXsCAehnjr8nYT5trt73A392_IOcxSjwvLti47sQrI0QpV/s1600/images.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglluQw3yk2m0tlS4ZcyBvlgMuwMj38mVfbhoQXyzIdkPL5Ikm5jZnb9hW-aLDzu_PaZDhzv1tpcqKMZuTcKzBQUc-U78FXsCAehnjr8nYT5trt73A392_IOcxSjwvLti47sQrI0QpV/s1600/images.jpg&quot; height=&quot;139&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Важно определиться с вычислением новой координаты. Можно заметить, что у коня есть 8 позиций-кандидатов (u, v) куда может прыгнуть конь.&lt;br /&gt;
Будем получать новые координаты прибавляя соответствующие смещения, хранящиеся в 2х списках dx, dy и отслеживать допустимость хода (находимся в пределах доски).&lt;br /&gt;
&lt;br /&gt;
Характерной чертой данного алгоритма является то, что каждый шаг, выполняемый в попытке приблизиться к полному решению, запоминается таким образом, чтобы от него можно было позднее отказаться, если выяснится, что он не может привести к полному решению. Такое действие называется &lt;i&gt;возвратом&lt;/i&gt;. А класс алгоритмов, как не трудно догадаться, &lt;i&gt;алгоритмы с возвратом&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Очень советую читать именно алгоритм, тем более Питон в этом сильно помогает. Это даст куда больше толку. чем множество лишних слов!)&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;#Задача о коняшке
def knightsTour(x0, y0, done, size=5):
    #создаем шахматную доску в виде 2го списка
    h = [[0 for j in xrange(size)] for i in xrange(size)]
    #начальная координата(1го хода)
    h[x0][y0] = 1
    
    #Возможные ходы
    dx = [2, 1, -1, -2, -2, -1, 1, 2]
    dy = [1, 2, 2, 1, -1, -2, -2, -1]

    def CanBeDone(u, v, i):
        h[u][v] = i
        done = tryNextMove(u, v, i)
        if not done:
            h[u][v] = 0
        return done
    
    def tryNextMove(x,y, i):
        
        #eos - показывает все ли варианты возможных 8ми ходов мы рассмотрели
        #done - показывает удачна ли данная ветка решения
        #k - порядковый номер рассмотренной попытки из 8 допустимых
        env = {&#39;done&#39;: False, &#39;eos&#39;: False, &#39;u&#39;: x, &#39;v&#39;: y, &#39;k&#39;: -1}

        def next():
            x = env[&#39;u&#39;]
            y = env[&#39;v&#39;]
            while env[&#39;k&#39;] &amp;lt; 8:
                env[&#39;k&#39;] +=1;
                if env[&#39;k&#39;] &amp;lt; 8:
                    env[&#39;u&#39;] = x + dx[env[&#39;k&#39;]]
                    env[&#39;v&#39;] = y + dy[env[&#39;k&#39;]]
                if (env[&#39;u&#39;] &amp;gt;= 0 and env[&#39;u&#39;]&amp;lt;size) and (env[&#39;v&#39;]&amp;gt;=0 and env[&#39;v&#39;]&amp;lt;size) and h[env[&#39;u&#39;]][env[&#39;v&#39;]]==0:
                    break
            env[&#39;eos&#39;] = (env[&#39;k&#39;]==8)

        if i &amp;lt; size**2:#если доска не заполнена
            next()
            while not env[&#39;eos&#39;] and not CanBeDone(env[&#39;u&#39;], env[&#39;v&#39;], i+1):
                next()
            done = not env[&#39;eos&#39;]
        else:
            done = True
        return done

    tryNextMove(x0, y0, 1)
    print h&lt;/pre&gt;
&lt;br /&gt;
Привожу пример заполнения шахматной доски.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2XEjU6NxO989P0MTZioEL8csb2VhnhPE386RauD_GDSGT_RqtzLnTnmudMukQ5ibbMMdLvLjAOreFAm6Jea5Gcr5mgqXT-m0a8NJzMtScO3B6gOxBbdiOoovf7s5c4GBasE5z-r4y/s1600/44712186_image006.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2XEjU6NxO989P0MTZioEL8csb2VhnhPE386RauD_GDSGT_RqtzLnTnmudMukQ5ibbMMdLvLjAOreFAm6Jea5Gcr5mgqXT-m0a8NJzMtScO3B6gOxBbdiOoovf7s5c4GBasE5z-r4y/s1600/44712186_image006.jpg&quot; height=&quot;204&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/1828211878050860297/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2013/04/blog-post_25.html#comment-form' title='Комментарии: 5'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/1828211878050860297'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/1828211878050860297'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2013/04/blog-post_25.html' title='Задача о путешествии шахматного коня'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_W46UfpFqTIIHGhFE0MKuq6VSglrZGidfx4NdyT8Vb87EMvoKPTbYPz7_oKEvoGYkJ3P1XUtXz5bQxS2546EmD6pis9vGVF1rZZ-1BKv4eCiuH9aEY7KLnfiPn2WmF2DFJM3SefkP/s72-c/images.jpg" height="72" width="72"/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-4154923947473640730</id><published>2013-04-19T06:15:00.000-07:00</published><updated>2013-04-19T06:15:14.327-07:00</updated><title type='text'>Алгоритм Кнута-Морриса-Пратта (КМП)</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsuRXkdtiEgSc-d-hEjUErMODmCQ6vAKOXE30zV350foO5ViUDNgF0jRAEZa6y-zuklfkjxYg8wO-PXXMmDbQVxS78VE05VmXG3HWTdHGE3GDcgbowfjafXSGagFP1rTveWLVROHZb/s1600/39_02.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsuRXkdtiEgSc-d-hEjUErMODmCQ6vAKOXE30zV350foO5ViUDNgF0jRAEZa6y-zuklfkjxYg8wO-PXXMmDbQVxS78VE05VmXG3HWTdHGE3GDcgbowfjafXSGagFP1rTveWLVROHZb/s1600/39_02.png&quot; height=&quot;140&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Алгоритм был разработан Кнутом (Knuth) и Праттом (Pratt) и независимо от них Моррисом (Morris) в 1977 г.&lt;br /&gt;
&lt;br /&gt;
Он относится к &quot;правильным&quot; подходам решения поставленной задачи, в отличии от тривиального подхода, рассмотренного &lt;a href=&quot;http://py-algorithm.blogspot.ru/2013/04/blog-post.html&quot;&gt;ранее&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Данный подход хоть и считается достаточно тривиальным, описания, которые нашел я, зачастую пестрят математическими основами и доказательствами, которые сбивают с сути. Так в книге, уважаемого Никлауса Вирта, приводится описание, которое я так и не одолел.&lt;br /&gt;
Однако я нашел пару статей, которые достаточно информативны, они приведены в ссылках и рекомендуемы для ознакомления.&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;Для понимания:&amp;nbsp;&lt;i style=&quot;background-color: white; border: 0px; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;Префикс строки&lt;/i&gt;&lt;span style=&quot;background-color: white; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;b style=&quot;background-color: white; border: 0px; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;A[&lt;/b&gt;&lt;span style=&quot;background-color: white; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px;&quot;&gt;..i&lt;/span&gt;&lt;b style=&quot;background-color: white; border: 0px; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;]&lt;/b&gt;&lt;span style=&quot;background-color: white; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px;&quot;&gt;&amp;nbsp;— это строка из i первых символов строки&amp;nbsp;&lt;/span&gt;&lt;b style=&quot;background-color: white; border: 0px; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;A&lt;/b&gt;&lt;span style=&quot;background-color: white; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px;&quot;&gt;.&amp;nbsp;&lt;/span&gt;&lt;i style=&quot;background-color: white; border: 0px; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;Суффикс строки&lt;/i&gt;&lt;span style=&quot;background-color: white; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;b style=&quot;background-color: white; border: 0px; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;A[&lt;/b&gt;&lt;span style=&quot;background-color: white; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px;&quot;&gt;j..&lt;/span&gt;&lt;b style=&quot;background-color: white; border: 0px; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;]&lt;/b&gt;&lt;span style=&quot;background-color: white; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px;&quot;&gt;&amp;nbsp;— это строка из |&lt;/span&gt;&lt;b style=&quot;background-color: white; border: 0px; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;A&lt;/b&gt;&lt;span style=&quot;background-color: white; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px;&quot;&gt;|-j+1 последних символов. Подстроку из&amp;nbsp;&lt;/span&gt;&lt;b style=&quot;background-color: white; border: 0px; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;A&lt;/b&gt;&lt;span style=&quot;background-color: white; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px;&quot;&gt;будем обозначать как&amp;nbsp;&lt;/span&gt;&lt;b style=&quot;background-color: white; border: 0px; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;A[&lt;/b&gt;&lt;span style=&quot;background-color: white; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px;&quot;&gt;i..j&lt;/span&gt;&lt;b style=&quot;background-color: white; border: 0px; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;]&lt;/b&gt;&lt;span style=&quot;background-color: white; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px;&quot;&gt;, а&amp;nbsp;&lt;/span&gt;&lt;b style=&quot;background-color: white; border: 0px; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;A[&lt;/b&gt;&lt;span style=&quot;background-color: white; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px;&quot;&gt;i&lt;/span&gt;&lt;b style=&quot;background-color: white; border: 0px; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;]&lt;/b&gt;&lt;span style=&quot;background-color: white; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px;&quot;&gt;&amp;nbsp;— i-ый символ строки.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
В статье &lt;a href=&quot;http://habrahabr.ru/post/111449/&quot;&gt;http://habrahabr.ru/post/111449/&lt;/a&gt; сказано:&lt;br /&gt;
&lt;br /&gt;
Идея КМП-поиска – при каждом несовпадении двух символов текста и образа образ сдвигается на все пройденное расстояние, так как меньшие сдвиги не могут привести к полному совпадению.&lt;br /&gt;
&lt;br /&gt;
Многие люди ошибаются в этом пункте, считая, что не надо возвращаться назад, а можно продолжать обработку строки A с текущей позиции. Почему это не так легко продемонстрировать на примере поиска X=«AAAB» в A=«AAAAB». Первая гипотеза нас приведет к четвертому символу A: &quot;AAAAB&quot;, где мы обнаружим несоответствие. Если не откатиться назад, то вхождение мы так и не обнаружим, хотя оно есть.&lt;br /&gt;
&lt;br /&gt;
Для реализации данного алгоритма, нам необходимо рассмотреть, так называемую, префикс функцию.&lt;br /&gt;
&lt;br /&gt;
Префикс-функция - это массив чисел, вычисляющийся, как наибольшая длина суффикса, совпадающего с её префиксом. Как пример, берем каждый возможный префикс строки и смотрим самое длинное совпадение начала с концом префикса (не учитывая тривиальное совпадение самого с собой).&lt;br /&gt;
&lt;br /&gt;
Вот пример для «ababcaba»:&lt;br /&gt;
&lt;table style=&quot;background-color: white; border-collapse: collapse; border-spacing: 0px; border: 1px solid rgb(204, 204, 204); clear: both; color: black; font-family: Verdana, sans-serif; font-size: 13px; line-height: 20px; margin: 1.5em 0px; outline: 0px; padding: 0px; vertical-align: baseline; width: 809px;&quot;&gt;&lt;tbody style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;
&lt;tr style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;&lt;th style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;суффикс&lt;/th&gt;&lt;th style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;префикс&lt;/th&gt;&lt;th style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;p&lt;/th&gt;&lt;/tr&gt;
&lt;tr style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;a&lt;/td&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;a&lt;/td&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;0&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;ab&lt;/td&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;ab&lt;/td&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;0&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;ab&lt;b style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;a&lt;/b&gt;&lt;/td&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;&lt;b style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;a&lt;/b&gt;ba&lt;/td&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;1&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;ab&lt;b style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;ab&lt;/b&gt;&lt;/td&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;&lt;b style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;ab&lt;/b&gt;ab&lt;/td&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;2&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;ababc&lt;/td&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;ababc&lt;/td&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;0&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;ababc&lt;b style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;a&lt;/b&gt;&lt;/td&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;&lt;b style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;a&lt;/b&gt;babca&lt;/td&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;1&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;ababc&lt;b style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;ab&lt;/b&gt;&lt;/td&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;&lt;b style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;ab&lt;/b&gt;abcab&lt;/td&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;2&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;ababc&lt;b style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;aba&lt;/b&gt;&lt;/td&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;&lt;b style=&quot;border: 0px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;aba&lt;/b&gt;bcaba&lt;/td&gt;&lt;td style=&quot;border: 1px solid rgb(204, 204, 204); margin: 0px; outline: 0px; padding: 0.3em; vertical-align: baseline; word-break: break-word;&quot;&gt;3&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
Итак, идея ясна? Ну тогда попробум написать префикс функцию в лоб:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def predkompil(x):
    #первый символ всегда 0, поэтому заносим и пропускаем
    d = {0:0}
    for i in xrange(1,len(x)):
     # проходоим от конца к началу
        j = i
        sdvig = 0
        while j&amp;gt;0:
            j -= 1
            if x[j] == x[i-sdvig]:
                sdvig += 1
            else:
                j += sdvig
                sdvig = 0
        d[i] = sdvig
    return d&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
Вроде работает, но как то много сравнений и проходов. Попробуем оптимизировать.&lt;br /&gt;
Начать можно с замены строки j = i, на j = d[i-1]+1.&lt;br /&gt;
&lt;br /&gt;
Что нам это дает? А то, что незачем просматривать каждый раз с конца и до начала. &amp;nbsp;Можно заметить, что если мы на предыдущем шаге (i-1) нашли вхождение &amp;gt; 0 (d[i-1]), то и начинать стоит с данной позиции (d[i-1]).&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
При i=4 &lt;b&gt;AB&lt;/b&gt;A&lt;b&gt;AB&lt;/b&gt; -&amp;gt; 2, тогда на i+1, т.е. i=5 &amp;nbsp;смотрим не с j=i(5), а с 3! Т.к. либо счетчик вырастет и станет 3 в случае&amp;nbsp;&lt;b&gt;ABAABA&lt;/b&gt;, либо сбросится в 0 при любой другой букве.&lt;br /&gt;
И хотя мы делаем меньше сравнений(пропускаем середину слова), однако весь совпадающий префикс мы проходим, что не есть хорошо.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Это уже не плохо, однако, мы с Вами так и не научились использовать &amp;nbsp;информацию, полученную на предыдущих итерациях.&lt;br /&gt;
&lt;br /&gt;
Зная длину совпадения префикса с суффиксом по предыдущей букве, мы можем начать поиск сразу с этой позиции (d[j-1]) и продвигаясь вперед либо увеличивать данное значение (суффикс равный префиксу продолжит свой рост), либо обнуляется (нет совпадения).&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def predkompil2(x):
    d = {0:0}
    for i in xrange(1,len(x)):
        j = d[i-1]#эту строку мы заменили
        while j &amp;gt; 0 and x[j] &amp;lt;&amp;gt; x[i]:
            j = d[j-1]
        if x[j] == x[i]:
            j += 1
        d[i] = j
    return d&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
В статье на &lt;a href=&quot;http://habrahabr.ru/post/113266/&quot;&gt;хабре&lt;/a&gt;, вы можете ознакомиться с так называемой z-функцией.&lt;br /&gt;
Идея её очень схожа с префикс функцией, поэтому её реализацию я опущу :)&lt;br /&gt;
&lt;br /&gt;
Итак, префикс функция готова, осталось применить её и решить поставленную задачу.&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def kmpSearch(s, x):
    d = predkompil2(x)
    i = j = 0
    while i&amp;lt;len(s) and j&amp;lt;len(x):
        if x[j] == s[i]:
            i+=1
            j+=1
        elif j==0:
            i+=1
        else:
            j = d[j-1]
    else:
        if j == len(x):
            return i-j
        return None&lt;/pre&gt;
&lt;br /&gt;
Вот такая идея описывается в книге Вирта, зная значения префикс ф-ии сдвигаться на заданное расстояние, однако кто-то мог заметить, что для решения задачи, нам достаточно было использовать только префикс функцию. Для этого достаточно сделать конкатенацию искомой подстроки, со строкой, через разделитель, заведомо уникальный(что-то вроде #) и применив префикс ф-ию. Если она даст значение равное длине искомой подстроки, значит мы нашли это место иначе - нет.
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def kmpSearchByCompil(s, x):
    d = {0:0}
    template = x + &#39;#&#39; + s
    for i in xrange(1,len(template)):
        j = d[i-1]#незачем смотреть всю строку, можно посмотреть со сдвига прошлой подстроки
        while j &amp;gt; 0 and template[j] &amp;lt;&amp;gt; template[i]:
            j = d[j-1]
        if template[j] == template[i]:
            j += 1
        d[i] = j
        if j == len(x):
            return i
    return None &lt;/pre&gt;
&lt;pre class=&quot;brush: python&quot;&gt;
&lt;/pre&gt;
&lt;br /&gt;
Надеюсь, идея понятна.&lt;br /&gt;
Мы рассмотрели с Вами один из &quot;правильных&quot; алгоритмов поиска подстроки, однако, классикой данной задачи стал алгоритм Бойера - Мура.&lt;br /&gt;
Автор статьи на Хабре утверждает, что он достаточно не тривиален и запутан, однако вынужден с ним не согласиться, что и покажу в следующей заметке.&lt;br /&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/4154923947473640730/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2013/04/blog-post_19.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/4154923947473640730'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/4154923947473640730'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2013/04/blog-post_19.html' title='Алгоритм Кнута-Морриса-Пратта (КМП)'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsuRXkdtiEgSc-d-hEjUErMODmCQ6vAKOXE30zV350foO5ViUDNgF0jRAEZa6y-zuklfkjxYg8wO-PXXMmDbQVxS78VE05VmXG3HWTdHGE3GDcgbowfjafXSGagFP1rTveWLVROHZb/s72-c/39_02.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-2419227711449025125</id><published>2013-04-18T06:57:00.002-07:00</published><updated>2013-04-19T06:16:03.658-07:00</updated><title type='text'>Поиск первого вхождение подстроки. Решение в лоб.</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFzxKdZi77O89n0Edm0AAMbAGU1qedIrEEpLjXwkk8F_qis8nAfr0A6fLHznuiyCJ5KNpx8Yz6OOH21asRT03Fa78o3wEEd_1Li4TWqxdWdurMkNqd6wHSDY0rPsL7g1SpnEPjkmab/s1600/images.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFzxKdZi77O89n0Edm0AAMbAGU1qedIrEEpLjXwkk8F_qis8nAfr0A6fLHznuiyCJ5KNpx8Yz6OOH21asRT03Fa78o3wEEd_1Li4TWqxdWdurMkNqd6wHSDY0rPsL7g1SpnEPjkmab/s1600/images.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Поиск информации — одно из основных использований компьютера. Одна из простейших задач поиска информации — поиск точно заданной подстроки в строке. Тем не менее, эта задача чрезвычайно важна — она применяется в текстовых редакторах, СУБД, поисковых машинах…&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
С поиском подстроки мы встречаемся постоянно. Всем любимый ctrl+f, это именно то, что нам нужно.&lt;br /&gt;
Часто ли вы задумывались, а как оно работает? Многие из Вас, наверняка, скажут, что если потребуется - сделаем.&lt;br /&gt;
Большинство, думаю, решат эту задачу в лоб и для наглядности я покажу, как это сделать.&lt;br /&gt;
&lt;br /&gt;
Прямой поиск, или, как еще часто говорят, «просто взять и поискать» - это первое решение, которое приходит в голову неискушенному программисту. Суть проста: идти по проверяемой строке A и искать в ней вхождение первого символа искомой строки X. Когда находим, делаем гипотезу, что это и есть то самое искомое вхождение. Затем остается проверять по очереди все последующие символы шаблона на совпадение с соответствующими символами строки A. Если они все совпали — значит вот оно, прямо перед нами. Но вот если какой-то из символов не совпал, то ничего не остается, как признать нашу гипотезу неверной, что возвращает нас к символу, следующему за вхождением первого символа из X.&lt;br /&gt;
&lt;br /&gt;
Многие люди ошибаются в этом пункте, считая, что не надо возвращаться назад, а можно продолжать обработку строки A с текущей позиции. Почему это не так, легко продемонстрировать на примере поиска X=«AAAB» в A=«AAAAB». Первая гипотеза нас приведет к четвертому символу A: &quot;AAAAB&quot;, где мы обнаружим несоответствие. Если не откатиться назад, то вхождение мы так и не обнаружим, хотя оно есть.&lt;br /&gt;
Неправильные гипотезы неизбежны, а из-за таких откатываний назад, при плохом стечении обстоятельств, может оказаться, что мы каждый символ в A проверили около |X| раз. То есть вычислительная сложность сложность алгоритма O(|X||A|). Так поиск фразы в параграфе может и затянуться...&lt;br /&gt;
&lt;br /&gt;
Справедливости ради следует отметить, что если строки невелики, то такой алгоритм может работать быстрее «правильных» алгоритмов за счет более предсказуемого с точки зрения процессора поведения.&lt;br /&gt;
&lt;br /&gt;
А вот и реализация:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def stringSearch(s, x):
    i=j=0
    lengthS = len(s)# Длина строки в которой ищем
    lengthX = len(x)# -||- которую ищем
    # пока не достигли одного из концов
    while i&amp;lt;=lengthS - lengthX and j&amp;gt;lengthx:
     # если совпали буквы продвигаемся по обеим строкам
        if li[i+j]==x[j]:
            j+=1
        # иначе двигаемся по строке(+1), начиная с 0 символа подстроки
        else:
            i+=1
            j=0
    # если дошли до конца подстроки - нашли, иначе - нет
    return i if j==lengthX else None&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
Алгоритм прост и тривиален, а главное, как было замечено выше, зачастую неплохо работает, особенно, когда строка поиска не сильно велика.&lt;br /&gt;
Разобравшись с прямым подходм, давайте &amp;nbsp;посмотрим, как решать эту задачу - правильно.&lt;br /&gt;
&lt;a href=&quot;http://py-algorithm.blogspot.ru/2013/04/blog-post_19.html&quot;&gt;Алгоритм Кнута-Морриса-Пратта (КМП)&lt;/a&gt;&lt;br /&gt;
Алгоритм Бойера - Мура&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;&lt;b&gt;Используемая литература:&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;&lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%B8%D1%81%D0%BA_%D0%BF%D0%BE%D0%B4%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8&quot;&gt;Википедия&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;&lt;a href=&quot;http://habrahabr.ru/post/113266/&quot;&gt;habrahabr&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/2419227711449025125/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2013/04/blog-post.html#comment-form' title='Комментарии: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/2419227711449025125'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/2419227711449025125'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2013/04/blog-post.html' title='Поиск первого вхождение подстроки. Решение в лоб.'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFzxKdZi77O89n0Edm0AAMbAGU1qedIrEEpLjXwkk8F_qis8nAfr0A6fLHznuiyCJ5KNpx8Yz6OOH21asRT03Fa78o3wEEd_1Li4TWqxdWdurMkNqd6wHSDY0rPsL7g1SpnEPjkmab/s72-c/images.jpg" height="72" width="72"/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-4271277225898325984</id><published>2013-02-12T11:24:00.000-08:00</published><updated>2014-01-09T21:05:52.894-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Поиск"/><title type='text'>Линейный поиск</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifeWSYWhNREO3TGhi5JPork2KaknU92HVALTdLfspH4jUD5w0fl1fDy_d7cAuE-xqsTXEUYStpeZzeC6T7POKmUPxdtApPPLQrx8znaIAGjPT_GVw6xaEcFRcGtW7Sg5qTlUzFXL7R/s1600/0002-002-Linejnyj-poisk.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifeWSYWhNREO3TGhi5JPork2KaknU92HVALTdLfspH4jUD5w0fl1fDy_d7cAuE-xqsTXEUYStpeZzeC6T7POKmUPxdtApPPLQrx8znaIAGjPT_GVw6xaEcFRcGtW7Sg5qTlUzFXL7R/s320/0002-002-Linejnyj-poisk.jpg&quot; width=&quot;320&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Линейный, последовательный поиск — алгоритм нахождения заданного значения произвольной функции на некотором отрезке. Данный алгоритм является простейшим алгоритмом поиска и в отличие, например, от &lt;a href=&quot;http://py-algorithm.blogspot.ru/2011/04/blog-post_2498.html&quot;&gt;двоичного поиска&lt;/a&gt;, не накладывает никаких ограничений на функцию и имеет простейшую реализацию. Поиск значения функции осуществляется простым сравнением очередного рассматриваемого значения (как правило поиск происходит слева направо, то есть от меньших значений аргумента к большим) и, если значения совпадают (с той или иной точностью), то поиск считается завершённым.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;a name=&quot;more&quot;&gt;&lt;/a&gt;&lt;br&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Данный алгоритм приведен здесь, для полноты изложения. Он мало где используется, только если в собственных проектах, которые не накладывают серьезных требований к производительности системы.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;br&gt;&lt;/div&gt;
Рассматриваем, левую и правую границы отрезка массива, где находится нужный нам элемент. Исследования начинаются с первого элемента отрезка. Если искомое значение не равно значению функции в данной точке, то осуществляется переход к следующей точке. Т.е., в результате каждой проверки область поиска уменьшается на один элемент.
&lt;br&gt;
&lt;br&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def linearSearch(li, x):
    i = 0
    length = len(li)
    while i&amp;lt;length and x&amp;lt;&amp;gt; li[i]:
        i+=1
    return i if i&amp;lt;length else None&lt;/pre&gt;
&lt;br&gt;
&lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%92%D0%B8%D1%80%D1%82,_%D0%9D%D0%B8%D0%BA%D0%BB%D0%B0%D1%83%D1%81&quot;&gt;Никлаус Вирт&lt;/a&gt;&amp;nbsp;описал модернизацию метода, при которой мы избавляемся от одного сравнения на каждом витке цикла. А именно от проверки окончания строки. Для этого мы добавляем искомый элемент в самый конец, что гарантирует нам остановку по одному условию, а финальная проверка на позицию найденного элемента, покажет подставной он или нет)&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def linearSearchVirt(li, x):
    i = 0
    length = len(li)-1
    while x x&amp;lt;&amp;gt; li[i]:
        i+=1
    return i if i&amp;lt;length else None&lt;/pre&gt;
&lt;br&gt;
Вот и весь линейный поиск!)&lt;br&gt;
Но есть более интересный метод -&amp;nbsp;&lt;span style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;http://py-algorithm.blogspot.ru/2011/04/blog-post_2498.html&quot; style=&quot;text-align: justify;&quot;&gt;двоичный поиск&lt;/a&gt;, милости просим к изучению.</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/4271277225898325984/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2013/02/blog-post.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/4271277225898325984'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/4271277225898325984'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2013/02/blog-post.html' title='Линейный поиск'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifeWSYWhNREO3TGhi5JPork2KaknU92HVALTdLfspH4jUD5w0fl1fDy_d7cAuE-xqsTXEUYStpeZzeC6T7POKmUPxdtApPPLQrx8znaIAGjPT_GVw6xaEcFRcGtW7Sg5qTlUzFXL7R/s72-c/0002-002-Linejnyj-poisk.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-8337317714867868611</id><published>2012-11-16T14:00:00.001-08:00</published><updated>2013-02-12T11:03:38.857-08:00</updated><title type='text'>Совершенный код</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSPkNIRboLkAobVo_1BJJ6tZw585gQyXG5xTIRE_IbUme7Lde-7OmDnH0AtJ62wBfTuVhtFWjWvJBV6t9GDjv-XlC7ZBDmAFewsKgxMWhcO4axHZCbNCZuACh4G-W-TsJSwqV1-Pja/s1600/ab528556e8e7f685795b6b7797d51ea3.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSPkNIRboLkAobVo_1BJJ6tZw585gQyXG5xTIRE_IbUme7Lde-7OmDnH0AtJ62wBfTuVhtFWjWvJBV6t9GDjv-XlC7ZBDmAFewsKgxMWhcO4axHZCbNCZuACh4G-W-TsJSwqV1-Pja/s320/ab528556e8e7f685795b6b7797d51ea3.jpg&quot; width=&quot;276&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
Есть такая хорошая книжка - &quot;Совершенный код&quot;, автора&amp;nbsp;С. Макконнелл. Кто не читал или не слышал вообще, очень советую. Книга не привязана к конкретному языку, примеры есть на С++, Java, C# и т.д. В ней описано много интересных приемов программирования и разработки проекта в целом.&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
Для того, чтобы Вас немного заинтересовать данной книгой - приведу интересные выкладки из нее:)&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;i&gt;&lt;span style=&quot;color: red; font-size: xx-small;&quot;&gt;&lt;b&gt;*-Нравится статья? Кликни по рекламе! :)&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;/div&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&amp;nbsp;Проведение аналогий часто приводит к важным открытиям (волновая и корпускулярная теории света -&amp;gt; эфир(среда распространяющая свет как воздух звук))&lt;/li&gt;
&lt;li&gt;Метафора - эвристический подход, а не алгоритм (разработка как: литературная, сельскохозяйственная, строительная метафоры и метафора жемчужины)&lt;/li&gt;
&lt;li&gt;Не бойтесь комбинировать метафоры&lt;/li&gt;
&lt;li&gt;Эвристика - метод помогающий искать ответ&lt;/li&gt;
&lt;li&gt;Общая цель подготовки - снижение риска&lt;/li&gt;
&lt;li&gt;Если менеджер проекта приказывает Вам немедленно начать программировать...Существует 4 основных подхода, но лучший - найти другую работу,&amp;nbsp;ведь жизнь слишком коротка, чтобы тратить ее на работу в отсталом учреждении&lt;/li&gt;
&lt;li&gt;Один из аспектов профессии разработчика - посвящение профанов в особенности процесса разработки ПО&lt;/li&gt;
&lt;li&gt;Подготовка к проекту - это дешевле, чем похерить результат и начать все заново&lt;/li&gt;
&lt;li&gt;Программисты - последнее звено пищевой цепи разработки ПО. Архитекторы поглощают требования, проектировщики архитектуру, а программисты - проект.&lt;/li&gt;
&lt;li&gt;Если на каждом этапе яды, программист получит их все.&lt;/li&gt;
&lt;li&gt;Общий принцип прост: исправлять ошибки нужно как можно раньше&lt;/li&gt;
&lt;li&gt;И при итеративном и при последовательных подходах разработки общая сумма затрат будет схожей, однако в первом случае она не будет казаться столь&amp;nbsp;крупной, т.к. будет уплачена по частям&lt;/li&gt;
&lt;li&gt;Убедитесь, что всем известна цена изменения требований&lt;/li&gt;
&lt;li&gt;Хорошая архитекура облегчает конструирование&lt;/li&gt;
&lt;li&gt;Архитектура должна производить оценку ресурсов в номинальном и пиковом состоянии,а так же уровень отказоустойчивости системы&lt;/li&gt;
&lt;li&gt;В мире ПО цепь не так крепка как, как слабейшее звено; Она так слаба, как все слабые звенья вместе взятые&lt;/li&gt;
&lt;li&gt;Изучая архитектуру, Вы должны испытывать удовольствие от того, насколько естественной и простой она получается&lt;/li&gt;
&lt;li&gt;Если над данным типом ПО Вы еще не работали - выделите больше времени&lt;/li&gt;
&lt;li&gt;Язык программирование - отражение вашего мышления&lt;/li&gt;
&lt;li&gt;Различайте программирование &quot;на языке&quot; и &quot;с использованием языка&quot;&lt;/li&gt;
&lt;li&gt;Проблему нужно решать дважды: первый , чтобы получить ее ясное определение, второй, для создания работоспособного решения&lt;/li&gt;
&lt;li&gt;Задача проектирования - объединение конкурирующих целей в удачном компромиссе&lt;/li&gt;
&lt;li&gt;Основные характеристики проекта: минимальнаясложность, простота сопровождения, слабое сопряжение(адекватная абстракция), расширяемость,повторное использование, высокий коэфф. объединения по входу (наличие ядра), низкий коэфф. разветвления на выходе (не большое делегирование),&amp;nbsp;портируемость, отсутствие избыточной функциональности, стратификация (грамотная декомпозиция системы на уровни)&lt;/li&gt;
&lt;li&gt;Если все подсистемы могут взаимодействовать (т.е. отсутствие ограничений, что увеличивает по 2-му з-ну термодинамики энтропию системы), выгода от&amp;nbsp;их разделения пропадает. Проще ограничить взаимодействие, а после сделать его свободнее.&lt;/li&gt;
&lt;li&gt;Диаграмма систем должна быть ациклическим графом&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
Выше я привел интересные выводы, советы и это основное, что я выдержал из первых глав) Так что поверьте, там много полезного и переписывать книгу я не буду, однако приведу интересные высказывания различных людей, которыми кишит книга!)&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;Планируйте выбросить первый экземпляр программы: вам в любом случае придется это сделать.&lt;/i&gt;&amp;nbsp;Фред Брукс&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;Если вы планируете выбросить первый экземпляр программы, вы выбросите и второй.&lt;/i&gt; Крейг Зеруни&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;Требования подобны воде. Опираться на них легче, когда они замарожены. &lt;/i&gt;Аноним&amp;nbsp;&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;Если вы не можете объяснить что-то 6-ти летнему ребенку, значит, вы сами этого не понимаете.&lt;/i&gt; Альберт Эйнштейн&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;Образ разработчика, проектирующего программу рациональным безошибочным способом на основе ясно сформулированных требований, совершенно не реалистичен&lt;/i&gt;. Дэвид Парнас&amp;nbsp;&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;Есть два способа разработки проекта приложения: сделать его настолько простым, чтобы было очевидно, что в нем нет недостатков, или сделать его таким сложным, чтобы в нем не было очевидных недостатков.&lt;/i&gt; Ч.Э.Р. Хоар&amp;nbsp;&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;Работая над проблемой, я никогда не думаю о красоте. Я думаю только о решении проблемы. Но если полученное решение некрасиво, я знаю, что оно не верно. &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/i&gt;Р. Бакминстер Фуллер&amp;nbsp;&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;Прежде всего следует узнать, не что система выполняет, а над чем она это выполняет!&lt;/i&gt;&amp;nbsp;Бертран Мейер&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;Интерфейсы классов должны быть полными и минимальными.&lt;/i&gt; Скотт Майерс&amp;nbsp;&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;Больше беспокоит то, что программист может выполнить одну задачу несколькими способами: иногда не осознанно, но чаще ради изменения или же создания элегантной вариации.&lt;/i&gt; А.Р.Браун и У.А.Сэмпсон (такие уж мы педанты))))&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;Мы пытаемся решить проблему, максимально ускоряя процесс проектирования, чтобы в конце работы над системой у нас осталось достаточно времени для нахождения ошибок, допущенных из-за слишком быстрого проектирования. &lt;/i&gt;Гленфорд Майерс&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;Я никогда не встречал человека, желающего читать 17000 страниц документации, а если бы встретил, то убил бы его, чтобы он не портил генофонд.&lt;/i&gt; Джозеф Костелло&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;Плохие новости заключаются в том, что мы, как нам кажется, никогда не найдем философского камня. Мы никогда не найдем процесса, позволяющего проектировать ПО абсолютно рациональным образом. Но ест и хорошие новости: мы можем его подделать!&lt;/i&gt; Дэвид Парнас&lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;Если для понимания того, что происходит, нужно увидеть реализацию, это не абстракция.&lt;/i&gt; Ф. Дж. Плоджер&lt;/blockquote&gt;
&lt;br /&gt;
Друзья, придерживайтесь золотых правил, проверенных годами! А для начала, ознакомьтесь с ними в данной книге!)&amp;nbsp;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/8337317714867868611/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2012/11/blog-post.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/8337317714867868611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/8337317714867868611'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2012/11/blog-post.html' title='Совершенный код'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSPkNIRboLkAobVo_1BJJ6tZw585gQyXG5xTIRE_IbUme7Lde-7OmDnH0AtJ62wBfTuVhtFWjWvJBV6t9GDjv-XlC7ZBDmAFewsKgxMWhcO4axHZCbNCZuACh4G-W-TsJSwqV1-Pja/s72-c/ab528556e8e7f685795b6b7797d51ea3.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-3415603635705023123</id><published>2012-01-15T12:28:00.000-08:00</published><updated>2014-01-09T21:04:15.616-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Сортировки"/><title type='text'>Сортировка слиянием</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuFnmihyphenhyphen5Xnu9CYInHxUIdbrx1XjQh9uagWVpnBdCfBWVoqCj1xB3lhCdmZt6KFVu70pyiA4SJTYSTUdjkeq3LH2KSADgtwMGII7lFB_0AUj1Y0WXu8XNOjuzhSVuS-EFsrQHxD6KU/s1600/220px-Merge_sort_animation2.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuFnmihyphenhyphen5Xnu9CYInHxUIdbrx1XjQh9uagWVpnBdCfBWVoqCj1xB3lhCdmZt6KFVu70pyiA4SJTYSTUdjkeq3LH2KSADgtwMGII7lFB_0AUj1Y0WXu8XNOjuzhSVuS-EFsrQHxD6KU/s1600/220px-Merge_sort_animation2.gif&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px; text-align: -webkit-auto;&quot;&gt;Сортировка слиянием&lt;/b&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;&amp;nbsp;(&lt;/span&gt;&lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%90%D0%BD%D0%B3%D0%BB%D0%B8%D0%B9%D1%81%D0%BA%D0%B8%D0%B9_%D1%8F%D0%B7%D1%8B%D0%BA&quot; style=&quot;background-attachment: initial; background-clip: initial; background-color: white; background-image: none; background-origin: initial; color: #0645ad; font-family: sans-serif; font-size: 13px; line-height: 19px; text-align: -webkit-auto; text-decoration: none;&quot; title=&quot;Английский язык&quot;&gt;англ.&lt;/a&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px; text-align: -webkit-auto;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;i style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px; text-align: -webkit-auto;&quot;&gt;&lt;span lang=&quot;en&quot; xml:lang=&quot;en&quot;&gt;merge sort&lt;/span&gt;&lt;/i&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px; text-align: -webkit-auto;&quot;&gt;) — алгоритм сортировки, который упорядочивает списки (или другие структуры данных, доступ к элементам которых можно получать только последовательно, например — потоки) в определённом порядке. &lt;/span&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px; text-align: -webkit-auto;&quot;&gt;Сначала задача разбивается на несколько подзадач меньшего размера. Затем эти задачи решаются с помощью рекурсивного вызова или непосредственно, если их размер достаточно мал. Наконец, их решения комбинируются, и получается решение исходной задачи.&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;Алгоритм был изобретён&amp;nbsp;&lt;/span&gt;&lt;a class=&quot;mw-redirect&quot; href=&quot;http://ru.wikipedia.org/wiki/%D0%A4%D0%BE%D0%BD_%D0%9D%D0%B5%D0%B9%D0%BC%D0%B0%D0%BD,_%D0%94%D0%B6%D0%BE%D0%BD&quot; style=&quot;background-attachment: initial; background-clip: initial; background-color: white; background-image: none; background-origin: initial; color: #0645ad; font-family: sans-serif; font-size: 13px; line-height: 19px; text-align: -webkit-auto; text-decoration: none;&quot; title=&quot;Фон Нейман, Джон&quot;&gt;Джоном фон Нейманом&lt;/a&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px; text-align: -webkit-auto;&quot;&gt;&amp;nbsp;в&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;http://ru.wikipedia.org/wiki/1945_%D0%B3%D0%BE%D0%B4&quot; style=&quot;background-attachment: initial; background-clip: initial; background-color: white; background-image: none; background-origin: initial; color: #0645ad; font-family: sans-serif; font-size: 13px; line-height: 19px; text-align: -webkit-auto; text-decoration: none;&quot; title=&quot;1945 год&quot;&gt;1945 году&lt;/a&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px; text-align: -webkit-auto;&quot;&gt;.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px; text-align: -webkit-auto;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: -webkit-auto;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: sans-serif; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;line-height: 19px;&quot;&gt;Странно, но мне показалось, что данный алгоритм не так сильно освещён в интернете в целом и на python &amp;nbsp;в частности. А ведь именно этот алгоритм чаще всего применяется для сортировки данных не помещающихся в оперативке, т.е. хранящихся в файлах(внешние сортировки). Как и в случае с &lt;a href=&quot;http://py-algorithm.blogspot.com/2011/11/quicksort.html&quot;&gt;быстрой сортировкой Хоара&lt;/a&gt;, существует 2 реализации данного алгоритма. Рекурсивная и нет) Скажу по секрету, не рекурсивную реализацию мне предоставил так же мой преподаватель Деон. Более того, она ещё и не требует дополнительной памяти, что в классическом варианте относят к её основным минусам!&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: -webkit-auto;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: sans-serif; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;line-height: 19px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: -webkit-auto;&quot;&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px; margin-bottom: 0.5em; margin-top: 0.4em;&quot;&gt;
Для решения задачи сортировки эти три этапа выглядят так:&lt;/div&gt;
&lt;ol style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px; list-style-image: none; margin-bottom: 0px; margin-left: 3.2em; margin-right: 0px; margin-top: 0.3em; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;&quot;&gt;
&lt;li style=&quot;margin-bottom: 0.1em;&quot;&gt;Сортируемый массив разбивается на две части примерно одинакового размера;&lt;/li&gt;
&lt;li style=&quot;margin-bottom: 0.1em;&quot;&gt;Каждая из получившихся частей сортируется отдельно, например — тем же самым алгоритмом;&lt;/li&gt;
&lt;li style=&quot;margin-bottom: 0.1em;&quot;&gt;Два упорядоченных массива половинного размера соединяются в один.&lt;/li&gt;
&lt;/ol&gt;
&lt;div style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px; margin-bottom: 0.5em; margin-top: 0.4em;&quot;&gt;
Рекурсивное разбиение задачи на меньшие происходит до тех пор, пока размер массива не достигнет единицы (любой массив длины 1 можно считать упорядоченным).&lt;/div&gt;
&lt;div style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px; margin-bottom: 0.5em; margin-top: 0.4em;&quot;&gt;
Нетривиальным этапом является соединение двух упорядоченных массивов в один. Основную идею слияния двух отсортированных массивов можно объяснить на следующем примере. Пусть мы имеем две стопки карт, лежащих рубашками вниз так, что в любой момент мы видим верхнюю карту в каждой из этих стопок. Пусть также, карты в каждой из этих стопок идут сверху вниз в неубывающем порядке. Как сделать из этих стопок одну? На каждом шаге мы берём меньшую из двух верхних карт и кладём её (рубашкой вверх) в результирующую стопку. Когда одна из оставшихся стопок становится пустой, мы добавляем все оставшиеся карты второй стопки к результирующей стопке.&lt;/div&gt;
&lt;div style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px; margin-bottom: 0.5em; margin-top: 0.4em;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: sans-serif; font-size: 13px; line-height: 19px; margin-bottom: 0.5em; margin-top: 0.4em;&quot;&gt;
&lt;/div&gt;
&lt;div style=&quot;font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;Пример работы алгоритма на массиве 3 7 8 2 4 6 1 5..&lt;/span&gt;&lt;/div&gt;
&lt;div align=&quot;center&quot; style=&quot;font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;192&quot; src=&quot;http://algolist.manual.ru/sort/gif/24.gif&quot; width=&quot;567&quot; /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;Рекурсивный алгоритм обходит получившееся дерево слияния в прямом порядке. Каждый уровень представляет собой&amp;nbsp;&lt;i&gt;проход&lt;/i&gt;&amp;nbsp;сортировки слияния - операцию, полностью переписывающую массив.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;Обратим внимание, что деление происходит до массива из единственного элемента. Такой массив можно считать упорядоченным, а значит, задача сводится к написанию функции слияния merge.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;Один из способов состоит в слиянии двух упорядоченных последовательностей при помощи вспомогательного буфера, равного по размеру общему количеству имеющихся в них элементов. Элементы последовательностей будут перемещаться в этот буфер по одному за шаг.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;
&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;Пример работы на последовательностях 2 3 6 7 и 1 4 5&lt;/span&gt;&lt;br /&gt;
&lt;div align=&quot;center&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;161&quot; src=&quot;http://algolist.manual.ru/sort/gif/25.gif&quot; width=&quot;530&quot; /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;Результатом является упорядоченная последовательность, находящаяся в буфере. Каждая операция слияния требует n пересылок и n сравнений, где n - общее число элементов, так что время слияния: Theta(n).&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;Ну что же, хватит слов, давайте реализовывать!)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def mergeSort(a, lb=0, ub=-1):
    def merge(a, lb, split, ub):
        #Слияние упорядоченных частей массива в буфер temp
        #с дальнейшим переносом содержимого temp в a[lb]...a[ub]

        #текущая позиция чтения из первой последовательности a[lb]...a[split]
        pos1=lb
        
        #текущая позиция чтения из второй последовательности a[split+1]...a[ub]
        pos2=split+1
        
        #текущая позиция записи в temp
        pos3=0
        
        temp = [i for i in xrange(ub-lb+1)]
        
        #идет слияние, пока есть хоть один элемент в каждой последовательности
        while pos1 &amp;lt;= split and pos2 &amp;lt;= ub:
            if a[pos1] &amp;lt; a[pos2]:
                temp[pos3] = a[pos1]
                pos1+=1
                pos3+=1
            else:
                temp[pos3] = a[pos2]
                pos2+=1
                pos3+=1
        
        #одна последовательность закончилась - 
        #копировать остаток другой в конец буфера 
        while pos2 &amp;lt;= ub:   #пока вторая последовательность непуста 
            temp[pos3] = a[pos2]
            pos3+=1
            pos2+=1
        while pos1 &amp;lt;= split:  #пока первая последовательность непуста
            temp[pos3] = a[pos1]
            pos3+=1
            pos1+=1

        #скопировать буфер temp в a[lb]...a[ub]
        a[lb:ub+1] = temp
        
        del(temp)
        
    if lb &amp;lt; ub:#если есть более 1 элемента
        split = (lb + ub)/2# индекс, по которому делим массив
        mergeSort(a, lb, split)#сортировать левую половину 
        mergeSort(a, split+1, ub)##сортировать правую половину 
        merge(a, lb, split, ub)#слить результаты в общий массив
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;font-size: 17px; text-align: -webkit-auto;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;Оценим быстродействие алгоритма: время работы определяется рекурсивной формулой T(n) = 2T(n/2) + Theta(n).&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 17px; text-align: -webkit-auto;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;Ее решение: T(n) = n log n - результат весьма неплох, учитывая отсутствие &quot;худшего случая&quot;. Однако, несмотря на хорошее общее быстродействие, у сортировки слиянием есть и серьезный минус: она требует Theta(n) памяти.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 17px; text-align: -webkit-auto;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
Это был классический вариант с сайта алголист. Теперь я приведу пример 2-го алгоритма &lt;b&gt;без &lt;/b&gt;дополнительного буфера и рекурсии. Но к сожалению всё вкусно не бывает, поэтому за всё нужно платить. Об этом смотри в результатах. А пока идея:&lt;br /&gt;
Она достаточно проста, но не так тривиальна, как в предыдущем алгоритме. Избавившись от рекурсии, мы обязаны следить за следованием промежуточных разбиений самостоятельно. Алгоритм начинает с того, что сравнивает каждые 2 соседних, объединяя их в 1 упорядоченный подмассив. Потом снова 2 соседних(но в каждом из них уже по 2 эл-та), потом так же, но по 4, 8, 16 и т.д. И чтобы не использовать буфер, мы итерационно переставляем элемента прям в памяти, , чтобы упорядочить их(это требует огромного числа перестановок((()&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def MergerSort(a):       
    def MergerGroup(a, left, m, right):
        if left &amp;gt;= right: return None
        if m &amp;lt; left or right &amp;lt; m: return None
        t = left
        for j in xrange(m+1, right+1):#подгруппа 2
            for i in xrange(t, j):#цикл подгруппы 1
                if a[j] &amp;lt; a[i]:
                    r = a[j]
                    #итерационно переставляем элементы, чтобы упорядочить
                    for k in xrange(j, i, -1):
                        a[k] = a[k - 1]
                    a[i] = r
                    t = i#проджолжение вставки в группе 1
                    break#к следующему узлу из подгруппы 2
                
    if len(a) &amp;lt; 2: return None
    k=1
    while k&amp;lt;len(a):
       g=0
       while g&amp;lt;len(a):#группы
            z = g + k + k - 1#последний эл-т группы
            r = z if z &amp;lt; len(a) else len(a) - 1#последняя группа
            MergerGroup(a, g, g + k - 1, r)#слияние
            g+=2*k
        k*=2
&lt;/pre&gt;
&lt;br /&gt;
Еще 1 пример не рекурсивного алгоритма приведён на сайте википедии. Но там всё же вводится дополнительный буфер, равный &lt;b&gt;размеру!&lt;/b&gt; массива.

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;font-size: 17px; text-align: -webkit-auto;&quot;&gt;
&lt;b style=&quot;background-color: #f9f9f9; font-family: monospace; font-size: 13px; line-height: 14px; text-align: left; white-space: pre-wrap;&quot;&gt;Производительность&lt;/b&gt;&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f9f9f9; font-family: monospace; font-size: 13px; line-height: 14px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;line-height: 24px;&quot;&gt;Тестирование проводилось на списке из 5000 не повторяющихся элементов(как и в &lt;a href=&quot;http://www.blogger.com/&quot;&gt;&lt;span id=&quot;goog_775732223&quot;&gt;&lt;/span&gt;быстрой сортировке Хоара&lt;span id=&quot;goog_775732224&quot;&gt;&lt;/span&gt;&lt;/a&gt;, чтобы можно было сравнить).&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f9f9f9; font-family: monospace; font-size: 13px; line-height: 14px; white-space: pre-wrap;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; font-size: small; line-height: normal; white-space: normal;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f9f9f9; font-family: monospace;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;line-height: 14px; white-space: pre-wrap;&quot;&gt;первый алгоритм рекурсивный и с дополнительной памятью mergeSort&lt;/span&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: small; white-space: pre;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;white-space: pre;&quot;&gt;15002 function calls (5004 primitive calls) in 0.132 seconds&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;line-height: 14px; white-space: pre-wrap;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; font-size: small; line-height: normal; white-space: normal;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f9f9f9; font-family: monospace;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;line-height: 14px; white-space: pre-wrap;&quot;&gt;второй алгоритм не рекурсивный и без доп. буфера &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace; white-space: pre;&quot;&gt;MergerSort 15057 function calls in 0.736 seconds&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
Результаты говорят сами за себя. Увы, но люди должны выбирать между доп. памятью и числом доп. итераций(т.е. перестановок - производительностью).&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-size: 17px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-size: 17px;&quot;&gt;Хорошо запрограммированная внутренняя сортировка слиянием работает немного быстрее пирамидальной, но медленнее быстрой, при этом требуя много памяти под буфер. Поэтому mergeSort &lt;b&gt;используют&lt;/b&gt; для упорядочения массивов, лишь &lt;b&gt;если требуется устойчивость метода(которой нет ни у быстрой, ни у пирамидальной сортировок)&lt;/b&gt;.&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;font-size: 17px; text-align: -webkit-auto;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;Сортировка слиянием &lt;b&gt;является одним из наиболее эффективных методов&lt;/b&gt; для односвязных списков и файлов, &lt;b&gt;когда есть лишь последовательный доступ к элементам&lt;/b&gt;.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div id=&quot;-chrome-auto-translate-plugin-dialog&quot; style=&quot;background-attachment: initial !important; background-clip: initial !important; background-color: transparent !important; background-image: initial !important; background-origin: initial !important; display: none; left: 0px; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; opacity: 1 !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: absolute !important; text-align: left !important; top: 0px; z-index: 999999 !important;&quot;&gt;
&lt;div style=&quot;-webkit-border-radius: 10px !important; background-color: #363636 !important; background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0%, #000), color-stop(50%, #363636), color-stop(100%, #000)); border-color: #000000 !important; border-width: 0px !important; color: #fafafa !important; font-size: 16px !important; max-width: 300px !important; opacity: 0.8 !important; overflow: visible !important; padding: 8px !important; text-align: left !important; z-index: 999999 !important;&quot;&gt;
&lt;div class=&quot;translate&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;additional&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;img onclick=&quot;document.location.href=&#39;http://translate.google.com/&#39;;&quot; src=&quot;http://www.google.com/uds/css/small-logo.png&quot; style=&quot;-webkit-border-radius: 20px; background-color: rgba(200, 200, 200, 0.3) !important; cursor: pointer !important; margin: 0 !important; padding: 3px 5px 0 !important; position: absolute !important; right: 1px !important; top: -20px !important; z-index: -1 !important;&quot; /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;&lt;b&gt;Используемая литература:&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;&lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&quot;&gt;Википедия&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white;&quot;&gt;&lt;a href=&quot;http://algolist.manual.ru/sort/merge_sort.php&quot;&gt;Algolist&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/3415603635705023123/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2012/01/blog-post.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/3415603635705023123'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/3415603635705023123'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2012/01/blog-post.html' title='Сортировка слиянием'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuFnmihyphenhyphen5Xnu9CYInHxUIdbrx1XjQh9uagWVpnBdCfBWVoqCj1xB3lhCdmZt6KFVu70pyiA4SJTYSTUdjkeq3LH2KSADgtwMGII7lFB_0AUj1Y0WXu8XNOjuzhSVuS-EFsrQHxD6KU/s72-c/220px-Merge_sort_animation2.gif" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-9017393531060641442</id><published>2011-12-14T06:04:00.000-08:00</published><updated>2012-02-10T00:36:33.676-08:00</updated><title type='text'>Технические задачки</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;background-color: white; font-family: Arial, sans-serif; font-size: 13px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;
&lt;b style=&quot;font-weight: bold; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div style=&quot;margin-bottom: 0.8em;&quot;&gt;
&lt;b style=&quot;font-weight: bold; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;1. Что будет выведено в результате исполнения программы? Почему?&lt;/b&gt;&lt;/div&gt;
&lt;b style=&quot;font-weight: bold; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;
&lt;/b&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;class A:
     def __init__(self, name):
          self.name = name
     def __del__(self):
          print self.name,
 
aa = [A(str(i)) for i in range(3)]
for a in aa:
    del a
&lt;/pre&gt;
&lt;pre style=&quot;background-color: white; font-size: 12px; font: normal normal normal 120%/normal monospace; margin-bottom: 1em; margin-top: 1em;&quot;&gt;&lt;/pre&gt;
Вывод узнать легко в любой IDE. Это 2 1 0. Вопрос почему? Исходя из порядка(он если что, обратен созданию), можно догадаться, что тут задействован стек, т.е. работает правило LIFO.&lt;br /&gt;
При удалении списка - элементы удаляются в обратном порядке созданию.&lt;br /&gt;
Но важно понять, что удаление происходит в нашем случае, всего лишь когда скрипт отработал, а инструкция del тут ни при чём!&lt;br /&gt;
Вызов инструкции del рвёт связь имени переменной(в нашем случае a) и данных, находящихся в памяти, т.е. в цикле мы создаём ссылку на элемент списка, дём ей название-&amp;gt;a, выводим name элемента и рвём связь. Чтобы отработал магический метод __del__ нужно вызывать del напрямую к элементу, т.е. через индекс, например del a[0]&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;
&lt;/pre&gt;
&lt;div style=&quot;background-color: white; font-family: Arial, sans-serif; font-size: 13px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;
&lt;b style=&quot;font-weight: bold; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;
&lt;/b&gt;&lt;br /&gt;
&lt;div style=&quot;margin-bottom: 0.8em;&quot;&gt;
&lt;b style=&quot;font-weight: bold; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;2. Что будет выведено в результате исполнения программы? Почему?&lt;/b&gt;&lt;/div&gt;
&lt;b style=&quot;font-weight: bold; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;
&lt;/b&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;class A:
    def __init__( self ):
        self.__value = 1
    def getvalue( self ):
        return self.__value
 
class B( A ):
    def __init__( self ):
        A.__init__( self )
        self.__value = 2
 
b = B()
print b.getvalue() == b.__value&lt;/pre&gt;
Ответ: случится Exception, потому что невозможно получить доступ к __value извне класса. Однако самое интересное, здесь другое. В данном случае&amp;nbsp;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace; white-space: pre;&quot;&gt;b.getvalue()&lt;/span&gt; возвращает 1, т.к.&amp;nbsp;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace; white-space: pre;&quot;&gt;self.__value&lt;/span&gt;&amp;nbsp;различно в каждом контексте. А именно&amp;nbsp;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace; white-space: pre;&quot;&gt;b._A__value и &lt;/span&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace; white-space: pre;&quot;&gt;b._B__value!&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace; white-space: pre;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;background-color: white; font-family: Arial, sans-serif; font-size: 13px; margin-bottom: 0.8em;&quot;&gt;
3. Есть 2 таблицы&amp;nbsp;&lt;strong style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;users&lt;/strong&gt;&amp;nbsp;и&amp;nbsp;&lt;strong style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;messages&lt;/strong&gt;&lt;/div&gt;
&lt;pre style=&quot;background-color: white; font-size: 12px; font: normal normal normal 120%/normal monospace; margin-bottom: 1em; margin-top: 1em;&quot;&gt;users
UID Name
1 «Вася»
2  «Петя»


messages
UID msg
1 “A”
1 “B”
2 “C”

&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: Arial, sans-serif; font-size: 13px; white-space: normal;&quot;&gt;Напишите SQL-запрос, результатом которого будет таблица из двух полей: «Имя пользователя» и «Общее количество сообщений».&lt;/span&gt;&lt;/pre&gt;
Здесь, могу посоветовать - &amp;nbsp;SELECT INTO
&lt;br /&gt;
&lt;b&gt;UPD&lt;/b&gt; добавил пример)&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;CREATE TABLE cvc.users(
 uid INT,
 name varchar(100)
);

CREATE TABLE cvc.messages(
 uid INT,
 msg varchar(100)
);

INSERT INTO cvc.users (uid, name) VALUES (1, &#39;Vasja&#39;), (2, &#39;Petja&#39;);
INSERT INTO cvc.messages (uid, msg) VALUES (1, &#39;A&#39;), (1, &#39;B&#39;), (2, &#39;C&#39;);

select name, count(*) as cnt from cvc.users join cvc.messages on users.uid = messages.uid group by users.uid;
select name, count(*) as cnt from cvc.users, cvc.messages where users.uid = messages.uid group by users.uid;

DROP TABLE cvc.users;
DROP TABLE cvc.messages;&lt;/pre&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/9017393531060641442/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2011/12/blog-post.html#comment-form' title='Комментарии: 6'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/9017393531060641442'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/9017393531060641442'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2011/12/blog-post.html' title='Технические задачки'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-534324071355682897</id><published>2011-11-02T01:00:00.000-07:00</published><updated>2012-04-01T09:58:29.681-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Сортировки"/><title type='text'>Быстрая сортировка(quicksort, сортировка Хоара)</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Sorting_quicksort_anim.gif/220px-Sorting_quicksort_anim.gif&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Sorting_quicksort_anim.gif/220px-Sorting_quicksort_anim.gif&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;&lt;b&gt;Быстрая сортировка&lt;/b&gt;&amp;nbsp;(англ.&amp;nbsp;&lt;i&gt;&lt;span lang=&quot;en&quot; xml:lang=&quot;en&quot;&gt;quicksort&lt;/span&gt;&lt;/i&gt;), часто называемая qsort по имени реализации в стандартной библиотеке языка&amp;nbsp;Си&amp;nbsp;— широко известный&amp;nbsp;алгоритм сортировки, разработанный английским информатиком&amp;nbsp;Чарльзом Хоаром&amp;nbsp;в&amp;nbsp;1960&amp;nbsp;году. Один из быстрых известных универсальных алгоритмов сортировки массивов (в среднем&amp;nbsp;O(&lt;i&gt;n&lt;/i&gt;&amp;nbsp;log&amp;nbsp;&lt;i&gt;n&lt;/i&gt;) обменов при упорядочении&amp;nbsp;&lt;i&gt;n&lt;/i&gt;&amp;nbsp;элементов), хотя и имеющий ряд недостатков.&lt;/span&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;&amp;nbsp;Например, в худшем случае (на некоторых входных&amp;nbsp;массивах) использует время&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: MathJax_Main, MathJax_Size1, MathJax_AMS; font-size: 24px; white-space: nowrap;&quot;&gt;&lt;span class=&quot;mi&quot; id=&quot;MathJax-Span-12&quot; style=&quot;border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; display: inline; font-family: MathJax_Main; line-height: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; position: static; text-decoration: none; vertical-align: 0px;&quot;&gt;Ω&lt;/span&gt;&lt;span class=&quot;mo&quot; id=&quot;MathJax-Span-13&quot; style=&quot;border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; display: inline; font-family: MathJax_Main; line-height: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; position: static; text-decoration: none; vertical-align: 0px;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: MathJax_Math; font-size: 24px; font-style: italic; white-space: nowrap;&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-size: 24px; white-space: nowrap;&quot;&gt;&lt;span class=&quot;msubsup&quot; id=&quot;MathJax-Span-14&quot; style=&quot;border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; display: inline; line-height: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; position: static; text-decoration: none; vertical-align: 0px;&quot;&gt;&lt;span style=&quot;border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; display: inline-block; height: 0px; line-height: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; position: relative; text-decoration: none; vertical-align: 0px; width: 1.093em;&quot;&gt;&lt;span style=&quot;border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; clip: rect(1.583em 1000em 2.282em -0.348em); display: inline; left: 0em; line-height: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; position: absolute; text-decoration: none; top: -2.148em; vertical-align: 0px;&quot;&gt;&lt;span style=&quot;border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; display: inline-block; font-family: MathJax_Main, MathJax_Size1, MathJax_AMS; height: 2.148em; line-height: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; position: static; text-decoration: none; vertical-align: 0px; width: 0px;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; display: inline; font-family: MathJax_Main, MathJax_Size1, MathJax_AMS; left: 0.649em; line-height: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; position: absolute; text-decoration: none; top: -2.511em; vertical-align: 0px;&quot;&gt;&lt;span class=&quot;mn&quot; id=&quot;MathJax-Span-16&quot; style=&quot;border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; display: inline; font-family: MathJax_Main; font-size: 17px; line-height: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; position: static; text-decoration: none; vertical-align: 0px;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; display: inline-block; font-family: MathJax_Main, MathJax_Size1, MathJax_AMS; height: 2.148em; line-height: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; position: static; text-decoration: none; vertical-align: 0px; width: 0px;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mo&quot; id=&quot;MathJax-Span-17&quot; style=&quot;border-bottom-width: 0px; border-color: initial; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-style: initial; border-top-width: 0px; display: inline; font-family: MathJax_Main; line-height: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; position: static; text-decoration: none; vertical-align: 0px;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: MathJax_Main; font-size: 24px; white-space: nowrap;&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; line-height: 19px;&quot;&gt;&lt;span aria-readonly=&quot;true&quot; class=&quot;MathJax&quot; role=&quot;textbox&quot; style=&quot;border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; direction: ltr; display: inline; float: none; letter-spacing: normal; line-height: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left; text-indent: 0px; text-transform: none; white-space: nowrap; word-spacing: normal; word-wrap: normal;&quot;&gt;&lt;nobr style=&quot;border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; line-height: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; max-height: none; max-width: none; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-decoration: none; vertical-align: 0px; white-space: nowrap;&quot;&gt;&lt;span class=&quot;math&quot; id=&quot;MathJax-Span-10&quot; style=&quot;border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; display: inline; line-height: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; position: static; text-decoration: none; vertical-align: 0px;&quot;&gt;&lt;span style=&quot;border-bottom-width: 0px; border-color: initial; border-left-color: initial; border-left-width: 0em; border-right-width: 0px; border-style: initial; border-top-width: 0px; display: inline-block; font-family: MathJax_Main, MathJax_Size1, MathJax_AMS; font-size: 13px; font-style: normal; height: 2.083em; line-height: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; overflow-x: hidden; overflow-y: hidden; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; position: static; text-decoration: none; vertical-align: -0.482em; width: 0px;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/nobr&gt;&lt;/span&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: sans-serif; font-size: 13px;&quot;&gt;, что, например, хуже, чем сложность в наихудшем случае алгоритма&amp;nbsp;&lt;/span&gt;сортировки слиянием&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: sans-serif; font-size: 13px;&quot;&gt;.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; line-height: 19px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: sans-serif; font-size: 13px;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f6f9ff; color: #111111; font-family: verdana, arial, sans-serif; font-size: 13px;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;margin-bottom: 5pt; margin-top: 5pt;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f6f9ff; color: #111111; font-family: verdana, arial, sans-serif; font-size: 13px;&quot;&gt;Функция QuickSort сводит сортировку данного ей массива к разделению (partitioning) этого массива на две группы элементов и сортировке этих двух групп по отдельности.&lt;/span&gt;&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f6f9ff; color: #111111; font-family: verdana, arial, sans-serif; font-size: 13px;&quot;&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;margin-bottom: 5pt; margin-top: 5pt;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f6f9ff; color: #111111; font-family: verdana, arial, sans-serif; font-size: 13px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f6f9ff; color: #111111; font-family: verdana, arial, sans-serif; font-size: 13px;&quot;&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;margin-bottom: 5pt; margin-top: 5pt;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f6f9ff; color: #111111; font-family: verdana, arial, sans-serif; font-size: 13px;&quot;&gt;Пример рекурсивного алгоритма с детерменированным(определённым) выбором оси:&lt;/span&gt;&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f6f9ff; color: #111111; font-family: verdana, arial, sans-serif; font-size: 13px;&quot;&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;margin-bottom: 5pt; margin-top: 5pt;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f6f9ff; color: #111111; font-family: verdana, arial, sans-serif; font-size: 13px;&quot;&gt;Пусть нам нужно отсортировать участок массива A с p-го по q-й элемент включительно, будем называть этот участок подмассивом и обозначать как A[p..q].&lt;/span&gt;&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f6f9ff; color: #111111; font-family: verdana, arial, sans-serif; font-size: 13px;&quot;&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;margin-bottom: 5pt; margin-top: 5pt;&quot;&gt;
&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f6f9ff; color: #111111; font-family: verdana, arial, sans-serif; font-size: 13px;&quot;&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-image: initial; list-style-position: outside; list-style-type: disc; margin-bottom: 0pt; margin-left: 15pt; margin-right: 0pt; margin-top: 0pt; padding-bottom: 0pt; padding-left: 0pt; padding-right: 0pt; padding-top: 0pt;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f6f9ff; color: #111111; font-family: verdana, arial, sans-serif; font-size: 13px;&quot;&gt;
&lt;li style=&quot;margin-left: 8pt; padding-bottom: 0pt; padding-left: 0pt; padding-right: 0pt; padding-top: 0pt;&quot;&gt;ШАГ 1: Возьмем элемент A[p] за ось и &quot;раскидаем&quot; остальные элементы A[(p+1)..q] по разные стороны от него стороны — меньшие влево, большие --- вправо, то есть переставим элементы подмассива A[p..q] так, чтобы вначале шли элементы меньше либо равные A[p] потом элементы, больше либо равные A[p]. Назовет этот шаг разделением (partition).&lt;/li&gt;
&lt;/span&gt;&lt;/ul&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f6f9ff; color: #111111; font-family: verdana, arial, sans-serif; font-size: 13px;&quot;&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;margin-bottom: 5pt; margin-top: 5pt;&quot;&gt;
&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f6f9ff; color: #111111; font-family: verdana, arial, sans-serif; font-size: 13px;&quot;&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-image: initial; list-style-position: outside; list-style-type: disc; margin-bottom: 0pt; margin-left: 15pt; margin-right: 0pt; margin-top: 0pt; padding-bottom: 0pt; padding-left: 0pt; padding-right: 0pt; padding-top: 0pt;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f6f9ff; color: #111111; font-family: verdana, arial, sans-serif; font-size: 13px;&quot;&gt;
&lt;li style=&quot;margin-left: 8pt; padding-bottom: 0pt; padding-left: 0pt; padding-right: 0pt; padding-top: 0pt;&quot;&gt;ШАГ 2: Пусть r есть новый индекс элемента A[p]. Тогда, если q - p &amp;gt; 2, вызовем функцию сортировки для подмассивов A[p..(r-1)] и A[(r+1)..q].&lt;/li&gt;
&lt;/span&gt;&lt;/ul&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f6f9ff; color: #111111; font-family: verdana, arial, sans-serif; font-size: 13px;&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;line-height: 1.5em; margin-bottom: 0.5em; margin-top: 0.4em; padding-bottom: 0.01px;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;Ключевая идея алгоритма заключается в процедуре «partition», которая за линейное время от размера массива, осуществляет такую перестановку элементов, относительно некоторой «оси»&amp;nbsp;— заданного значения, равного одному из значений сортируемого интервала массива, что переставленный массив состоит из трех интервалов, идущих по порядку:&lt;/span&gt;&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;ol style=&quot;line-height: 1.5em; list-style-image: none; margin-bottom: 0px; margin-left: 2.4em; margin-right: 0px; margin-top: 0.3em; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;
&lt;li style=&quot;margin-bottom: 0.1em;&quot;&gt;Элементы меньшие «оси»&lt;/li&gt;
&lt;li style=&quot;margin-bottom: 0.1em;&quot;&gt;Элементы равные «оси»&lt;/li&gt;
&lt;li style=&quot;margin-bottom: 0.1em;&quot;&gt;Элементы большие «оси»&lt;/li&gt;
&lt;/span&gt;&lt;/ol&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;margin-bottom: 0.5em; margin-top: 0.4em; padding-bottom: 0.01px;&quot;&gt;
&lt;div style=&quot;line-height: 1.5em;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;Первый и последний из упомянутых интервалов могут быть неупорядоченными, поэтому далее, они рекурсивно сортируются.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;line-height: 1.5em;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;line-height: 1.5em; margin-bottom: 0.5em; margin-top: 0.4em; padding-bottom: 0.01px;&quot;&gt;
Эффективность алгоритма существенно зависит от выбора «оси». Например, если назначать «осью» значение, которое больше или меньше всех элементов, то алгоритм вовсе не будет работать&amp;nbsp;— разбиение никак не будет уменьшать сортируемый интервал и алгоритм зациклится.&lt;/div&gt;
&lt;div style=&quot;margin-bottom: 0.5em; margin-top: 0.4em; padding-bottom: 0.01px;&quot;&gt;
&lt;div style=&quot;line-height: 1.5em;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;span style=&quot;line-height: 1.5em;&quot;&gt;Существует много
различных вариантов данного алгоритма,
отличающихся друг от друга сильно и не
очень, в основном функцией партиционирования.
Я же предлагаю Вам не сложный и при этом,
достаточно оптимальный алгоритм.
Прочитал я его в книге «Песни о Паскале»
&lt;/span&gt;&lt;a href=&quot;http://oleg-derevenets.narod.ru/&quot; style=&quot;line-height: 1.5em;&quot;&gt;http://oleg-derevenets.narod.ru/&lt;/a&gt;&lt;span style=&quot;line-height: 1.5em;&quot;&gt;
Он уже модифицирован и улучшен тем, что
оcь выбирается усредненная по 3-м точкам выборки (приближенная
к медиане). &amp;nbsp;&lt;/span&gt;&lt;span style=&quot;line-height: 24px;&quot;&gt;Данная модификация алгоритма предусматривает&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;line-height: 24px;&quot;&gt;наличие двух указателей в списке. Первый идет снизу, второй -&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;line-height: 24px;&quot;&gt;сверху. В основном цикле алгоритма нижний указатель увели&lt;/span&gt;&lt;span style=&quot;line-height: 24px;&quot;&gt;чивается до тех пор, пока не будет обнаружен элемент, больший&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;line-height: 24px;&quot;&gt;осевого, а верхний уменьшается пока не будет обнаружен эле&lt;/span&gt;&lt;span style=&quot;line-height: 24px;&quot;&gt;мент, соответственно, меньший. Затем найденные элементы меняются&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;line-height: 24px;&quot;&gt;местами. Этот процесс повторяется пока два указателя не пе&lt;/span&gt;&lt;span style=&quot;line-height: 24px;&quot;&gt;рекроются. Эти внутренние циклы работают очень быстро, по&lt;/span&gt;&lt;span style=&quot;line-height: 24px;&quot;&gt;скольку исключаются накладные расходы на проверку конца спис&lt;/span&gt;&lt;span style=&quot;line-height: 24px;&quot;&gt;ка.&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;line-height: 1.5em;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def QuickPas(s, aL, aR):
    l, r=aL, aR
    mid = (s[l]+s[(l+r)/2]+s[r])/3
    while l&lt;r: s[l]&lt;mid:l+=&quot;1&quot; s[r]=&quot;&quot; while=&quot;&quot;&gt;mid:r-=1
        if l&amp;lt;=r:
            if s[l]&amp;gt;s[r]:
                s[l], s[r] = s[r], s[l]
            l+=1
            r-=1
    if r&amp;gt;aL: QuickPas(s, aL, r)
    if l&amp;lt;aR: QuickPas(s, l, aR)
&lt;/r:&gt;&lt;/pre&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;







&lt;span style=&quot;line-height: 1.5em;&quot;&gt;Математический подход&lt;/span&gt;&lt;/h3&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-size: 13px;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;margin-bottom: 0.5em; margin-top: 0.4em; padding-bottom: 0.01px;&quot;&gt;
&lt;h3 style=&quot;font-family: sans-serif; line-height: 1.5em; text-align: left;&quot;&gt;







&lt;span style=&quot;font-size: x-small;&quot;&gt;Не строгая оценка&lt;/span&gt;&lt;/h3&gt;
&lt;div style=&quot;font-family: sans-serif; line-height: 1.5em; text-align: left;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Times New Roman&#39;; line-height: normal;&quot;&gt;Рассмотрим наихудший случай. Допустим, что нам не везет и в качестве опорного элемента выбирается либо мин. либо макс. элемент. Тогда на след рекурсивном вызове у нас останется ровно n-1 элементов. Следовательно высота нашего дерева будет n-1 &amp;nbsp;и время O(n).&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: sans-serif; line-height: 1.5em; text-align: left;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Times New Roman&#39;; line-height: normal;&quot;&gt;В наилучшем же случае, мы будем делить массив ровно пополам и получим идеально сбалансированное бинарное дерево, т.е. O(log(n)).&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; font-family: sans-serif; line-height: 1.5em; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvcYqC8W5dM5pf5kYKZ4yCT0X9PhBOgjPBBA9_3FCtEN6XBms7Fr5iOguCQixiqGlymdDNc8zwt85zmEoVcMUCNjgcNfoepetiPQTGcTIzvGjwKzg7lCCKbYe_851VNo6kQtU8AkbS/s1600/%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-2012-04-01+01:36:16.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;244&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvcYqC8W5dM5pf5kYKZ4yCT0X9PhBOgjPBBA9_3FCtEN6XBms7Fr5iOguCQixiqGlymdDNc8zwt85zmEoVcMUCNjgcNfoepetiPQTGcTIzvGjwKzg7lCCKbYe_851VNo6kQtU8AkbS/s640/%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-2012-04-01+01:36:16.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
Итак, на весах лучший и наихудший случаи, каков же средний?&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
Вероятность выбора наудачу точно средний элемент довольно низка, а именно равна 1/n. Но допустим, что разделитель является &lt;i&gt;достаточно хорошим&lt;/i&gt;, если он находится в центральной части массива, т.е. в диапазоне от n/4 до 3n/4. Таких элементов уже больше и вероятность выбора одного из них равна 1/2.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAEg3EWNbEKUMz8K9xvXbU-fhlSvmQJksgMkcLlM_EUOlYed51d0mtGzt4ijoHoKgCYQahyphenhyphenGIC3IiZKOjAp2rBNEp6mUYgQscmqGsY7DsMtuqRvNIJQ0AByuThh15svxo5IlAmUCTX/s1600/%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-2012-04-01+16:07:07.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;128&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAEg3EWNbEKUMz8K9xvXbU-fhlSvmQJksgMkcLlM_EUOlYed51d0mtGzt4ijoHoKgCYQahyphenhyphenGIC3IiZKOjAp2rBNEp6mUYgQscmqGsY7DsMtuqRvNIJQ0AByuThh15svxo5IlAmUCTX/s640/%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-2012-04-01+16:07:07.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
Оценим наихудший случай теперь. При выборе &lt;i&gt;плохого&lt;/i&gt; элемента из достаточно хороших, большая часть массива содержит 3n/4 элементов. Самая длинная ветвь такого дерева проходит через части размером n, 3n/4, (3/4)&lt;sup&gt;2&lt;/sup&gt;n...и т.д. до 1 элемента.&amp;nbsp;Длина этой ветви = высоте дерева&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh74Pf4A3V8ugiGi5J9fJx0tLJXWUAI3-3-HoQ9SBzwdj5py9uriNVWpor51kJ-ve_sZoGgxSrEyI7BvT3uj1ULKfjkhQzJKbWMgX1C4r-ZtBdb5LRr6jivVyqKKUSoijquba7N5PxC/s1600/%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-2012-04-01+17:03:33.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;30&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh74Pf4A3V8ugiGi5J9fJx0tLJXWUAI3-3-HoQ9SBzwdj5py9uriNVWpor51kJ-ve_sZoGgxSrEyI7BvT3uj1ULKfjkhQzJKbWMgX1C4r-ZtBdb5LRr6jivVyqKKUSoijquba7N5PxC/s400/%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-2012-04-01+17:03:33.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Но только половина выбираемых произвольно разделителей являются &lt;i&gt;достаточно хорошими&lt;/i&gt;, а другие &lt;i&gt;плохими&lt;/i&gt;. Т.к. вероятность выбора того или иного равна 1/2, то и высота дерева может увеличиться самоее большее в 2 раза&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_D7qkQ7jmkFXrG7LlTZLoOYwJ79hHquMe7TYShd0oaqWIabIuL7h1Z9gS2mz75DKzKTZsyF8hFYBAzoCxAqMplDQD5-vjGzJYBEWXbO1KyJ0wBNkLuX9AzcXw7YFCJDcV5fok6HYc/s1600/%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-2012-04-01+17:08:06.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;24&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_D7qkQ7jmkFXrG7LlTZLoOYwJ79hHquMe7TYShd0oaqWIabIuL7h1Z9gS2mz75DKzKTZsyF8hFYBAzoCxAqMplDQD5-vjGzJYBEWXbO1KyJ0wBNkLuX9AzcXw7YFCJDcV5fok6HYc/s320/%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-2012-04-01+17:08:06.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
Более подробный анализ показывает, что после n вставок средняя высота дерева составляет приблизительно 2ln(n), что приблизительно равно 1.3861log(n), т.е. всего на 39% больше чем идеально сбалансированное бинарное дерево.&amp;nbsp;&lt;/div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h4 style=&quot;font-family: sans-serif; line-height: 1.5em; text-align: left;&quot;&gt;







&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-size: 13px;&quot;&gt;Строгая оценка&lt;/span&gt;&lt;/h4&gt;
&lt;div&gt;
&lt;div style=&quot;font-family: sans-serif; line-height: 1.5em;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;Наихудший и наилучший случаи не требуют строгого доказательства и полностью совпадают с рассмотрением выше. Здесь же рассмотрим средний случай.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
Для анализа среднего случая рассмотрим каждую из этих возможностей и усредним результаты. При анализе наихудшего случая мы&amp;nbsp;заметили, что процедура разбиения делает N — 1 сравнений, разбивая&amp;nbsp;список из N элементов. Слияние этих списков не требует никаких действий. Наконец, заметим, что когда она возвращает значение оси(P),&amp;nbsp;происходит рекурсивный вызов процедуры Quicksort на списках длины Р — I и N — Р. Проводимый нами анализ среднего случая должен&amp;nbsp;учитывать все N возможных значений .&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7aJRM82UcSaf03hpIM8WdKgP7Ijgi_wJbG24qhn_x58rcZq5PAryNClsJWiRDOVH6N2jpr-zE_n-74hGRgAalsbqze8ehadbhj5_h5a-7BaP7tOU915_koEJBNZg9HeIZe0TdXqFu/s1600/%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-2012-04-01+18:48:41.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;68&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7aJRM82UcSaf03hpIM8WdKgP7Ijgi_wJbG24qhn_x58rcZq5PAryNClsJWiRDOVH6N2jpr-zE_n-74hGRgAalsbqze8ehadbhj5_h5a-7BaP7tOU915_koEJBNZg9HeIZe0TdXqFu/s320/%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-2012-04-01+18:48:41.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
Если повнимательней посмотреть на сумму, то видно, что аргумент&amp;nbsp;первого слагаемого пробегает значения от 0 до N — 1, а аргумент второго слагаемого — те же значения, но в порядке убывания.&lt;/div&gt;
&lt;div&gt;
Это означает, что каждое из слагаемых А(г) участвует в сумме дважды, и формулу можно упростить:&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiq4LX33D7FC5gXUUmVHtzwOJa_O_C8ToKHGVIYVaxMB5fO0WcvEtfqMhMfqE7-44bR8Tje3Eox6AcpGK-kcyATE5W0nGSs11lqm-XndzH7o4hQdzM_E0H1t2zQzSq3twmGVEzBuwYt/s1600/%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-2012-04-01+18:50:01.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;81&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiq4LX33D7FC5gXUUmVHtzwOJa_O_C8ToKHGVIYVaxMB5fO0WcvEtfqMhMfqE7-44bR8Tje3Eox6AcpGK-kcyATE5W0nGSs11lqm-XndzH7o4hQdzM_E0H1t2zQzSq3twmGVEzBuwYt/s320/%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-2012-04-01+18:50:01.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
теперь давайте посмотрим сразу на 2 формулы&amp;nbsp;для A(N) и для A(N — 1).&lt;/div&gt;
&lt;div&gt;
Эти два выражения отличаются лишь несколькими членами.&lt;/div&gt;
&lt;div&gt;
Чтобы избавиться от дробей, подсчитаем A(N)-N и A(N—1)-(N—1).&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZBpesUrGUIjtdEh-ANW7aWUTZHtO0jLKKtdTK_MtPCC_FnhAtqH_KJl9ZLa_2WsXhdJxbJ70JBGCiZ7HpPYa8x16UqQIWCJH_YVh99x_WqRwFEAlD0_N54VvOxKKQpmKltBfhU1im/s1600/%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-2012-04-01+18:55:41.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;128&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZBpesUrGUIjtdEh-ANW7aWUTZHtO0jLKKtdTK_MtPCC_FnhAtqH_KJl9ZLa_2WsXhdJxbJ70JBGCiZ7HpPYa8x16UqQIWCJH_YVh99x_WqRwFEAlD0_N54VvOxKKQpmKltBfhU1im/s320/%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-2012-04-01+18:55:41.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Путем не сложных преобразований получим окончательное рекуррентное соотношение&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtzz_Wkhhe1Hwll9KsP1Eo2_Qi7yM0NvWgLj-K24p2_5hppPVv4qQfuT96ZOrCb4OGqGcgcEq1kNtkxMuIRVW49w3YV6ghz8bX40S6iLvHoqvsTHU2qB-C-A9atouNTWuEsTPVign9/s1600/%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-2012-04-01+18:57:31.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;87&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtzz_Wkhhe1Hwll9KsP1Eo2_Qi7yM0NvWgLj-K24p2_5hppPVv4qQfuT96ZOrCb4OGqGcgcEq1kNtkxMuIRVW49w3YV6ghz8bX40S6iLvHoqvsTHU2qB-C-A9atouNTWuEsTPVign9/s320/%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-2012-04-01+18:57:31.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
Его детальный анализ дает A(N) = 1.4(N +1)log&lt;sub&gt;2&lt;/sub&gt;N. Таким образом, средняя&lt;/div&gt;
&lt;div&gt;
сложность алгоритма быстрой сортировки равна O(Nlog&lt;sub&gt;2&lt;/sub&gt;N).&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;




Улучшаем алгоритм&lt;/h3&gt;
&lt;div&gt;
Вся сложность алгоритма Хоара заключается в процедуре разделения массива на 2 половины, что зависит от правильного выбора оси разбиения и чем она ближе к медиане, тем лучше. Следовательно, если мы найдём метод приблизиться к ней(медиане) тем все станет красочнее и пушистее.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
Методы основные следующие:&lt;/div&gt;
&lt;div&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;алгоритм выбора значения наиболее приближенного к медиане&lt;/li&gt;
&lt;li&gt;вероятностный выбор оси&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
Описанный выше алгоритм относится, как раз к 1 пункту. Там мы находим элемент по 3-м точкам и в среднем он оказывается ближе к медиане, чем постоянный выбор оси.&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
2 пункт реализовать так же не сложно, что описывается в &quot;инженерном подходе&quot;. Можно отметить, что данная модификация является не столь эффективной как 1-я, однако спасает нас от деградации алгоритма при граничных случаях (т.е. сводит почти к 0 вероятность выполнения алгоритма за квадратичное время).&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;





Инженерный подход&lt;/h3&gt;
&lt;/div&gt;
&lt;div style=&quot;font-family: sans-serif; line-height: 1.5em;&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-size: 13px;&quot;&gt;
&lt;/span&gt;&lt;br /&gt;
Рассмотрим простенький вариантик с использованием встроенной в Питон возможностью условной генерации списков вместо использования функции&amp;nbsp;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace; white-space: pre;&quot;&gt;partition.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def qsort1(list):
    if list == []: 
        return []
    else:
        pivot = list[0]
        lesser = qsort1([x for x in list[1:] if x &amp;lt; pivot])
        greater = qsort1([x for x in list[1:] if x &amp;gt;= pivot])
        return lesser + [pivot] + greater&lt;/pre&gt;
&lt;span class=&quot;mw-headline&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;mw-headline&quot;&gt;И его однострочная версия&lt;/span&gt;&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def qsortr2(list):
    return [] if list==[]  else qsortr2([x for x in list[1:] if x &amp;lt; list[0]]) + [list[0]] + qsortr2([x for x in list[1:] if x &amp;gt;= list[0]])&lt;/pre&gt;
&lt;br /&gt;
На данных примерах показывается лаконичность и изящность языка, надеюсь вы оценили :)&lt;br /&gt;
&lt;br /&gt;
На сладкое, привожу вам вариант, которому меня научил в университете великий Деон!) Версия избавлена от рекурсии, классическим способом - введением стека, в котором хранятся границы наших интервалов.&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def QuickSort(a):
    w = [x for x in xrange(4 + len(a) / 2)]#создаём стек
    k = 0#дно
    w[0] = 0#указатель на позицию левой границы половины
    w[1] = len(a) - 1#-||- правой
    while (k &amp;gt;= 0):
        i = QuickSortPos(a, w[k], w[k + 1])
        if(i != w[k + 1]):RL =i + 1#левая граница правого подъинтервала
        else:RL =w[k + 1]
        RR = w[k + 1]#Правая граница правого подъинтервала
        LL = w[k]#Левая граница левого подъинтервал
        if(i != w[k]):LR =i - 1#Правая граница левого подъинтервал
        else:LR =w[k]
        k -= 2#удалить текущий интервал
        if (RL != RR):k += 2; w[k] = RL; w[k + 1] = RR
        if (LL != LR):k += 2; w[k] = LL; w[k + 1] = LR
    return

def QuickSortPos(a, left, right):
    i = left
    j = right - 1
    while (True):#чтобы поставить разделяющий элемент на свое место
        while (a[i] &amp;lt; a[right]): i+=1
        while (a[j] &amp;gt; a[right] and j &amp;gt; left): j-=1
        if (i &amp;gt;= j): break
        a[i],a[j] = a[j],a[i]
    a[right],a[i]  = a[i],a[right]
    return i
&lt;/pre&gt;
Сразу скажу, что он показывает максимальную производительность из все виденных мной.&lt;br /&gt;
&lt;br /&gt;
Стоит сказать пару слов про использование методов оптимизации и их применимости на практике.&lt;br /&gt;
&lt;span class=&quot;mw-headline&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;mw-headline&quot; id=&quot;.D0.91.D1.8B.D1.81.D1.82.D1.80.D0.B0.D1.8F_.D1.81.D0.BE.D1.80.D1.82.D0.B8.D1.80.D0.BE.D0.B2.D0.BA.D0.B0_.D1.81_.D0.B2.D0.B5.D1.80.D0.BE.D1.8F.D1.82.D0.BD.D0.BE.D1.81.D1.82.D0.BD.D1.8B.D0.BC_.D0.B2.D1.8B.D0.B1.D0.BE.D1.80.D0.BE.D0.BC_.D0.BE.D1.81.D0.B8&quot;&gt;&lt;b&gt;Быстрая сортировка с вероятностным выбором оси&lt;/b&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;div style=&quot;line-height: 1.5em; margin-bottom: 0.5em; margin-top: 0.4em; padding-bottom: 0.01px;&quot;&gt;
К сожалению, предположение о равномерности распределения «осей» относительно интервалов, может не встречаться на практике. Например, есть вариации детерминированного алгоритма, для которых «плохими» будут уже отсортированные (или почти отсортированные) последовательности, а таковые часто встречаются в реальных задачах. В таких случаях, когда нельзя «сделать случайными» входные данные, можно внести «элемент случайности» непосредственно в сам алгоритм. В частности, чтобы сохранилась оптимальная оценка&amp;nbsp;математического ожидания, достаточно сделать вероятностным выбор осевого элемента из разделяемого интервала.&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;Вероятностный алгоритм отличается от детерминированного, только строчкой, где задается выбор вероятностный выбор осевого элемента, для первого алгоритма она будет выглядеть следующим образом&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f9f9f9; font-size: 13px; line-height: 19px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: sans-serif;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f9f9f9; font-family: monospace; font-size: 13px; line-height: 14px; white-space: pre-wrap;&quot;&gt;indexLow,indexHigh)=partition(left,right,A[RandomSource.randrange(left, right)]) &lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f9f9f9; font-family: monospace; font-size: 13px; line-height: 14px; white-space: pre-wrap;&quot;&gt;где&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f9f9f9; font-family: monospace; font-size: 13px; line-height: 14px; white-space: pre-wrap;&quot;&gt;RandomSource создаётся перед quicksort_interval(0, len(A)) так&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f9f9f9; font-family: monospace; font-size: 13px; line-height: 14px; white-space: pre-wrap;&quot;&gt;RandomSource = random.Random(6666) # Инициализируем генератор случайных чисел.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f9f9f9; font-family: monospace; font-size: 13px; line-height: 14px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;margin-bottom: 0cm;&quot;&gt;
К сожалению, реализация Random сама по себе привносит большие
задержки. Я так и не нашел входных данных, при которых он выиграл у первого варианта.&lt;/div&gt;
&lt;div style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;margin-bottom: 0cm;&quot;&gt;
В большинстве зарубежных книжных изданиях, представлен данный алгоритм:&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def partition(A, left, right):           
#       indexLow  = left+1             # Нижний и текущий индексы                        
#       indexHigh = right-1    
    pivotPoint=left         # Верхний индекс
    pivotVal = A[left]
    i=left+1
    while i &amp;lt;= right:# Пока есть область не просмотренных элементов.
        if A[i] &amp;lt; pivotVal:
            pivotPoint+=1# Если элемент меньше оси
            if i&amp;gt;pivotPoint:#мое улучшение :) убирает перестановки эл-та с самим собой
                A[i], A[pivotPoint]=A[pivotPoint],A[i]# гоним его в начало интервала
#               indexLow = indexLow + 1 # сужаем область слева
        i +=1
#       print A, left, pivotPoint
    A[left],  A[pivotPoint] = A[pivotPoint], A[left]
    return pivotPoint
&lt;/pre&gt;
&lt;div style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Данная реализация сокращает количество перестановок по сравнению с классическим вариантом, однако проигрывает первому варианту, т.к. тот сокращает обе границы циклов, при каждом обмене, а этот лишь нижнюю. Т.е. рано или поздно в нем произойдет так, что фактически массив будет разбит, но алгоритм все равно будет идти до самого верха, выполняя сравнение с осевым элементом, хотя все они будут точно больше.&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f9f9f9; font-family: monospace; font-size: 13px; line-height: 14px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;margin-bottom: 0cm;&quot;&gt;
В основном, методы
призванные приблизить выполнение
алгоритма к оптимальному, за счет поиска
более точного положения оси, лишь
усложняет логику, что приводит к
увеличению числа сравнений, обменов
или того и другого одновременно. Если Вы
заинтересуетесь данной проблемой, прошу
заметить, что операции сравнения дешевле
обменов, а следовательно стоит уменьшать
кол-во вторых, чаще за счет увеличения
первых. &amp;nbsp;&lt;/div&gt;
&lt;br /&gt;
&lt;div style=&quot;margin-bottom: 0cm;&quot;&gt;
&lt;br /&gt;
Экспериментально
доказано, что в среднем алгоритм быстрой
сортировки работает в 2-3 раза быстрее
сортировок слиянием и пирамидальной.&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f9f9f9; font-family: monospace; font-size: 13px; line-height: 14px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f9f9f9; font-family: monospace; font-size: 13px; line-height: 14px; white-space: pre-wrap;&quot;&gt;&lt;b&gt;Производительность&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f9f9f9; font-family: monospace; font-size: 13px; line-height: 14px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;line-height: 24px;&quot;&gt;Тестирование проводилось на списке из 50000 не повторяющихся элементов.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f9f9f9; font-family: monospace; font-size: 13px; line-height: 14px; white-space: pre-wrap;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; font-size: small; line-height: normal; white-space: normal;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f9f9f9; font-family: monospace;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;line-height: 14px; white-space: pre-wrap;&quot;&gt;первый алгоритм &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;span style=&quot;white-space: pre;&quot;&gt;54074 function calls in 0.572 seconds&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;i style=&quot;background-color: #f9f9f9; font-family: monospace; font-size: 13px; line-height: 14px; white-space: pre-wrap;&quot;&gt;второй алгоритм избавленный от рекурсии &lt;/i&gt;&lt;i&gt;33395 function calls in 0.432 seconds&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;третий - однострочная Python версия 100004 function calls (4 primitive calls) in 0.708 seconds&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f9f9f9; font-family: monospace; font-size: 13px; line-height: 14px; white-space: pre-wrap;&quot;&gt;&lt;i&gt;Встроенная реализация сортировки list.sort() 4 function calls in 0.004 CPU seconds&lt;/i&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f9f9f9; font-family: monospace; font-size: 13px; line-height: 14px; white-space: pre-wrap;&quot;&gt;Результат показывает, насколько выгодно избавляться от рекурсии, но реализация на чистом С, всё равно рулит и бибикает)
&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #f9f9f9; font-family: monospace; font-size: 13px; line-height: 14px; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;b&gt;Используемая литература:&lt;/b&gt;&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BF%D1%83%D0%B7%D1%8B%D1%80%D1%8C%D0%BA%D0%BE%D0%BC&quot;&gt;Википедия&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://traditio.ru/wiki/%D0%91%D1%8B%D1%81%D1%82%D1%80%D0%B0%D1%8F_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&quot;&gt;Традиция&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Алгоритмы. Руководство по разработке. Автор: Стивен Скиена&lt;/li&gt;
&lt;li&gt;Основы современных алгоритмов. Автор: Макконнелл Дж.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/534324071355682897/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2011/11/quicksort.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/534324071355682897'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/534324071355682897'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2011/11/quicksort.html' title='Быстрая сортировка(quicksort, сортировка Хоара)'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvcYqC8W5dM5pf5kYKZ4yCT0X9PhBOgjPBBA9_3FCtEN6XBms7Fr5iOguCQixiqGlymdDNc8zwt85zmEoVcMUCNjgcNfoepetiPQTGcTIzvGjwKzg7lCCKbYe_851VNo6kQtU8AkbS/s72-c/%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-2012-04-01+01:36:16.png" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-4329037114005782765</id><published>2011-10-03T12:41:00.000-07:00</published><updated>2011-11-02T04:36:38.048-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Сортировки"/><title type='text'>Пузырьковая сортировка</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://fiskus.name/static/2011/05/bubble-sort.gif&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;111&quot; src=&quot;http://fiskus.name/static/2011/05/bubble-sort.gif&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;Алгоритм состоит в повторяющихся проходах по сортируемому массиву. За каждый проход элементы последовательно сравниваются попарно и, если порядок в паре неверный, выполняется обмен элементов. Проходы по массиву повторяются до тех пор, пока на очередном проходе не окажется, что обмены больше не нужны, что означает&amp;nbsp;— массив отсортирован. При проходе алгоритма, элемент, стоящий не на своём месте, «всплывает» до нужной позиции как пузырёк в воде, отсюда и название алгоритма.&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;Для понимания и реализации этот алгоритм&amp;nbsp;— простейший, но эффективен он лишь для небольших массивов. Сложность алгоритма:&amp;nbsp;O(&lt;i&gt;n&lt;/i&gt;²).&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;; font-size: small; line-height: normal;&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: red; font-size: xx-small;&quot;&gt;&lt;b&gt;*-Нравится статья? Кликни по рекламе! :)&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #eeeeee; font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;font-size: 13pt;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;Расположим массив сверху вниз, от нулевого элемента - к последнему.&lt;/span&gt;&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #eeeeee; font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;font-size: 13pt;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #eeeeee; font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;Идея метода: шаг сортировки состоит в проходе снизу вверх по массиву. По пути просматриваются пары соседних элементов. Если элементы некоторой пары находятся в неправильном порядке, то меняем их местами.&lt;/span&gt;&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #eeeeee; font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div align=&quot;center&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #eeeeee; font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;225&quot; src=&quot;http://algolist.manual.ru/sort/gif/6.gif&quot; width=&quot;375&quot; /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #eeeeee; font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;font-size: 13pt;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #eeeeee; font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;После нулевого прохода по массиву &quot;вверху&quot; оказывается самый &quot;легкий&quot; элемент - отсюда аналогия с пузырьком. Следующий проход делается до второго сверху элемента, таким образом второй по величине элемент поднимается на правильную позицию.&lt;/span&gt;&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #eeeeee; font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;font-size: 13pt;&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #eeeeee; font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;Делаем проходы по все уменьшающейся нижней части массива до тех пор, пока в ней не останется только один элемент. На этом сортировка заканчивается, так как последовательность упорядочена по возрастанию.&lt;/span&gt;&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #eeeeee; font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div align=&quot;center&quot;&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #eeeeee; font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;184&quot; src=&quot;http://algolist.manual.ru/sort/gif/7.gif&quot; width=&quot;527&quot; /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #eeeeee; font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #eeeeee; font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: 17px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #eeeeee;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;font-size: 13pt;&quot;&gt;
Среднее число сравнений и обменов имеют квадратичный порядок роста: O(n&lt;sup&gt;2&lt;/sup&gt;), отсюда можно заключить, что алгоритм пузырька очень медленен и малоэффективен.&lt;br /&gt;
Тем не менее, у него есть громадный плюс: он прост и его можно по-всякому улучшать.&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;font-size: 13pt;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 13pt;&quot;&gt;
Чем мы сейчас и займемся:&lt;/div&gt;
&lt;div style=&quot;font-size: 13pt;&quot;&gt;
&lt;/div&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Во-первых, рассмотрим ситуацию, когда на каком-либо из проходов не произошло ни одного обмена. Что это значит ?Это значит, что все пары расположены в правильном порядке, так что массив уже отсортирован. И продолжать процесс не имеет смысла(особенно, если массив был отсортирован с самого начала !).Итак, первое улучшение алгоритма заключается в запоминании, производился ли на данном проходе какой-либо обмен. Если нет - алгоритм заканчивает работу.&lt;/li&gt;
&lt;li&gt;Процесс улучшения можно продолжить, если запоминать не только сам факт обмена, но и индекс последнего обмена k. Действительно: все пары соседих элементов с индексами, меньшими k, уже расположены в нужном порядке. Дальнейшие проходы можно заканчивать на индексе k, вместо того чтобы двигаться до установленной заранее верхней границы i.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: 17px;&quot;&gt;Качественно другое улучшение алгоритма можно получить из следующего наблюдения. Хотя легкий пузырек снизу поднимется наверх за один проход, тяжелые пузырьки опускаются со минимальной скоростью: один шаг за итерацию. Так что массив 2 3 4 5 6 1 будет отсортирован за 1 проход, а сортировка последовательности 6 1 2 3 4 5 потребует 5 проходов.Чтобы избежать подобного эффекта, можно менять направление следующих один за другим проходов.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
&lt;div style=&quot;font-size: 13pt;&quot;&gt;
Получившийся алгоритм иногда называют &quot;&lt;i&gt;шейкер-сортировкой&lt;/i&gt;&quot;.&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;Лучший случай для этой сортировки — отсортированный массив (О(n)), худший — отсортированный в обратном порядке (O(n²)).&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: white; font-family: sans-serif; font-size: 13px; line-height: 19px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #eeeeee; font-family: &#39;Times New Roman&#39;; font-size: 17px; line-height: normal;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div id=&quot;-chrome-auto-translate-plugin-dialog&quot; style=&quot;background-attachment: initial !important; background-clip: initial !important; background-color: transparent !important; background-image: initial !important; background-origin: initial !important; display: none; left: 0px; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; opacity: 1 !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: absolute !important; text-align: left !important; top: 0px; z-index: 999999 !important;&quot;&gt;
&lt;div style=&quot;-webkit-border-radius: 10px !important; background-color: #363636 !important; background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0%, #000), color-stop(50%, #363636), color-stop(100%, #000)); border-color: #000000 !important; border-width: 0px !important; color: #fafafa !important; font-size: 16px !important; max-width: 300px !important; opacity: 0.8 !important; overflow: visible !important; padding: 8px !important; text-align: left !important; z-index: 999999 !important;&quot;&gt;
&lt;div class=&quot;translate&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;additional&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;img onclick=&quot;document.location.href=&#39;http://translate.google.com/&#39;;&quot; src=&quot;http://www.google.com/uds/css/small-logo.png&quot; style=&quot;-webkit-border-radius: 20px; background-color: rgba(200, 200, 200, 0.3) !important; cursor: pointer !important; margin: 0 !important; padding: 3px 5px 0 !important; position: absolute !important; right: 1px !important; top: -20px !important; z-index: -1 !important;&quot; /&gt;&lt;/div&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def shakerSort(a): 
    #lb, ub границы неотсортированной части массива
    k= ub = len(a)-1
    lb=1
    while ( lb &amp;lt; ub ):
        # проход сверху вниз 
        for j in xrange (ub, lb-1, -1):
            if a[j-1] &amp;gt; a[j]: 
                a[j-1], a[j] = a[j], a[j-1]
                k=j
            lb = k
        # проход снизу вверх 
        for j in xrange (lb, ub+1):
            if a[j-1] &amp;gt; a[j]:
                a[j-1], a[j] = a[j], a[j-1]
                k=j
            ub = k
    return a
&lt;/pre&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;background-color: #eeeeee; font-size: 17px;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;font-size: 13pt;&quot;&gt;
Насколько описанные изменения повлияли на эффективность метода ? Среднее количество сравнений, хоть и уменьшилось, но остается O(n&lt;sup&gt;2&lt;/sup&gt;), в то время как число обменов не поменялось вообще никак. Среднее(оно же худшее) количество операций остается квадратичным.&lt;/div&gt;
&lt;div style=&quot;font-size: 13pt;&quot;&gt;
Дополнительная память, очевидно, не требуется. Поведение усовершенствованного (но не начального) метода довольно естественное, почти отсортированный массив будет отсортирован намного быстрее случайного. Сортировка пузырьком &lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%A3%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%B0%D1%8F_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&quot;&gt;устойчива&lt;/a&gt;, однако шейкер-сортировка утрачивает это качество.&lt;/div&gt;
&lt;div style=&quot;font-size: 13pt;&quot;&gt;
На практике метод пузырька, даже с улучшениями, работает, увы, слишком медленно. А потому - почти не применяется.&lt;br /&gt;
&lt;br /&gt;
Так же мы создавали сортировку пузырьком, когда рассматривали &lt;a href=&quot;http://py-algorithm.blogspot.com/2011/08/blog-post.html&quot;&gt;связный список&lt;/a&gt;, но он сортирует 5000 значений 183 сек, в то время, как shaker_sort 3.6 сек.&lt;br /&gt;
&lt;a href=&quot;http://habrahabr.ru/blogs/algorithm/73726/&quot;&gt;Интересная статья&lt;/a&gt;, не совсем про сортировку и Python, но в тему)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Вычисление времени выполнения&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Все операторы присваивания, как и проверки &lt;i&gt;if&lt;/i&gt; имеют некоторое постоянное время выполнения О(1). Все операторы в каждом из циклов, в среднем, выполняются n-i раз. А по правилу сложения времен 2n-2i(т.к. 2 цикла). Цикл while в среднем выполняется (n-1)/2 раз. И если мы напишем формулу суммы сократив заранее 2-ки, получим среднее выражение&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhx9MLlqwQ-_JenGzpp77s7Nz51rwXAVGfqIsd6gqEsGrBmLOLvRDfH3nJByq1tTTvQJciAU3XqQvGNBGuBwJWluJM2ILesVFocVlnRDX8-xdRmgQyG0DrHJdtKOpGXkuQhC7CvMBr7/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhx9MLlqwQ-_JenGzpp77s7Nz51rwXAVGfqIsd6gqEsGrBmLOLvRDfH3nJByq1tTTvQJciAU3XqQvGNBGuBwJWluJM2ILesVFocVlnRDX8-xdRmgQyG0DrHJdtKOpGXkuQhC7CvMBr7/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Тем самым мы показали, что данный алгоритм имеет порядок роста&amp;nbsp;O(n&lt;sup&gt;2&lt;/sup&gt;)&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;b&gt;Используемая литература:&lt;/b&gt;&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%BF%D1%83%D0%B7%D1%8B%D1%80%D1%8C%D0%BA%D0%BE%D0%BC&quot;&gt;Википедия&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://algolist.manual.ru/sort/bubble_sort.php&quot;&gt;Algolist&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/4329037114005782765/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2011/10/blog-post.html#comment-form' title='Комментарии: 6'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/4329037114005782765'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/4329037114005782765'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2011/10/blog-post.html' title='Пузырьковая сортировка'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhx9MLlqwQ-_JenGzpp77s7Nz51rwXAVGfqIsd6gqEsGrBmLOLvRDfH3nJByq1tTTvQJciAU3XqQvGNBGuBwJWluJM2ILesVFocVlnRDX8-xdRmgQyG0DrHJdtKOpGXkuQhC7CvMBr7/s72-c/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.jpg" height="72" width="72"/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-4235830437491480073</id><published>2011-09-14T08:35:00.000-07:00</published><updated>2011-11-03T13:15:09.575-07:00</updated><title type='text'>Раскраска графа</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihUbKV8Wepo80AooImZ-IKwmKrwHpilKrGlhNNQY8Tf7IrfmESTBbEn9F-fCldMhFl70d7fJMcJINhq0d_J9EsCBj1LLVBG8vt0sfDNK2zp42nmzOMaNW8U-YtNRT8fb7AW17bXkU7/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://blogs.msdn.com/cfs-filesystemfile.ashx/__key/CommunityServer-Components-ImageFileViewer/CommunityServer-Blogs-Components-WeblogFiles-00-00-00-29-89/1715.FourGraph3.png_2D00_550x0.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://blogs.msdn.com/cfs-filesystemfile.ashx/__key/CommunityServer-Components-ImageFileViewer/CommunityServer-Blogs-Components-WeblogFiles-00-00-00-29-89/1715.FourGraph3.png_2D00_550x0.png&quot; width=&quot;310&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Рассмотрим математическую модель, используемую для управления&lt;br /&gt;
светофорами на сложном перекрестке дорог. Мы должны создать программу, которая в&lt;br /&gt;
качестве входных данных использует множество всех допустимых поворотов на перекрестке (продолжение прямой дороги, проходящей через перекресток, также будем&lt;br /&gt;
считать &quot;поворотом&quot;) и разбивает это множество на несколько групп так, чтобы все повороты в группе могли выполняться одновременно, не создавая проблем друг для друга. Затем мы сопоставим с каждой группой поворотов соответствующий режим работы&lt;br /&gt;
светофоров на перекрестке.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&lt;span style=&quot;color: red; font-size: xx-small;&quot;&gt;&lt;b&gt;*-Нравится статья? Кликни по рекламе! :)&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2Q0lCx_Sy0wBMcqLwt6CzF0jH380VtQa8b5tV4_GDEQ47iSVg8MxT6I2S6g_c0p-pEEeAoAX_MhIcjlYV0JoaCEhozBf8-nsmqNobZKRdp7YIG1ApQ_Z83DlEbOGRz1DpRuirDhi5/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;br /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; margin-right: 1em; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVEBM_jQcfFeGDsJN55mD6SxLYHNscgDiKL67sXn_jHWMvRETb2FMr0bQOb1VFL8spFYQ0UfKGYb_23vn21Nb_7iKEd0qYpPwVhE593rM5PdNWTi37ryroAFk2FB9j-325YwpdCkfy/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;163&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVEBM_jQcfFeGDsJN55mD6SxLYHNscgDiKL67sXn_jHWMvRETb2FMr0bQOb1VFL8spFYQ0UfKGYb_23vn21Nb_7iKEd0qYpPwVhE593rM5PdNWTi37ryroAFk2FB9j-325YwpdCkfy/s200/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Рис. 1.1. Сложный перекресток&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Желательно минимизировать число разбиений исходного множества поворотов, поскольку при этом минимизируется количество режимов работы светофоров на перекрестке.&lt;br /&gt;
Для примера на рис. 1.1 показан перекресток возле Принстонского университета, известный сложностью его преодоления. Обратите внимание, что дороги С и E односторонние, остальные — двухсторонние. Всего на этом перекрестке возможно 13 поворотов. Некоторые-из этих поворотов, такие как АВ (поворот с дороги А на дорогу В) и ЕС, могут выполняться одновременно. Трассы других поворотов, например АО и ЕВ, пересекаются, поэтому их нельзя выполнять одновременно. Режимы работы светофоров должны учитывать эти обстоятельства.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3QDShKDRpo8ZWIbdH8XEWZdBBdP67fQmpVfhLdO6S4yLCnX_uUw1f8lcKN2Z4nKprq3jGqnZTZxqzwh_kZVZFaXeUawAlETODwSC8MrarBH4OMxpl9hNejSXfLyhjIET0YMCRsYSe/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;br /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; margin-right: 1em; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7gsXyD0iDGzJBGOvE721oXmJVa8x1Jv0LWw00uQu-0YBfecPJPKEwb4ESzTf8hEM_Hjo7ua9luh29_8WeHjsSM18CLP8bdRtj7aeddXqUJcrRUD-WEWfM2ZZZYf1Ma0AA2GjO9Rd1/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;192&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7gsXyD0iDGzJBGOvE721oXmJVa8x1Jv0LWw00uQu-0YBfecPJPKEwb4ESzTf8hEM_Hjo7ua9luh29_8WeHjsSM18CLP8bdRtj7aeddXqUJcrRUD-WEWfM2ZZZYf1Ma0AA2GjO9Rd1/s200/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Рис. 1.2. Граф, показывающий несо-&lt;br /&gt;
вместимые повороты&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Для построения модели этой задачи можно применить математическую структуру, известную как &lt;a href=&quot;http://py-algorithm.blogspot.com/2011/06/python.html&quot;&gt;граф&lt;/a&gt;. Для решения задачи можно нарисовать граф, где вершины будут представлять повороты, а ребра соединят ту часть вершин-поворотов, которые нельзя выполнить одновременно. Для нашего перекрестка соответствующий граф показан на рис. 1.2, а в табл. 1.1 дано другое представление графа — в виде таблицы(матрицы смежности), где на пересечении строки i и столбца j стоит 1 тогда и только тогда, когда существует ребро между вершинами i и j.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzpzf3MjMoelzA3fTb7sfoRGTyZTli_E37EG4JyiAgAKG5EkqE8L_R0bdk874ta3xek7w87Sw694IcXVYcahtjLOLFjlAirfbIFKOcSEqmh8CGdoU5oZU54FLPtjSLHSlpIKdmPFVh/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;br /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; margin-right: 1em; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMjonQNpKHCxLZCCnm5PREGpBnoWWIpz4zZSUT65zGhaSHXuPNvJPVrsigje2CL4GYJ6ti0vxHK0V5XqRp4DMVpXLy8pVouYBhqofdOlveY1gW4WWsjbSjfPg1pkLn5s0NaHy5Rcwj/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;159&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMjonQNpKHCxLZCCnm5PREGpBnoWWIpz4zZSUT65zGhaSHXuPNvJPVrsigje2CL4GYJ6ti0vxHK0V5XqRp4DMVpXLy8pVouYBhqofdOlveY1gW4WWsjbSjfPg1pkLn5s0NaHy5Rcwj/s320/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Таблица 1.1. Таблица несовместимых поворотов&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
В рамках этой модели можно использовать решение, которое дает математическая задача раскраски графа: каждой вершине графа надо так задать цвет, чтобы никакие две соединенные ребром вершины не имели одинаковый цвет, и при этом по возможности использовать минимальное количество цветов. При такой раскраске графа несовместимым поворотам будут окрашены в разные цвета.&lt;br /&gt;
&lt;br /&gt;
Проблема раскраски графа изучается математиками уже несколько десятилетий, но теория алгоритмов мало что может сказать о решении этой проблемы. К сожалению, задача раскраски произвольного графа минимальным количеством цветов принадлежит классу задач, которые называются &lt;i&gt;NP-полными&lt;/i&gt; задачами и для которых все известные решения относятся к типу &quot;проверь все возможности&quot; или &quot;перебери все варианты&quot;. Для раскраски графа это означает, что сначала для&amp;nbsp; закраски вершин используется один цвет, затем — два цвета, потом — три и т.д., пока не будет получена подходящая раскраска вершин. В некоторых частных случаях можно предложить более быстрое решение, но в общем случае не существует&lt;br /&gt;
более эффективного (в значительной степени) алгоритма решения задачи раскраски, чем алгоритм полного перебора возможных вариантов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, поиск оптимального решения задачи раскраски графа требует больших вычислительных затрат. В этой ситуации можно воспользоваться одним из следующих трех подходов. &lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Если граф небольшой, можно попытаться найти оптимальное решение, перебрав все возможные варианты раскраски. Однако этот подход не приемлем для больших графов, так как программно трудно организовать эффективный перебор всех вариантов.&lt;/li&gt;
&lt;li&gt;Второй подход предполагает использование дополнительной информации об исходной задаче. Желательно найти какие-то особые свойства графа, которые исключали бы необходимость полного перебора всех вариантов раскраски для нахождения оптимального решения.&lt;/li&gt;
&lt;li&gt;В третьем подходе мы немного изменяем постановку задачи и ищем не оптимальное решение, а близкое к оптимальному. Если мы откажемся от требования минимального количества цветов раскраски графа, то можно построить алгоритмы раскраски, которые работают значительно быстрее, чем алгоритмы полного перебора.&lt;/li&gt;
&lt;/ol&gt;
Алгоритмы, которые быстро находят &quot;подходящее&quot;, но не оптимальное решение, называются &lt;i&gt;эвристическими&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;Примером рационального эвристического алгоритма может служить следующий &quot;&lt;i&gt;жадный&lt;/i&gt;&quot; алгоритм раскраски графа. В этом алгоритме сначала мы пытаемся раскрасить как можно больше вершин в один цвет, затем закрашиваем во второй цвет также по возможности максимальное число оставшихся вершин, и т.д. При закраске вершин в новый цвет мы выполняем следующие действия.&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Выбираем произвольную не закрашенную вершину и назначаем ей новый цвет. &lt;/li&gt;
&lt;li&gt;Просматриваем список не закрашенных вершин и для каждой из них определяем, соединена ли она ребром с вершиной, уже закрашенной в новый цвет. Если&lt;br /&gt;не соединена, то к этой вершине также применяется новый цвет.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwUSf6f87oFDj1yhgbas0pFgiFoe0WOGUklbJL6dUrp9a7T4RDgfLNjaA9cwxVlmTT3i5mpiG1ws8129gctOAJEy6w7WtHfMI-7EKVNllRFapLd6YduDZDq8-rrMwEdPt3EVzpXfC0/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;br /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; margin-right: 1em; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijNjv7QeKosdhX5VlC4dboucoYrQamuSB9hCv6ygt3s6KBd1ELoYxqPhrcpLou1MUiuOQSJKrdrjDgTOiM3_rtLTrE6H3zC7IK5EmeucStHd3fsKI0rsE8qPavzmwCZ97furjLA76m/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijNjv7QeKosdhX5VlC4dboucoYrQamuSB9hCv6ygt3s6KBd1ELoYxqPhrcpLou1MUiuOQSJKrdrjDgTOiM3_rtLTrE6H3zC7IK5EmeucStHd3fsKI0rsE8qPavzmwCZ97furjLA76m/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.png&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Рис. 1.3. Граф&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Этот алгоритм назван &quot;&lt;i&gt;жадным&lt;/i&gt;&quot; из-за того, что каждый цвет применяется к максимально большому числу вершин, без возможности пропуска некоторых из них или перекраски ранее закрашенных. Возможны ситуации, когда, будь алгоритм менее &quot;&lt;i&gt;жадным&lt;/i&gt;&quot; и пропустил бы некоторые вершины при закраске новым цветом, мы получили бы раскраску графа меньшим количеством цветов. Например, для раскраски графа на рис. 1.3 можно было бы применить два цвета, закрасив вершину 1 в красный цвет, а затем, пропустив вершину 2, закрасить в красный цвет вершины 3 и 4. Но &quot;&lt;i&gt;жадный&lt;/i&gt;&quot; алгоритм, основываясь на порядковой очередности вершин(применив, например &lt;a href=&quot;http://py-algorithm.blogspot.com/2011/06/python.html&quot;&gt;структуру Вирта&lt;/a&gt;, можно попытаться исправить это), закрасит в красный цвет вершины 1 и 2, для закраски остальных вершин потребуются еще два цвета. &lt;br /&gt;
&lt;br /&gt;
Применим описанный алгоритм для закраски вершин графа нашей задачи (рис.1.2), при этом первой закрасим вершину АВ в синий цвет. Также можно закрасить в синий цвет вершины AC, AD и ВА, поскольку никакие из этих четырех вершин не имеют общих ребер. Вершину ВС нельзя закрасить в этот цвет, так как существует ребро между вершинами АВ и ВС. По этой же причине мы не можем закрасить в синий цвет вершины BD, DA и DB — все они имеют хотя бы по одному ребру, связывающему их с уже закрашенными в синий цвет вершинами. И так, продолжая перебор, закрашиваем все возможные вершины. Теперь применим второй цвет, например красный и повторим всё заново.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; margin-right: 1em; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihUbKV8Wepo80AooImZ-IKwmKrwHpilKrGlhNNQY8Tf7IrfmESTBbEn9F-fCldMhFl70d7fJMcJINhq0d_J9EsCBj1LLVBG8vt0sfDNK2zp42nmzOMaNW8U-YtNRT8fb7AW17bXkU7/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;67&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihUbKV8Wepo80AooImZ-IKwmKrwHpilKrGlhNNQY8Tf7IrfmESTBbEn9F-fCldMhFl70d7fJMcJINhq0d_J9EsCBj1LLVBG8vt0sfDNK2zp42nmzOMaNW8U-YtNRT8fb7AW17bXkU7/s320/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Таблица 1.2. Раскраска графа, представленного на рис. 1.2&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Назначенные вершинам цвета приведены в табл. 1.2. В этой таблице &quot;дополнительные&quot; повороты совместимы с соответствующими поворотами из столбца &quot;Повороты&quot;, хотя алгоритмом они окрашены в разные цвета. При задании режимов работы светофоров, основанных на одном из цветов раскраски, вполне безопасно вклю&lt;span id=&quot;goog_1952688512&quot;&gt;&lt;/span&gt;&lt;span id=&quot;goog_1952688513&quot;&gt;&lt;/span&gt;чить в эти режимы&lt;br /&gt;
и дополнительные повороты.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;
&lt;i&gt;Можно использовать результаты из общей теории графов для оценки качества полученного решения. В теории графов k-кликой называется множество из k вершин, в котором каждая пара вершин соединена ребром. Очевидно, что для закраски k-клики необходимо k цветов, поскольку в клике никакие две вершины не могут иметь одинаковый цвет.&lt;/i&gt;&lt;/blockquote&gt;
&lt;br /&gt;
B графе рис. 1.2 множество из четырех вершин AC, DA, BD и ЕВ является 4-кликой.&lt;br /&gt;
Поэтому,&amp;nbsp; не существует раскраски этого графа тремя и менее цветами, и,&lt;br /&gt;
следовательно, (решение, представленное в табл. 1.2 является оптимальным в том&lt;br /&gt;
смысле, что использует минимально возможное количество цветов. В терминах исходной задачи это означает, что для управления перекрестком, показанным на рис; 1.1, необходимо не менее четырех режимов работы светофора.&lt;br /&gt;
&lt;br /&gt;
Теперь привожу реализацию алгоритма, результат которого полностью совпадает с таблицей 1.2! 
&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;     # ab ac ad ba bc bd da db dc ea eb ec ed
N =  [[0,0,0,0,1,1,1,0,0,1,0,0,0],# ab
     [0,0,0,0,0,1,1,1,0,1,1,0,0], # ac
     [0,0,0,0,0,0,0,0,0,1,1,1,0], # ad
     [0,0,0,0,0,0,0,0,0,0,0,0,0], # ba
     [1,0,0,0,0,0,0,1,0,0,1,0,0], # bc
     [1,1,0,0,0,0,1,0,0,0,1,1,0], # bd
     [1,1,0,0,0,1,0,0,0,0,1,1,0], # da
     [0,1,0,0,1,0,0,0,0,0,0,1,0], # db
     [0,0,0,0,0,0,0,0,0,0,0,0,0], # dc
     [1,1,1,0,0,0,0,0,0,0,0,0,0], # ea
     [0,1,1,0,1,1,1,0,0,0,0,0,0], # eb
     [0,0,1,0,0,1,1,1,0,0,0,0,0], # ec
     [0,0,0,0,0,0,0,0,0,0,0,0,0]] # ed

#раскраска графа
def graphColoring():
    colored=[[]]
    color=0#№ цвета
    stack=[]#покрашенные узлы
    num2=num1=-1
#функция проверки возможности покраски в используемый сейчас цвет
    def loop(num):
        for t in colored[color]:
            if N[t][num]==1:
                return False
        return True
    
    for a in N:
        num1+=1
        if num1 not in stack:#просматриваем только те, которые еще не покрашены
            if not loop(num1):#значит применяем новый цвет
                colored.append([])
                color+=1
                stack.append(num1)
                colored[color].append(num1)
            num2=num1
            for b in a[num1:]:
                if b==0 and num2 not in stack and loop(num2):
                    stack.append(num2)
                    colored[color].append(num2)  
                num2+=1
    return colored
&lt;/pre&gt;
Подставьте теперь новый граф, на примере которого объяснялась жадность алгоритма и вы увидите доказательство тому.&lt;br /&gt;
&lt;br /&gt;
Думая, по дороге на работу, над тем, как избавиться от жадности алгоритма, я пришёл к следующей идее. А что если нам проходиться начиная с узла максимальной мощности(больше всего связей), окрашивать его и переходить к соседу, так же с макс. мощностью, окрашивая в другой цвет и проверяя в стеке цвета(если их уже окрасили) других своих соседей. Реализацию данной идее вы можите лицезреть в самом низу, под названием&amp;nbsp;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace; white-space: pre;&quot;&gt;VirtGraphColoring2(рекурсивная реализация)&lt;/span&gt;. Потом я подумал, а почему бы не разработать теорию максимезации энтропии(мощности) узлов графа. Эта идея была навеяна прошлым алгоритмом и стратегическими играми, ну знаете, когда от склада с оружием зависят разные точки и разрушив его мы избавляемся, фактически, и от них. И я не стал следовать к соседу с макс. мощностью, а просто прошёлся по узлам в порядке убывания их мощностей, раскрашивая в разные цвета. Радует, что пока что я не нашёл такого графа, который бы они раскрасили не оптимально))) &lt;span class=&quot;Apple-style-span&quot; style=&quot;color: red;&quot;&gt;Просьба, подкинуть!))&lt;/span&gt;&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;Edges = {&#39;1&#39;:[&#39;8&#39;, &#39;5&#39;, &#39;6&#39;], &#39;2&#39;:[&#39;6&#39;,&#39;7&#39;, &#39;9&#39;], &#39;3&#39;:[&#39;7&#39;, &#39;10&#39;, &#39;5&#39;], &#39;4&#39;:[&#39;8&#39;,&#39;10&#39;, &#39;9&#39;], &#39;9&#39;:[&#39;4&#39;,&#39;5&#39;, &#39;2&#39;], &#39;10&#39;:[&#39;3&#39;, &#39;4&#39;, &#39;6&#39;], &#39;5&#39;:[&#39;1&#39;, &#39;9&#39;, &#39;3&#39;], &#39;6&#39;:[&#39;1&#39;, &#39;2&#39;, &#39;10&#39;], &#39;7&#39;:[&#39;8&#39;, &#39;2&#39;, &#39;3&#39;], &#39;8&#39;:[&#39;7&#39;, &#39;1&#39;, &#39;4&#39;]}

#функция раскраски в порядке мощностей узлов
def VirtGraphColoring(Edges):
    result={}
    colors=[0]
  
    def SortEdges():
        sort={}
        for key in Edges:
            sort[key]=len(Edges[key])
        sort2=sorted(sort.iteritems(), key=lambda (k,v):(v,k), reverse=True)
        return sort2
    
    def colorize():
        def removeColor():
            for color in colors:
                if color not in stackColor: return color
            color=colors[-1]+1
            colors.append(color)
            return color
    
        for key in sort:
            stackColor=[]
            for key2 in Edges[key[0]]:
                if key2 in result:stackColor.append(result[key2])
            color=removeColor()
            result[key[0]]=color
        return result
    
    sort=SortEdges()
    return colorize()

print VirtGraphColoring(Edges)&lt;/pre&gt;
&lt;pre class=&quot;brush: python&quot;&gt;#рекурсивная функция раскраски в порядке мощностей соседей
def VirtGraphColoring2(Edges):
    result={}# результат
    colors=[0]#стек использованных цветов
    sort1={}# ссловарь ключей с их мощностью(количеством соседей)
  
    def SortEdges(): # сортируем словарь
        for key in Edges:
            sort1[key]=len(Edges[key])
        sort2=sorted(sort1.iteritems(), key=lambda (k,v):(v,k), reverse=True)
        return sort2 # список упорядоченных по мощности кортежей вида (ключ, мощность)
    
    def colorize(key):
        def removeColor(): #возвращает нужный цвет 
            for color in colors:
                if color not in stackColor: return color #если можне выбрать цвет, используемый ранее
            color=colors[-1]+1 # нет, тогда новый цвет
            colors.append(color) # добавляем его в коллекцию
            return color
        
        stackColor=[]
        maxi=-1
        maxkey=None
        for key2 in Edges[key]:
            if key2 not in result and sort1[key2]&amp;gt;maxi: 
                maxi=sort1[key2]
                maxkey=key2
            if key2 in result:stackColor.append(result[key2])
        color=removeColor()
        result[key]=color
        sort.remove((key,sort1[key]))
        if maxkey != None: colorize(maxkey)
        elif len(sort)&amp;gt;0: colorize(sort[0][0])

    sort=SortEdges()
    colorize(sort[0][0])   
    return result   &lt;/pre&gt;
Тут обнаружил, что задача раскраски графа, это решение судоку)) Вот так игры и создаются))&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/4235830437491480073/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2011/09/blog-post_14.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/4235830437491480073'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/4235830437491480073'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2011/09/blog-post_14.html' title='Раскраска графа'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVEBM_jQcfFeGDsJN55mD6SxLYHNscgDiKL67sXn_jHWMvRETb2FMr0bQOb1VFL8spFYQ0UfKGYb_23vn21Nb_7iKEd0qYpPwVhE593rM5PdNWTi37ryroAFk2FB9j-325YwpdCkfy/s72-c/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.png" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-2429330585542814667</id><published>2011-09-03T00:14:00.000-07:00</published><updated>2011-10-10T06:32:29.719-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Графы"/><category scheme="http://www.blogger.com/atom/ns#" term="Сортировки"/><title type='text'>Топологическая сортировка</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;style type=&quot;text/css&quot;&gt;
   TABLE { 
    border: 4px double black; /* Рамка вокруг таблицы */
    border-collapse: collapse; /* Отображать только одинарные линии */
   }
   TH { 
    text-align: left; /* Выравнивание по левому краю */
    border: 1px solid black; /* Граница вокруг ячеек */
   }
   TD { 
    border: 1px solid black; /* Граница вокруг ячеек */
   }
  
&lt;/style&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://habrastorage.org/storage/habraeffect/b3/d1/b3d112675c0e83b9d953699c3fe4674f.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;200&quot; src=&quot;http://habrastorage.org/storage/habraeffect/b3/d1/b3d112675c0e83b9d953699c3fe4674f.png&quot; width=&quot;155&quot; /&gt;&lt;/a&gt;&amp;nbsp;&lt;/div&gt;
&lt;br /&gt;
Под топологической сортировкой понимается сортировка элементов, для  которых определен частичный порядок, т.е. упорядочивание задано не для  всех, а только для некоторых пар элементов.&lt;br /&gt;
&lt;i&gt;Задача топологической сортировки&lt;/i&gt; графа состоит в следующем:  указать такой линейный порядок на его вершинах, чтобы любое ребро вело  от вершины с меньшим номером к вершине с большим номером. Очевидно, что  &lt;b&gt;если в графе есть циклы&lt;/b&gt;, то такого &lt;b&gt;порядка&lt;/b&gt; &lt;b&gt;не существует&lt;/b&gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;&lt;span style=&quot;color: red; font-size: xx-small;&quot;&gt;*-Нравится статья? Кликни по рекламе! :)&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;h2&gt;

Существует несколько способов топологической сортировки — из наиболее известных:&lt;br /&gt;
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Алгоритм Демукрона&lt;/li&gt;
&lt;li&gt;Метод сортировки для представления графа в виде нескольких уровней&lt;/li&gt;
&lt;li&gt;Метод топологической сортировки с помощью обхода в глубину&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;

&lt;span class=&quot;mw-headline&quot; id=&quot;.D0.90.D0.BB.D0.B3.D0.BE.D1.80.D0.B8.D1.82.D0.BC&quot;&gt;Алгоритм &lt;/span&gt;с помощью обхода в глубину&lt;/h2&gt;
&lt;h4&gt;

Суть алгоритма&lt;/h4&gt;
&lt;i&gt;Поиск в глубину&lt;/i&gt; или &lt;i&gt;обход в глубину&lt;/i&gt; (англ. &lt;i&gt;Depth-first search&lt;/i&gt;, сокращенно &lt;i&gt;DFS&lt;/i&gt;)  — один из методов обхода графа. Алгоритм поиска описывается следующим  образом: для каждой не пройденной вершины необходимо найти все не  пройденные смежные вершины и повторить поиск для них. &lt;br /&gt;
Запускаем обход в глубину, и когда вершина обработана, заносим ее в  стек. По окончании обхода в глубину вершины достаются из стека. Новые  номера присваиваются в порядке вытаскивания из стека.&lt;br /&gt;
&lt;i&gt;Цвет:&lt;/i&gt; во время обхода в глубину используется 3 цвета. Изначально  все вершины белые. Когда вершина обнаружена, красим ее в серый цвет.  Когда просмотрен список всех смежных с ней вершин, красим ее в черный  цвет.&lt;br /&gt;
Думаю будет проще рассмотреть данный алгоритм на примере:&lt;br /&gt;
&lt;br /&gt;
Имеем бесконтурный ориентированный граф.&lt;br /&gt;
Изначально все вершины белые, а стек пуст.&lt;br /&gt;
Начнем обход в глубину с вершины номер 1.&lt;br /&gt;
&lt;img alt=&quot;image&quot; src=&quot;http://img.picsa.ru/pictures/0/000/050/192/50192.PNG&quot; /&gt;&lt;br /&gt;
↑ Переходим к вершине номер 1. Красим ее в серый цвет.&lt;br /&gt;
&lt;img alt=&quot;image&quot; src=&quot;http://img.picsa.ru/pictures/0/000/050/193/50193.PNG&quot; /&gt;&lt;br /&gt;
↑ Существует ребро из вершины номер 1 в вершину номер 4. Переходим к вершине номер 4 и красим ее в серый цвет.&lt;br /&gt;
&lt;img alt=&quot;image&quot; src=&quot;http://img.picsa.ru/pictures/0/000/050/195/50195.PNG&quot; /&gt;&lt;br /&gt;
↑ Существует ребро из вершины номер 4 в вершину номер 2. Переходим к вершине номер 2 и красим ее в серый цвет.&lt;br /&gt;
&lt;img alt=&quot;image&quot; src=&quot;http://img.picsa.ru/pictures/0/000/050/194/50194.PNG&quot; /&gt;&lt;br /&gt;
↑ Из вершины номер 2 нет рёбер, идущих не в черные вершины. Возвращаемся  к вершине номер 4. Красим вершину номер 2 в черный цвет и кладем ее в  стек.&lt;br /&gt;
&lt;img alt=&quot;image&quot; src=&quot;http://img.picsa.ru/pictures/0/000/050/196/50196.PNG&quot; /&gt;&lt;br /&gt;
↑ Существует ребро из вершины номер 4 в вершину номер 3. Переходим к вершине номер 3 и красим ее в серый цвет.&lt;br /&gt;
&lt;img alt=&quot;image&quot; src=&quot;http://img.picsa.ru/pictures/0/000/050/197/50197.PNG&quot; /&gt;&lt;br /&gt;
↑ Из вершины номер 3 нет рёбер, идущих не в черные вершины. Возвращаемся  к вершине номер 4. Красим вершину номер 3 в черный цвет и кладем ее в  стек.&lt;br /&gt;
&lt;img alt=&quot;image&quot; src=&quot;http://img.picsa.ru/pictures/0/000/050/198/50198.PNG&quot; /&gt;&lt;br /&gt;
↑ Из вершины номер 4 нет рёбер, идущих не в черные вершины. Возвращаемся  к вершине номер 1. Красим вершину номер 4 в черный цвет и кладем ее в  стек.&lt;br /&gt;
&lt;img alt=&quot;image&quot; src=&quot;http://img.picsa.ru/pictures/0/000/050/199/50199.PNG&quot; /&gt;&lt;br /&gt;
↑ Из вершины номер 1 нет рёбер, идущих не в черные вершины. Красим её в черный цвет и кладем в стек. Обход точек закончен.&lt;br /&gt;
&lt;img alt=&quot;image&quot; src=&quot;http://img.picsa.ru/pictures/0/000/050/200/50200.PNG&quot; /&gt;&lt;br /&gt;
↑ По очереди достаем все вершины из стека и присваиваем им номера 1, 2,  3, 4 соответсвенно. Алгоритм топологической сортировки завершен. Граф  отсортирован.&lt;br /&gt;
И всем бы это объяснение было хорошо, если бы не &lt;b&gt;одно НО:&lt;/b&gt;&lt;br /&gt;
Если мы начнем сортировку с 4-го элемента, то никогда не вернемся в 1-й, т.к. мы в нём еще не были, а из 4-го в 1-й стрелочки не идет) Эта проблема полностью ложится на внутреннюю реализацию алгоритма. Я ввел переменную path=[] дабы отслеживать путь перемещения по графу. Т.е. при переходе к новому эл-ту я ддобавляю его в path, а при возвращении - удаляю. Таким образом, нам останется проверить в момент опустения path все ли эл-ты мы прошли и если нет, то запустить алгоритм для любой из еще не просмотренных элементов.&lt;br /&gt;
Я использовал здесь матрицы смежности, т.к. считаю, что разрабатывать алгоритм проще, начиная именно с такого представления графа, а уже после вводить необходимые структуры данных.&lt;br /&gt;
Например в данной реализации, я делаю N&lt;sup&gt;2&lt;/sup&gt; проверок связи узлов, в то время, как введя, например, связный список, для точной связи элементов, можно избавиться от if вообще и останется N конкретных действий.&lt;br /&gt;
&lt;div style=&quot;color: red;&quot;&gt;
&lt;b&gt;Важно!&lt;/b&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;br /&gt;
Циклы в графе есть тогда и только тогда, когда при обходе в глубину мы &#39;уткнемся&#39; в свой &#39;серый хвост&#39;.&lt;/li&gt;
&lt;/ol&gt;
Ну а вот вам моя ркурсивная реализация данного чуда!)&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;roofs=[&#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39;, &#39;t&#39;]
matrix = {(&#39;a&#39;, &#39;c&#39;):1, (&#39;c&#39;, &#39;b&#39;):1, (&#39;d&#39;, &#39;b&#39;):1, (&#39;d&#39;, &#39;c&#39;):1, (&#39;d&#39;, &#39;t&#39;):1}
#топологическая сортировка поиском в глубину
def topologicSortDFS(v, roof, firstNode=0):
    path=dict()#для разделения несвязных элементов графа
    result=[]#стек результата
    length=len(roof)
    global col
    col=0
    def topologicSort(v, roof, firstNode=0):
        global col
        path[roof[firstNode]]=1
        col+=1
        for i in range(length):
            if roof[i] not in result and v.get((roof[firstNode],roof[i]),0)==1:
                if path.get(roof[i],0)==1:
                    print &quot;!!!имеется цикл!!!&quot;
                    exit()
                topologicSort(v,roof,i)
            if i==length-1:
                result.append(roof[firstNode])
                col-=1
                if col==0 and len(result)!=length:#для отслеживания несвязанных участков
                    for x in roof:
                        if x not in result:topologicSort(v,roof, roof.index(x))
                return result#номер для занесения в стек
    return topologicSort(v, roof, firstNode)
&lt;/pre&gt;
&lt;br /&gt;
Я ничего не раскрашиваю тут, а использую фактически 2 стека, но увы эта моя реализация не смогла превзойти классическую функцию, которую я привожу ниже.&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;#Color — массив, в котором хранятся цвета вершин (0 — белый, 1 — серый, 2 — черный).
#Edges — массив списков смежных вершин.
#Numbers — массив, в котором сохраняются новые номера вершин.
#Stack — стек, в котором складываются вершины после их обработки.
#Cycle — принимает значение true, если в графе найден цикл.
Edges = {&#39;a&#39;:[&#39;c&#39;], &#39;c&#39;:[&#39;b&#39;], &#39;d&#39;:[&#39;c&#39;, &#39;b&#39;, &#39;t&#39;], &#39;b&#39;:[], &#39;t&#39;:[]}
def topologicSortDFS2(Edges):
    Stack=[]
    Color=dict()
    for i in Edges.keys():
        Color[i]=0
    def topological_sort():
        def dfs(v):
#Если вершина серая, то мы обнаружили цикл. 
#Заканчиваем поиск в глубину.
            if Color[v] == 1: return True
            if Color[v] == 2: return False#Если вершина черная, то заканчиваем ее обработку.
            Color[v] = 1#Красим вершину в серый цвет.
#Обрабатываем список смежных с ней вершин.
            for i in range(len(Edges[v])-1):
                if dfs(Edges[v][i]): return True
            Stack.append(v)#Кладем вершину в стек.
            Color[v] = 2#Красим вершину в черный цвет.
            return False;
        
#Вызывается обход в глубину от всех вершин. 
#Заканчиваем работу алгоритма, если обнаружен цикл.
        for i in Edges.keys():
            Cycle = dfs(i)
            if Cycle: 
                print &quot;!!!имеется цикл!!!&quot;
                exit()
                
#Заносим в массив новые номера вершин.    
        Stack.reverse()
        return Stack
    return topological_sort()
&lt;/pre&gt;
Результаты тестов приведу в конце!)&lt;br /&gt;
&lt;h2&gt;

&lt;span class=&quot;mw-headline&quot; id=&quot;.D0.90.D0.BB.D0.B3.D0.BE.D1.80.D0.B8.D1.82.D0.BC&quot;&gt;Алгоритм представления графа в виде уровней&lt;/span&gt;&lt;/h2&gt;
Пусть дан бесконтурный ориентированный простой граф &lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;G&lt;/i&gt; = (&lt;i&gt;V&lt;/i&gt;,&lt;i&gt;E&lt;/i&gt;)&lt;/span&gt;.&lt;br /&gt;
Через &lt;img alt=&quot;A(v), v \in V&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/e/3/2/e32bc53ea0894b86d68f5508ac5fd848.png&quot; /&gt; обозначим множество вершин таких, что &lt;img alt=&quot;u \in A(v) \Leftrightarrow (u, v) \in E&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/b/d/9/bd9dc92b9eb74b8a2e996d78118c4128.png&quot; /&gt;.&lt;br /&gt;
То есть, &lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;A&lt;/i&gt;(&lt;i&gt;v&lt;/i&gt;)&lt;/span&gt; — множество всех вершин, из которых есть ребро в вершину &lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;v&lt;/i&gt;&lt;/span&gt;.&lt;br /&gt;
Пусть &lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;P&lt;/i&gt;&lt;/span&gt; — искомая последовательность вершин.&lt;br /&gt;
&lt;blockquote&gt;
&lt;pre&gt;&lt;b&gt;пока&lt;/b&gt; &lt;span class=&quot;texhtml&quot;&gt; | &lt;i&gt;P&lt;/i&gt; |  &amp;lt;  | &lt;i&gt;V&lt;/i&gt; | &lt;/span&gt;
  выбрать &lt;i&gt;любую&lt;/i&gt; вершину &lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;v&lt;/i&gt;&lt;/span&gt; такую, что &lt;img alt=&quot;A(v) = \{\varnothing\}&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/a/5/3/a5382161734a3bed2621c85584c25395.png&quot; /&gt; и &lt;img alt=&quot;v \notin P&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/9/5/4/9549b964129f560ca371991df8df401a.png&quot; /&gt;
  &lt;img alt=&quot;P \gets P, v&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/a/a/5/aa5b343d01955297515e085e45462a5d.png&quot; /&gt;
  удалить &lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;v&lt;/i&gt;&lt;/span&gt; из всех &lt;img alt=&quot;A(u), u \neq v&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/8/6/8/8687bf54b0c30f3dfb92e8b2b5058918.png&quot; /&gt;
&lt;/pre&gt;
&lt;/blockquote&gt;
Наличие хотя бы одного контура в графе приведёт к тому, что на определённой итерации цикла не удастся выбрать новую вершину &lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;v&lt;/i&gt;&lt;/span&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;

&lt;span class=&quot;mw-headline&quot; id=&quot;.D0.9F.D1.80.D0.B8.D0.BC.D0.B5.D1.80_.D1.80.D0.B0.D0.B1.D0.BE.D1.82.D1.8B_.D0.B0.D0.BB.D0.B3.D0.BE.D1.80.D0.B8.D1.82.D0.BC.D0.B0&quot;&gt;Пример работы алгоритма&lt;/span&gt;&lt;/h3&gt;
&lt;div class=&quot;floatleft&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;http://ru.wikipedia.org/wiki/%D0%A4%D0%B0%D0%B9%D0%BB:Tred-G.svg&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;Tred-G.svg&quot; height=&quot;240&quot; src=&quot;http://upload.wikimedia.org/wikipedia/commons/thumb/f/fe/Tred-G.svg/175px-Tred-G.svg.png&quot; width=&quot;175&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Пусть задан граф &lt;img alt=&quot;G = \Bigl ( \bigl \{a, b, c, d, e \bigr \}, \bigl \{(a, b), (a, c), (a, d), (a, e), (b, d), (c, d), (c, e), (d,e) \bigr \} \Bigr )&quot; class=&quot;tex&quot; height=&quot;24&quot; src=&quot;http://upload.wikimedia.org/math/e/e/b/eeb6bbb8c885188a4b2cbbc55b85c23b.png&quot; width=&quot;400&quot; /&gt;.&lt;br /&gt;
В таком случае алгоритм выполнится следующим образом:&lt;br /&gt;
&lt;table class=&quot;standard&quot;&gt;&lt;tbody&gt;
&lt;tr&gt; &lt;th&gt;шаг&lt;/th&gt; &lt;th&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;v&lt;/i&gt;&lt;/span&gt;&lt;/th&gt; &lt;th&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;A&lt;/i&gt;(&lt;i&gt;a&lt;/i&gt;)&lt;/span&gt;&lt;/th&gt; &lt;th&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;A&lt;/i&gt;(&lt;i&gt;b&lt;/i&gt;)&lt;/span&gt;&lt;/th&gt; &lt;th&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;A&lt;/i&gt;(&lt;i&gt;c&lt;/i&gt;)&lt;/span&gt;&lt;/th&gt; &lt;th&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;A&lt;/i&gt;(&lt;i&gt;d&lt;/i&gt;)&lt;/span&gt;&lt;/th&gt; &lt;th&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;A&lt;/i&gt;(&lt;i&gt;e&lt;/i&gt;)&lt;/span&gt;&lt;/th&gt; &lt;th&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;P&lt;/i&gt;&lt;/span&gt;&lt;/th&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;th&gt;0&lt;/th&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;-&lt;/span&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;a&lt;/i&gt;&lt;/span&gt;&lt;/td&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;a&lt;/i&gt;&lt;/span&gt;&lt;/td&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;a&lt;/i&gt;,&lt;i&gt;b&lt;/i&gt;,&lt;i&gt;c&lt;/i&gt;&lt;/span&gt;&lt;/td&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;a&lt;/i&gt;,&lt;i&gt;c&lt;/i&gt;,&lt;i&gt;d&lt;/i&gt;&lt;/span&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;th&gt;1&lt;/th&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;a&lt;/i&gt;&lt;/span&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;b&lt;/i&gt;,&lt;i&gt;c&lt;/i&gt;&lt;/span&gt;&lt;/td&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;c&lt;/i&gt;,&lt;i&gt;d&lt;/i&gt;&lt;/span&gt;&lt;/td&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;a&lt;/i&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;th&gt;2&lt;/th&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;c&lt;/i&gt;&lt;/span&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;b&lt;/i&gt;&lt;/span&gt;&lt;/td&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;d&lt;/i&gt;&lt;/span&gt;&lt;/td&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;a&lt;/i&gt;,&lt;i&gt;c&lt;/i&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;th&gt;3&lt;/th&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;b&lt;/i&gt;&lt;/span&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;d&lt;/i&gt;&lt;/span&gt;&lt;/td&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;a&lt;/i&gt;,&lt;i&gt;c&lt;/i&gt;,&lt;i&gt;b&lt;/i&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;th&gt;4&lt;/th&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;d&lt;/i&gt;&lt;/span&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;a&lt;/i&gt;,&lt;i&gt;c&lt;/i&gt;,&lt;i&gt;b&lt;/i&gt;,&lt;i&gt;d&lt;/i&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;th&gt;5&lt;/th&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;e&lt;/i&gt;&lt;/span&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;img alt=&quot;\varnothing&quot; class=&quot;tex&quot; src=&quot;http://upload.wikimedia.org/math/d/0/9/d096fc15d57854ec89d746709b02e52e.png&quot; /&gt;&lt;/td&gt; &lt;td&gt;&lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;a&lt;/i&gt;,&lt;i&gt;c&lt;/i&gt;,&lt;i&gt;b&lt;/i&gt;,&lt;i&gt;d&lt;/i&gt;,&lt;i&gt;e&lt;/i&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
На втором шаге вместо &lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;c&lt;/i&gt;&lt;/span&gt; может быть выбрана вершина &lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;b&lt;/i&gt;&lt;/span&gt;, поскольку порядок между &lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;b&lt;/i&gt;&lt;/span&gt; и &lt;span class=&quot;texhtml&quot;&gt;&lt;i&gt;c&lt;/i&gt;&lt;/span&gt; не задан.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим более подробно.&lt;br /&gt;
Каждую вершину можно охарактеризовать числом дуг, входящих в неё (&lt;b&gt;полустепень захода&lt;/b&gt;), и числом дуг, исходящих из неё к другим вершинам (&lt;b&gt;полустепень исхода&lt;/b&gt;).&lt;br /&gt;
Если у вершины нет ни одной &lt;b&gt;входящей&lt;/b&gt; дуги, вершина называется &lt;b&gt;источником&lt;/b&gt; сети.&lt;br /&gt;
Если у вершины нет ни одной &lt;b&gt;исходящей&lt;/b&gt; дуги, вершина называется &lt;b&gt;стоком&lt;/b&gt; сети.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;http://s47.radikal.ru/i116/0908/df/c4cd76401faa.png&quot; /&gt; &lt;br /&gt;
Сначала опишем, что же мы хотим от нашего алгоритма, а потом приведем код.&lt;br /&gt;
Итак, наша цель — создать сеть, состоящую из нескольких уровней.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;http://s13.radikal.ru/i186/0908/a6/2a4910b924e8.png&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
Из рисунка видно, что задачи внутри одного уровня зависят только от задач на младших уровнях, и независимы друг от друга.&lt;br /&gt;
В таком случае, для достижения цели нам сначала надо в любом порядке  выполнить все задачи уровня 0, потом, в любом порядке, задачи уровня 1, и  т.д., до уровня 3 (последнего).&lt;br /&gt;
&lt;br /&gt;
Для решения задачи, нам понадобится представление графа в виде матрицы  (ij элемент = 1, если есть дуга из вершины i в вершину j, и равен 0,  если дуги нет).&lt;br /&gt;
В строке под таблицей даны полустепени захода для всех вершин. Каждое  число отражает сумму единичек в соответствующем столбце матрицы.&lt;br /&gt;
&lt;br /&gt;
На первом шаге алгоритма мы выбираем все вершины с нулевой полустепенью  захода, заносим их в нулевой уровень и, мысленно, выкидываем из графа.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;http://s02.radikal.ru/i175/0908/6c/aea1b3761061.png&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
В результате, (мы больше не учитываем строки матрицы, соответствующие  обработанным вершинам) полустепени захода остальных вершин уменьшатся.&lt;br /&gt;
&lt;br /&gt;
Далее, проделываем тоже самое с &lt;b&gt;оставшимися&lt;/b&gt; вершинами, имеющими нулевую полустепень захода и помещаем их в первый уровень:&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;http://i057.radikal.ru/0908/e6/19702201a178.png&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
Последующие шаги выполняются аналогично!&lt;br /&gt;
&lt;br /&gt;
Приведем код реализации, за пример взяв прошлый граф.&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;#топологическая сортировка уровнями
class Graph:
    def __init__(self):
        self.nodes=[[0,0,0,0,0,0],
                    [1,0,0,1,0,0],
                    [0,1,0,1,0,0],
                    [0,0,0,0,0,0],
                    [0,0,0,1,0,0]
                    ];
        self.count=range(len(self.nodes))
        
    def GetInputNodesArray(self):
        array = []
        for i in self.count: 
            step=0
            for j in self.count:
                if self.nodes[i][j]==1:step+=1
            array.insert(i,step)
        return array;
    
    def TopologicSort(self):
        levels =[];
        workArray = self.GetInputNodesArray();
        completedCounter = 0;
        currentLevel = 0;
        while (completedCounter != len(self.nodes)):
            for i in self.count:
                if (workArray[i] == 0):
                    ind=0
                    #добавляем обработанную вершину
                    levels.insert(completedCounter,i);
                    for node in self.nodes:
                        if node[i]==1:
                            workArray[ind]-=1
                        ind+=1
        
                    workArray[i] = -1; # Помечаем вершину как обработанную
                    completedCounter+=1;
            currentLevel+=1;
        levels.reverse()
        return levels#осталось выбрать в обратном порядке
&lt;/pre&gt;
Данный метод, от 2-х предыдущих примеров отличает то, что используется больше памяти на входе, т.к. мы описываем связь каждого узла с каждым. В предыдущем же алгоритме мы хранили только связи с соседями! Насколько оправдано это, смотри в конце статьи в результатах тестов!)&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Топологическая сортировка графа в виде структуры Вирта. &lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Еще 1 пример сортировки уровнями, но в другой структуре.&lt;br /&gt;
О самой структуре Вирта, я писал раньше, в статье &lt;a href=&quot;http://py-algorithm.blogspot.com/2011/06/python.html&quot;&gt;&quot;Теория графов и деревьев для Python&quot;&lt;/a&gt;&lt;br /&gt;
Поэтому перейду сразу к описанию алгоритма.&lt;br /&gt;
Для данного графа Edges = {&#39;1&#39;:[&#39;2&#39;,&#39;4&#39;], &#39;2&#39;:[&#39;8&#39;], &#39;4&#39;:[&#39;8&#39;], &#39;5&#39;:[&#39;8&#39;], &#39;8&#39;:[]}&lt;br /&gt;
&lt;br /&gt;
&lt;div align=&quot;CENTER&quot;&gt;
&lt;img src=&quot;http://khpi-iip.mipk.kharkiv.edu/library/datastr/book_sod/kgsu/ris88_1.jpg&quot; /&gt;&lt;br /&gt;
&lt;span style=&quot;color: black;&quot;&gt;Рис.1. Структура Вирта&lt;/span&gt;&lt;/div&gt;
&amp;nbsp;Функция сортировки сначала производит внутреннюю оптимизацию, связывая узлы количество исходящих дуг в которых равно 0, чтобы сразу пройтись по ним, сократив несколько итераций поиска таких элементов.&lt;br /&gt;
После оптимизации, в нашем случае, структура видоизменится следующим образом:&lt;br /&gt;
&lt;br /&gt;
&lt;div align=&quot;CENTER&quot;&gt;
&lt;img src=&quot;http://khpi-iip.mipk.kharkiv.edu/library/datastr/book_sod/kgsu/ris88_2.jpg&quot; /&gt;&lt;br /&gt;
&lt;span style=&quot;color: black;&quot;&gt;Рис.2. Результат оптимизации&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def VirtTopSort():
    result=[]
    z=len(Edges)
    head=ceateVirtStructLeader(Edges) 
    #Оптимизация
    #Поиск ведущих с нулевым количеством предшественников.
    p=head
    head=None
    while p!=None:
        q=p
        p=p.Next
        if q.Count==0:
            q.Next=head
            head=q
              
    q = head
    while  q!=None:
            #счетчик z для подсчета ведущих узлов
            #он должен вновь стать равным нулю в конце работы программы
            #или имеем цикл!
            z-=1
            #Занести элемент в результат и исключить его.
            result.append(q.Key)
            t=q.Trail
            q=q.Next
            while  t!=None:
                # Уменьшить счетчик предшественников у всех его  
                # последователей в списке ведомых t; если какой- 
                #либо счетчик стал равен 0, то добавить этот    
                # элемент к списку ведущих q;                    
                # p - вспомогательная переменная, указывающая на 
                # ведущий узел, счетчик которого нужно уменьшить 
                # и проверить на равенство нулю.                  
                p=t.Id
                p.Count-=1
                if  p.Count==0: #Включение p в список ведущих.
                    p.Next = q;
                    q = p;
                t = t.Next;
    if z!=0:
        print &quot;цикл!!!&quot;
        exit()
    result.reverse()
    return result
&lt;/pre&gt;
&lt;br /&gt;
В зарубежном интернете нашел еще один алгоритм, решил привести его здесь, для полноты картины!&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Алгоритм R. E. Tarjan от 1972 года&lt;/b&gt;&lt;br /&gt;
Алгоритм является модификацией алгоритма с применением обхода в глубину&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;#Алгоритм R. E. Tarjan от 1972 года
def topological_sort(items, partial_order):

    def add_node(graph, node):
        &quot;&quot;&quot;Добавить узел в графе если он еще не существует.&quot;&quot;&quot;
        if not graph.has_key(node): 
            graph[node] = [0] # 0 = число дуг входящих в этот узел.

    def add_arc(graph, fromnode, tonode):
        &quot;&quot;&quot;Добавить дуги графа. 
        Можно создать несколько дуг. 
        Конечные узлы должны уже существовать.&quot;&quot;&quot;
        graph[fromnode].append(tonode)
        # Обновление количество входящих дуг в узле.
        graph[tonode][0] = graph[tonode][0] + 1
    
    # Шаг 1 - создание ориентированного графа с дугой b--&amp;gt;a для каждого входа
    # Паре (a, b).
    # Граф представлен словарём.Словарь содержит:
    # Пару item:list для каждого узла в графе. /item/ это значение узла
    # /list/ с первым пунктом является счетчиком входящих дуг, а
    # остальные направления исходящих дуг. Например:
    # {&#39;a&#39;:[0,&#39;b&#39;,&#39;c&#39;], &#39;b&#39;:[1], &#39;c&#39;:[1]} 
    # получим следующий граф: c &amp;lt;-- a --&amp;gt; b 
    graph = {}
    for v in items:
        add_node(graph, v)
    for a,b in partial_order:
        add_arc(graph, a, b)
    
    # Шаг 2 - найти все корни (узлы с нулевым входящих дуг).
    roots = [node for (node,nodeinfo) in graph.items() if nodeinfo[0] == 0]
    
    # Шаг 3 - неоднократно выделяют корень и удаляем его из графа.
    # Удаление узла может преобразовывать некоторые из прямых потомков узла в корни.
    # Всякий раз, когда это произойдет, мы добавляем новые корни в список корней
    sorted = []
    while len(roots) != 0:
        # Если длина (roots) всегда равна 1, когда мы сюда попали, это означает, что
        # вход описывает законченый порядок, и есть только
        # один возможный вывод.
        # Когда длина (roots)&amp;gt; 1, мы можем выбрать любой корень, чтобы отправить
        # на выход; эта свобода представляет несколько полной упорядоченности
        # Мы произвольно принимать один из
        # корней использованием pop(). Заметим, что для алгоритма, чтобы быть эффективным,
        # эта операция должна быть сделана за O(1) времени.
        root = roots.pop()
        sorted.append(root)
        for child in graph[root][1:]:
            graph[child][0] = graph[child][0] - 1
            if graph[child][0] == 0:
                roots.append(child)
        del graph[root]
    if len(graph.items()) != 0:
        # Существует цикл!
        print &quot;цикл!!!&quot;
        exit()
    return sorted

print topological_sort([&#39;a&#39;,&#39;b&#39;,&#39;c&#39;,&#39;d&#39;,&#39;t&#39;], [(&#39;t&#39;,&#39;d&#39;),(&#39;b&#39;,&#39;d&#39;),(&#39;c&#39;,&#39;d&#39;),(&#39;b&#39;,&#39;c&#39;),(&#39;c&#39;,&#39;a&#39;)])
&lt;/pre&gt;
&lt;br /&gt;
&lt;div class=&quot;ibm-container ibm-alt-header dw-container-sidebar&quot;&gt;
&lt;blockquote&gt;
&lt;b&gt;Примеры использования топологической сортировки&lt;/b&gt;&lt;/blockquote&gt;
&lt;div class=&quot;ibm-container-body&quot;&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;&lt;br /&gt;
Техническая задача разбивается на ряд подзадач, при этом выполнение  одних подзадач должно предшествовать выполнению других подзадач.  Топологическая сортировка означает выполнение подзадач в таком порядке,  чтобы перед началом выполнения каждой подзадачи все необходимые для  этого подзадачи были уже выполнены.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;br /&gt;
В программе некоторые процедуры могут вызывать другие процедуры.  Топологическая сортировка предполагает расположение описаний процедур в  таком порядке, чтобы вызываемые процедуры описывались раньше тех,  которые их вызывают. Сборка приложения &lt;img src=&quot;http://s54.radikal.ru/i143/0908/86/7f1619269286.png&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
Дуга, идущая из вершины «Код» в вершину «Результирующий файл» говорит о  том, что «Код» должен быть обработан прежде, чем будет получен  Result.exe&lt;br /&gt;
Перед тем, как вершина может быть обработана, следует обработать все вершины, ссылающиеся на неё.&lt;/li&gt;
&lt;li&gt;&lt;br /&gt;
При помощи топологической сортировки строится корректная  последовательность выполнения действий, всякое из которых может зависеть  от другого: последовательность прохождения учебных курсов студентами,  установки программ при помощи пакетного менеджера, сборки исходных текстов программ при помощи Makefile&#39;ов. &lt;/li&gt;
&lt;li&gt;&lt;br /&gt;
При распараллеливании алгоритмов, когда по некоторому описанию алгоритма  нужно составить граф зависимостей его операций и, отсортировав его  топологически, определить, какие из операций являются независимыми и  могут выполняться параллельно (одновременно).&lt;/li&gt;
&lt;li&gt;&lt;br /&gt;
Примером использования топологической сортировки может служить создание  карты сайта, где имеет место древовидная система разделов.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Результаты тестов&lt;/b&gt;&lt;br /&gt;
Тест проводился путем исполнения 10000 раз определенной функции в profile с использованием функции test.&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;br /&gt;
Мой самодельный алгоритм.&lt;br /&gt;
&lt;i&gt;profile.run(&#39;test(topologicSortDFS2, 10000, Edges)&#39;)&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;420005 function calls (380005 primitive calls) in 4.598 seconds&lt;/i&gt;&lt;br /&gt;
Я думаю улучшить его, разбивая на подграфы, но много ли это принесет, увидим позже.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;br /&gt;
Классический алгоритм поиска в глубину и раскраски.&lt;br /&gt;
&lt;i&gt;profile.run(&#39;test(topologicSortDFS, 10000, matrix, roofs)&#39;)&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;270005 function calls (250005 primitive calls) in 2.915 seconds&lt;/i&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;br /&gt;
Алгоритм разбиения уровнями, с представлением графа в виде матрицы смежности&lt;br /&gt;
&lt;i&gt;profile.run(&#39;test(gr.TopologicSort,10000)&#39;)&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;160005 function calls in 1.688 seconds&lt;/i&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;br /&gt;
С алгоритмом использующим структуру Вирта, Всё несколько интереснее.&lt;br /&gt;
&lt;i&gt;profile.run(&#39;test(VirtTopSort,10000)&#39;)&lt;/i&gt;&lt;br /&gt;
Скорость его выполнения&lt;br /&gt;
&lt;i&gt;780005 function calls (750005 primitive calls) in 8.322 seconds&lt;/i&gt;&lt;br /&gt;
из них &lt;i&gt;10000    1.227    0.000    6.676    0.001 __init__.py:150(ceateVirtStructLeader)&lt;/i&gt;&lt;br /&gt;
Уходит на создание самой структуры! Т.е. фактическое время исполнения метода около 1.5 сек, но использовать его нужно там, где используется данная структура сразу, а несоздается специально для данной функции!&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;br /&gt;
Ну и в заключение алгоритм R. E. Tarjan от 1972 года&lt;br /&gt;
&lt;i&gt;profile.run(&quot;test(topological_sort,10000,[&#39;a&#39;,&#39;b&#39;,&#39;c&#39;,&#39;d&#39;,&#39;t&#39;], [(&#39;t&#39;,&#39;d&#39;),(&#39;b&#39;,&#39;d&#39;),(&#39;c&#39;,&#39;d&#39;),(&#39;b&#39;,&#39;c&#39;),(&#39;c&#39;,&#39;a&#39;)])&quot;)&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;430005 function calls in 3.901 seconds&lt;/i&gt;&lt;br /&gt;
Хоть он и считается модифицированной версией алгоритма номер 2, но почему то он проиграл ему секунду! Может я просто нашел плохую его реализацию?&lt;br /&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
&lt;b&gt;Используемая литература:&lt;/b&gt;&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_03/index.html&quot;&gt;Работа со структурами данных в языках Си и Python: Часть 3. Классификация связных списков&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%A2%D0%BE%D0%BF%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&quot;&gt;Википедия&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://habrahabr.ru/blogs/algorithm/100953/&quot;&gt;Хабрахабр&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://habrahabr.ru/blogs/algorithm/66766/&quot;&gt;Хабрахабр2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://rain.ifmo.ru/cat/view.php/vis/graph-general/topological-sort-2007/algorithm&quot;&gt;Дискретная математика: алгоритмы&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.bitformation.com/art/python_toposort.html&quot;&gt;Use the algorithm by R. E. Tarjan from 1972&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/2429330585542814667/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2011/09/blog-post.html#comment-form' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/2429330585542814667'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/2429330585542814667'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2011/09/blog-post.html' title='Топологическая сортировка'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-3098150256472005164</id><published>2011-08-27T12:51:00.000-07:00</published><updated>2011-12-16T12:09:13.754-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Структуры данных"/><title type='text'>Связные списки</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://dic.academic.ru/pictures/wiki/files/83/Single_linked_list.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;86&quot; src=&quot;http://dic.academic.ru/pictures/wiki/files/83/Single_linked_list.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote&gt;
В информатике, &lt;b&gt;свя́зный спи́сок&lt;/b&gt;&amp;nbsp;— &lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85&quot; title=&quot;Структура данных&quot;&gt;структура данных&lt;/a&gt;, состоящая из &lt;a class=&quot;new&quot; href=&quot;http://ru.wikipedia.org/w/index.php?title=%D0%A3%D0%B7%D0%B5%D0%BB_%28%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0%29&amp;amp;action=edit&amp;amp;redlink=1&quot; title=&quot;Узел (информатика) (страница отсутствует)&quot;&gt;узлов&lt;/a&gt;, каждый из которых содержит как собственные &lt;a class=&quot;mw-redirect&quot; href=&quot;http://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%BB%D0%B5_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85_%28%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0%29&quot; title=&quot;Поле данных (информатика)&quot;&gt;данные&lt;/a&gt;, так и одну или две &lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%A1%D1%81%D1%8B%D0%BB%D0%BA%D0%B0_%28%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%29&quot; title=&quot;Ссылка (программирование)&quot;&gt;ссылки&lt;/a&gt; («связки») на следующий и/или предыдущий узел списка. Принципиальным преимуществом перед &lt;a class=&quot;mw-redirect&quot; href=&quot;http://ru.wikipedia.org/wiki/%D0%9C%D0%B0%D1%81%D1%81%D0%B8%D0%B2&quot; title=&quot;Массив&quot;&gt;массивом&lt;/a&gt;  является структурная гибкость: порядок элементов связного списка может  не совпадать с порядком расположения элементов данных в памяти  компьютера, а порядок обхода списка всегда явно задаётся его внутренними  связями.&lt;/blockquote&gt;
Мы с вами рассмотрим реализацию односвязного (однонаправленного) списка.&lt;br /&gt;
&lt;i&gt;&lt;span style=&quot;color: red; font-size: xx-small;&quot;&gt;&lt;b&gt;*-Нравится статья? Кликни по рекламе! :)&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;span style=&quot;font-size: xx-small;&quot;&gt;&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;i&gt;&lt;span style=&quot;font-size: xx-small;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/i&gt; &lt;br /&gt;
Коли уж я натолкнулся на прелестные статьи &lt;a class=&quot;dwauthor&quot; href=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_01/#author1&quot; rel=&quot;#authortip1&quot; title=&quot;&quot;&gt;Сергея Яковлева&lt;/a&gt;, на сайте IBM, которые люди так не заслужено оценили в 2 звезды, давайте обсудим их.&lt;br /&gt;
В конечном итоге мы получим реализацию данного рисунка&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_01/images/figure_01.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;26&quot; src=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_01/images/figure_01.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
В одной из статей Sython&#39;а (&lt;a href=&quot;http://py-algorithm.blogspot.com/2011/04/list.html&quot;&gt;Cвойство замыкания, на примере list&lt;/a&gt;) мы уже создавали похожую структуру, методами функционального программирования. Пришло время задействовать ООП!)&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span class=&quot;atitle&quot;&gt;История связных списков&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
Основной принцип связных списков крайне прост: эта структура данных  состоит из последовательности записей, в которой каждая запись хранит  помимо самих данных еще и ссылку на следующую запись в этой  последовательности. На рисунке 1 изображен связный список из трех  записей, каждая запись которого состоит из поля данных - целого числа и  ссылки на следующую запись.&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_03/images/figure_01.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;37&quot; src=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_03/images/figure_01.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;b&gt;Рисунок 1. Пример связного списка&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
У последней записи на рисунке отсутствует ссылка, но она есть и указывает на &lt;b&gt;NULL&lt;/b&gt;. На основе списков можно реализовать структуры данных, такие как стеки, очереди и ассоциативные массивы.&lt;br /&gt;
Ранее уже упоминалось, что в массиве все элементы расположены в  памяти по порядку, а в списке они в памяти никак не упорядочены. Более  того, элемент может быть добавлен в любую позицию в списке. Однако сама  операция по вставке элемента в список требует дополнительных ресурсов,  так как нужно последовательно просканировать список для поиска нужной  позиции.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span class=&quot;atitle&quot;&gt;Основные правила реализации связных списков&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
Список состоит из элементов, называемых узлами (&lt;b&gt;node&lt;/b&gt;). Первый узел списка называется «головным» (&lt;b&gt;head&lt;/b&gt;), а последний - «хвостовым» (&lt;b&gt;tail&lt;/b&gt;). На рисунке 2 изображен двойной связный список.&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_03/images/figure_02.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;31&quot; src=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_03/images/figure_02.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;b&gt;Рисунок 2. Двойной связный список&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
Каждый элемент состоит из 3-х полей, два из которых являются  указателями на предыдущий или следующий узел. Элемент может указывать и  более чем на два узла, и в этом случае список называется многосвязным.&lt;br /&gt;
Помимо упоминавшихся ранее стандартных массивов существуют еще  динамические массивы. Размер обычного массива является фиксированной  величиной, а в динамический массив можно добавлять или удалять из него  элементы. Если элемент добавляется в середину динамического массива, то  происходит перераспределение элементов, находящихся справа от него, так  как все элементы массива должны быть расположены в памяти строго по  порядку. Поэтому вставка элемента в динамический массив требует  дополнительных ресурсов, если элемент добавляется не в конец массива.  Преимущество связного списка в том, что не требуется перестраивать  последовательность узлов, независимо от того, в какую позицию списка  вставляется новый элемент. Недостаток связных списков – это  последовательный доступ (&lt;b&gt;sequential access&lt;/b&gt;) к элементам, тогда как для массивов время доступа постоянно и не зависит от размера - &lt;b&gt;random access&lt;/b&gt;.  Если приложению требуется быстрый поиск элемента по индексу, то в  данном случае списки не подходят, и лучше воспользоваться массивами.&lt;br /&gt;
Еще один негативный момент при использовании связных списков связан с  нерациональным использованием памяти. Если в узле хранится небольшая  порция данных, например, булевское значение, то список становится  неэффективными из-за того, что объем памяти, выделяемой под хранение  связей, превышает объем памяти, выделяемой под хранение «полезной  нагрузки».&lt;br /&gt;
&lt;br /&gt;
Связный список - это рекурсивная структура, так как узел всегда  содержит указатель на следующий узел. Это позволяет использовать простой  рекурсивный алгоритм для таких операций, как объединение двух списков  или изменение порядка элементов на обратный. У односвязных списков есть  важное преимущество: если к вершине такого списка добавляется новый  элемент, то старый список будет по прежнему доступен по ссылке на только  что добавленный узел. Этот прием называется &lt;b&gt;persistent data structure&lt;/b&gt;  (постоянное хранение данных). У двусвязных списков есть свои  преимущества, так как они позволяют выполнять итерацию в обоих  направлениях, в отличие от односвязных списков.&lt;br /&gt;
Если последний элемент будет указывать на первый элемент списка, то  такая структура называется циклическим замкнутым (или кольцевым (&lt;b&gt;circular&lt;/b&gt;)) списком. Кольцевые списки можно использовать для списка процессов, в которых применяется «карусельный» (&lt;b&gt;round-robin&lt;/b&gt;)  алгоритм. Для такого списка достаточно иметь один указатель, который  одновременно указывает и на конец, и на начало очереди. Кольцевой список  можно разбить на два кольцевых списка или, наоборот, объединить.&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_03/images/figure_03.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;51&quot; src=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_03/images/figure_03.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;b&gt;Рисунок 3. Кольцевой связный список&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Полезно почитать введение, данное в 1-й части цикла &lt;br /&gt;
&lt;a href=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_01/&quot;&gt;Работа со структурами данных в языках Си и Python: Часть 1.&lt;/a&gt; Самое главное, на мой взгляд, написано в конце статьи, а именно:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;
&lt;b&gt;Преимущества:&lt;/b&gt;&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Удаление элементов в таком списке более эффективно, нежели  удаление элементов из стандартного списка Python, который рассматривался  в предыдущем разделе. Так как этот элемент удаляется из середины  стандартного списка, то время, необходимое на эту операцию, будет  зависеть от нескольких факторов: размера списка, положения удаляемого  элемента относительно конца. Чем больше размер списка, тем медленнее  будет происходить данная операция. В данном случае со ссылочной  организацией списка удаление будет происходить одинаково быстро,  независимо  от размера списка и относительного положения элемента, так  как потребуется всего лишь перевести ссылку в предыдущем элементе на  следующий за удаляемым элемент.&lt;/li&gt;
&lt;li&gt;То же самое можно сказать и про вставку элементов - она выполняется так же эффективно, как и удаление.&lt;/li&gt;
&lt;li&gt;Объединение или разбиение 2-х списков будет выполняться быстрее, нежели в стандартном варианте.&lt;/li&gt;
&lt;li&gt;Преимуществом связных списков является и то, что элемент такого  списка может иметь произвольную структуру, и включать не одну, а сразу  несколько ссылок, что является отличительной особенностью деревьев.&lt;/li&gt;
&lt;/ol&gt;
&lt;b&gt;Недостатки:&lt;/b&gt;&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Требуется выделять дополнительную память на ссылки, которые сами по себе не несут никакой полезной  информации.&lt;/li&gt;
&lt;li&gt;Доступ к произвольному элементу для стандартного массива в Си и для  стандартного списка в Python есть величина постоянная и не зависящая от  величины массива. В случае со ссылочными списками время доступа будет  зависеть от величины списка, так как потребуется выполнить итерацию по  всему списку.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
И в той же статье, еще раз обратите внимание на всем известные, но не теряющие интереса особенности Python&#39;а в отношении ссылок! &lt;br /&gt;
&lt;br /&gt;
Итак, приступим к кодингу)&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;#класс Node для определения элемента списка
class Node:
    def __init__(self, value = None, next = None):
        self.value = value
        self.next = next
&lt;/pre&gt;
Для определения связного списка потребуется еще один класс – &lt;b&gt;LinkedList&lt;/b&gt;,  в конструкторе которого будут определяться первый и последний элементы  списка и его длина. Также в классе будут использоваться встроенный метод  &lt;b&gt;str&lt;/b&gt; для распечатки содержимого списка и метод &lt;b&gt;clear&lt;/b&gt; для очистки списка.&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;class LinkedList:
    def __init__(self):
        self.first = None
        self.last = None
        self.length = 0

    def __str__(self):
        if self.first != None:
            current = self.first
            out = &#39;LinkedList [\n&#39; +str(current.value) +&#39;\n&#39;
            while current.next != None:
                current = current.next
                out += str(current.value) + &#39;\n&#39;
            return out + &#39;]&#39;
        return &#39;LinkedList []&#39;

    def clear(self):
        self.__init__()
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Добавление элементов в конец списка. &lt;/b&gt;&lt;br /&gt;
Может я чего накрутил, но во первых я не понял, зачем была нужна секция &quot;elif&quot; и вообще я её немного упростил)&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def add(self, x):
        self.length+=1
        if self.first == None:
            #self.first и self.last будут указывать на одну область памяти
            self.last = self.first = Node(x, None)
        else:
            #здесь, уже на разные, т.к. произошло присваивание
            self.last.next = self.last = Node(x, None)
&lt;/pre&gt;
&lt;br /&gt;
Теперь мы можем добавить несколько эл-тов и даже распечатать наш список!)&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;L = LinkedList()
L.add(1)
L.add(2)
L.add(3)
print(L)
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;А не научиться ли нам вставлять эл-ты в начало списка?)&lt;/b&gt;&lt;br /&gt;
В реализации нужно учитывать два варианта: в первом случае список  пуст, а во втором создается новый узел, в конструктор которого в  качестве второго параметра передается головной элемент списка. Комментарии по коду, те же, что и в предыдущем листинге.&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def push(self, x):
            self.length+=1
            if self.first == None:
                self.last = self.first = Node(x,None)
            else:
                self.first = Node(x,self.first)
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Давайте усложним себе задачу и вставим новый элемент в место, куда хотим!)&lt;/b&gt;&lt;br /&gt;
Я посмел чуточку исправить код, чтобы он заработал, а так все как и там. Необходимо сначала проверить, что список не пуст, а затем, что  вставка не происходит на нулевую позицию. Если оба условия не  выполняются, то происходит итерация по списку до нужной позиции и  добавление элемента:&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def InsertNth(self,i,x):
        if self.first == None:
            self.last = self.first = Node(x, None)
            return
        if i == 0:
          self.first = Node(x,self.first)
          return
        curr=self.first
        count = 0
        while curr != None:
            count+=1
            if count == i:
              curr.next = Node(x,curr.next)
              if curr.next.next == None:
                self.last = curr.next
              break
            curr = curr.next
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Научились добавлять, пора всех их посчитать!)&lt;/b&gt;&lt;br /&gt;
Я не очень понял, зачем в статье для этого пишется отдельная функция, видимо, чтобы просто поиграть извилинами. Раз уж используем ООП, то просто при добавлении инкриментируем встроенную переменную length, а при удалении дикрементируем, ну или как там?) Что я собственно и сделаю, тогда длина списка всегда будет статична и не нужно будет бегать по списку для её нахождения, хотя это и увеличит добавление и удаление элементов на несколько процессор-итераций.)&amp;nbsp; Но все же приведу ту ф-цию! Для определения длины списка в используется функция &lt;b&gt;len&lt;/b&gt;, которая вначале проверяет, не является ли список пустым, а затем выполняет итерацию по элементам списка.&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def len(self):
        length =0
        if self.first != None:
            current = self.first
            while current.next != None:
                current = current.next
                length +=1
        return length+1#+1 для учета self.first
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Удаление головного элемента&lt;/b&gt;&lt;br /&gt;
В реализации потребуется проверить список на пустоту и объявить две локальных переменных: первая будет хранить текущий элемент, а вторая - предыдущий. Потом выполняется итерация по списку для поиска удаляемого элемента и проверка того, не является ли он последним в списке. Если удаляемый элемент является последним, то предыдущий узел становится последним, в противном случае предыдущий узел связывается со следующим узлом вместо текущего.&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def Del(self,i):
        if (self.first == None):
          return
        curr = self.first
        count = 0
        if i == 0:
          self.first = self.first.next
          return
        while curr != None:
            if count == i:
              if curr.next == None:
                self.last = curr
              old.next = curr.next 
              break
            old = curr  
            curr = curr.next
            count += 1
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Вставка элемента в отсортированный список&lt;/b&gt;&lt;br /&gt;
В данной реализации выполняется проверка списка на пустоту, а  затем выполняется итерация с помощью двух временных переменных, как и в прошлом  листинге.&lt;b&gt; &lt;/b&gt;&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def SortedInsert(self,x):
        if self.first == None:
          self.first = Node(x,self.last)
          return
        if self.first.value &amp;gt; x:
          self.first = Node(x,self.first)
          return
        curr = self.first
        while curr != None:
            if curr.value &amp;gt; x:
              old.next = Node(x,curr)
              return
            old = curr
            curr = curr.next       
        self.last = old.next = Node(x,None)
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span class=&quot;atitle&quot;&gt;Удаление повторяющихся значений&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&amp;nbsp;Сначала напишем данную функцию для общего случая. Она будет проходить по всему списку от начала, до конца, для каждого элемента. Это приблизительно N&lt;sup&gt;2&lt;/sup&gt;/2 проходов!&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def RemoveDuplicates(self):
        if (self.first == None):
            return
        old=curr = self.first
        while curr != None:
            if curr.next != None:
                if old.value == curr.next.value:
                    curr.next = curr.next.next
            else:
                old=curr = old.next
            curr=curr.next
&lt;/pre&gt;
&lt;br /&gt;
Но куда более оптимальнее проводить данную операция для уже отсортированного списка, т.к. это экономит нам много итераций по списку(т.к. не нужно проходить весь список). Если в ходе  итерации текущий элемент оказывается равным следующему за ним, то  текущий элемент удаляется.&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def RemoveSortedDuplicates(self):
        if (self.first == None):
            return
        curr = self.first
        while curr != None:
            _del = 0 
            if curr.next != None:
                if curr.value == curr.next.value:
                    curr.next = curr.next.next
                    _del = 1
            if _del == 0:
                curr = curr.next
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;&amp;nbsp;&lt;span class=&quot;atitle&quot;&gt;Копирование списков&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
Это последнее, что мы с вами реализуем!) Если в СИ в реализации данной ф-ии  используется три указателя: на первый элемент оригинального списка и на  первый и последний элементы скопированного списка и много кода, то в Python для копирования списков можно использовать стандартный модуль &lt;b&gt;copy&lt;/b&gt;, как показано ниже.&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;import copy
L2 = copy.deepcopy(L) // создание копии списка L
&lt;/pre&gt;
&lt;b&gt;&lt;span class=&quot;atitle&quot;&gt;Пузырьковая сортировка&lt;/span&gt;&lt;/b&gt;

&lt;pre class=&quot;brush: python&quot;&gt;def BubbleSort(self):
       a = Node(0,None)
       b = Node(0,None)
       c = Node(0,None)
       e = Node(0,None)
       tmp = Node(0,None)
       
       while(e != self.first.next) :
        c = a = self.first
        b = a.next

        while a != e:
          if a and b:
            if a.value &amp;gt; b.value:
              if a == self.first:
                tmp = b.next
                b.next = a
                a.next = tmp
                self.first = b
                c = b
              else:
                tmp = b.next
                b.next = a
                a.next = tmp
                c.next = b
                c = b
            else:
              c = a
              a = a.next
            b = a.next
            if b == e:
              e = a
          else:
              e = a&lt;/pre&gt;
По заявкам, добавляю ф-ию получения элемента, обращаться можно по индексу L[n]:
&lt;pre class=&quot;brush: python&quot;&gt;
    def __getitem__(self, key):#поддержка обращения по ключу
        length =0
        current=None
        if self.first != None:
            current = self.first
            while key!=length or current.next != None:
                current = current.next
                length +=1
            if key==length:current=current.value
        return current
&lt;/pre&gt;
&lt;b&gt;&lt;span class=&quot;atitle&quot;&gt;Тестирование производительности&lt;/span&gt;&lt;/b&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Было произведено сравение скоростей создания встроенного списка Python(путем list.append()) и созданного выше(list.add()) из 10000 элементов, производительность нашего связного списка ниже.&lt;i&gt;40004 function calls in 0.327 CPU seconds &lt;/i&gt;против&amp;nbsp;&lt;i&gt;30004 function calls in 0.182 CPU seconds&lt;/i&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;b&gt;Используемая литература:&lt;/b&gt;

&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_02/index.html&quot;&gt;Работа со структурами данных в языках Си и Python: Часть 2. Связные списки&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_03/index.html&quot;&gt;Работа со структурами данных в языках Си и Python: Часть 3. Классификация связных списков&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/3098150256472005164/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2011/08/blog-post.html#comment-form' title='Комментарии: 6'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/3098150256472005164'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/3098150256472005164'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2011/08/blog-post.html' title='Связные списки'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-9046209125889754504</id><published>2011-07-30T10:41:00.000-07:00</published><updated>2011-10-07T14:27:32.560-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Графы"/><title type='text'>Бинарные деревья</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_06/images/figure_01.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;122&quot; src=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_06/images/figure_01.jpg&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;b&gt;Бинарное дерево&lt;/b&gt; представляет собой структуру, в которой каждый узел (или вершина) имеет не более двух узлов-потомков и в точности одного родителя. Самый верхний узел дерева является единственным узлом без родителей; он называется корневым узлом. Бинарное дерево&lt;br /&gt;
с N узлами имеет не меньше [log&lt;sub&gt;2&lt;/sub&gt;N + 1] уровней (при максимально плотной упаковке узлов).&lt;br /&gt;
Если уровни дерева занумеровать, считая что корень лежит на уровне 1, то на уровне с номером К лежит 2&lt;sup&gt;К-1&lt;/sup&gt; узел. У полного бинарного дерева с j уровнями (занумерованными от 1 до j) все листья лежат на уровне с номером j, и у каждого узла на уровнях с первого по j — 1&lt;br /&gt;
в точности два непосредственных потомка. В полном бинарном дереве с j уровнями 2&lt;sup&gt;j&lt;/sup&gt; — 1 узел.&lt;br /&gt;
&lt;i&gt;&lt;span style=&quot;color: red; font-size: xx-small;&quot;&gt;&lt;b&gt;*-Нравится статья? Кликни по рекламе! :)&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Бинарные деревья поиска обычно применяются для реализации множеств и ассоциативных массивов. И применяются для быстрого поиска информации. Например в статье &lt;a href=&quot;http://py-algorithm.blogspot.com/2011/04/blog-post_2498.html&quot;&gt;Двоичный (бинарный) поиск элемента в массиве&lt;/a&gt; мы искали во встроенной в Python структуре данных, типа list, а могли реализовать бинарное дерево. Двоичные деревья, как и связные списки, являются рекурсивными структурами.&lt;br /&gt;
&lt;a href=&quot;http://www.blogger.com/post-create.g?blogID=2551258626199289542&quot; name=&quot;fig&quot;&gt;&lt;b&gt;Различные реализации одного и того же бинарного дерева&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_06/images/figure_02.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;302&quot; src=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_06/images/figure_02.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Существуют следующие разновидности бинарных деревьев:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;полное(расширенное) бинарное дерево - каждый узел, за исключением листьев, имеет по 2 дочерних узла;&lt;/li&gt;
&lt;li&gt;идеальное бинарное дерево - это полное бинарное дерево, в котором все листья находятся на одной высоте;&lt;/li&gt;
&lt;li&gt;сбалансированное бинарное дерево - это бинарное дерево, в котором  высота 2-х поддеревьев для каждого узла отличается не более чем на 1.  Глубина такого дерева вычисляется как двоичный логарифм log(n), где n -  общее число узлов;&lt;/li&gt;
&lt;li&gt;вырожденное дерево - дерево, в котором каждый узел имеет всего один дочерний узел, фактически это связный список;&lt;/li&gt;
&lt;li&gt;бинарное поисковое дерево (BST) - бинарное дерево, в котором для  каждого узла выполняется условие: все узлы в левом поддереве меньше, и  все узлы в правом поддереве больше данного узла.&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;&lt;a href=&quot;http://www.blogger.com/post-create.g?blogID=2551258626199289542&quot; name=&quot;N100D0&quot;&gt;&lt;span class=&quot;atitle&quot;&gt;Вычисление путей&lt;/span&gt;&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;
Путь - это расстояние от корня дерева  до какого либо узла. Если число листьев полного бинарного дерева обозначить как &lt;b&gt;S&lt;/b&gt;, а число остальных узлов обозначить как &lt;b&gt;N&lt;/b&gt;, то справедлива формула: &lt;br /&gt;
&lt;table border=&quot;0&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; summary=&quot;This table contains a code listing.&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td class=&quot;code-outline&quot;&gt;&lt;pre class=&quot;displaycode&quot;&gt;S = N +1
&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
Если путь от корневого узла до листа обозначить как внешний путь, а  путь от корневого узла до НЕлиста обозначить как внутренний путь, тогда  сумма всех внешних путей для дерева, изображенного на рисунке, примере полного дерева, ниже:&lt;br /&gt;
&lt;table border=&quot;0&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; summary=&quot;This table contains a code listing.&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td class=&quot;code-outline&quot;&gt;&lt;pre class=&quot;displaycode&quot;&gt;E=3+3+2+3+4+4+3+3=25,
&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
а сумма внутренних путей будет равна:&lt;br /&gt;
&lt;table border=&quot;0&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; summary=&quot;This table contains a code listing.&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td class=&quot;code-outline&quot;&gt;&lt;pre class=&quot;displaycode&quot;&gt;I=2+1+0+2+3+1+2=11.
&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
и тогда будет справедлива формула:&lt;br /&gt;
&lt;table border=&quot;0&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; summary=&quot;This table contains a code listing.&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td class=&quot;code-outline&quot;&gt;&lt;pre class=&quot;displaycode&quot;&gt;E=I+2n, где n - число узлов.&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;b&gt;&lt;a href=&quot;http://www.blogger.com/post-create.g?blogID=2551258626199289542&quot; name=&quot;fig&quot;&gt;&lt;b&gt;Пример расширенного дерева&lt;/b&gt;&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_06/images/figure_03.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;267&quot; src=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_06/images/figure_03.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Можно сформулировать следующие задачи:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;сконструировать бинарное дерево таким образом, чтобы сумма путей  была минимальной, так как это сокращает время вычислений для различных  алгоритмов.&lt;/li&gt;
&lt;li&gt;сконструировать полное расширенное бинарное дерево таким образом,  чтобы сумма произведений путей от корневого узла до листьев на значение  листового узла была минимальной. &lt;/li&gt;
&lt;/ol&gt;
Давид Хаффман (David Huffman) предложил алгоритм для решения этой  проблемы, в котором на каждом шаге выбираются и складываются два  наименьших листа, как показано в листинге 1, что приводит к дереву,  изображенному на рисунке ниже.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.blogger.com/post-create.g?blogID=2551258626199289542&quot; name=&quot;N1012C&quot;&gt;&lt;b&gt;Листинг 1. Пример алгоритма Хаффмана&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;
&lt;pre class=&quot;displaycode&quot;&gt;2 3 5 7 11 13 17 19 23 29 31 37 41
    5 5 7 11 13 17 19 23 29 31 37 41
     10 7 11 13 17 19 23 29 31 37 41
       17    24 17 19 23 29 31 37 41
             24 34 19 23 29 31 37 41
             24 34    42 29 31 37 41
                      42 53 65 37 41
                      42 53 65    78
                         95 65    78
                         95      143
                                 238
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Бинарное дерево, построенное по алгоритму Хаффмана&lt;/b&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_06/images/figure_04.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;300&quot; src=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_06/images/figure_04.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;&amp;nbsp;&lt;/b&gt; Более полную статью, по кодам Хаффмана читай в моей более ранней &lt;a href=&quot;http://py-algorithm.blogspot.com/2011/06/blog-post_18.html&quot;&gt;статье&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Реализация:&lt;br /&gt;
До этого, в своих статьях я показывал силу функционального программирования Python.&lt;br /&gt;
Теперь, пришло время, показать ООП в действии, создав новую структуру данных Tree, состоящую из других структур, типа Node.&lt;br /&gt;
Сразу скажу, что код взят с сайта IBM с минимальными изменениями и дополнениями. С моей точки зрения данный класс является недееспособным с точки зрения добавления элементов,по причине того, что мы сами должны строить дерево, помня структуру у себя в голове, а ведь мы можем и ошибиться. И позже я напишу так, как мне кажется верным, где добавление элемента является рекурсивным проходом по дереву и поиску подходящего места. А пока, разберем, что есть:&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;class node:
    def __init__(self, data = None, left = None, right = None):
        self.data   = data
        self.left   = left
        self.right  = right

    def __str__(self):
        return &#39;Node [&#39;+str(self.data)+&#39;]&#39;

#/* класс, описывающий само дерево */  
class Tree:
    def __init__(self):
        self.root = None #корень дерева

# /* функция для добавления узла в дерево */
    def newNode(self, data):
        return node(data,None,None)
&lt;/pre&gt;
Дальше, все функции расширяют класс Tree.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;a href=&quot;http://www.blogger.com/post-create.g?blogID=2551258626199289542&quot; name=&quot;N1021D&quot;&gt;&lt;span class=&quot;atitle&quot;&gt;Высота бинарного дерева&lt;/span&gt;&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;
Для определения высоты дерева потребуется пройти от корня сначала по  левому поддереву, потом по правому, сравнить две этих высоты и выбрать  максимальное значение. И не забыть к получившемуся значению прибавить  единицу (корневой элемент). Мы реализуем её в привычном уже нам рекурсивном виде.&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;# /* функция для вычисления высоты дерева */
    def height(self,node):
      if node==None:
          return 0
      else:
        lheight = self.height(node.left)
        rheight = self.height(node.right)
    
        if lheight &amp;gt; rheight:
            return(lheight+1)
        else:
          return(rheight+1)
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;&lt;a href=&quot;http://www.blogger.com/post-create.g?blogID=2551258626199289542&quot; name=&quot;N10230&quot;&gt;&lt;span class=&quot;atitle&quot;&gt;«Зеркальное» отражение бинарного дерева&lt;/span&gt;&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;
Когда два дерева являются зеркальным отражением друг друга, то  говорится, что они симметричны. Для получения «зеркальной» копии дерева сначала выполняется  проверка на наличие у корня дерева дочерних узлов, и если эти узлы есть,  то они меняются местами. Потом эти же действия рекурсивно повторяются  для левого и правого дочерних узлов. Если существует только один  дочерний узел, тогда можно переходить на один уровень ниже по дереву и  продолжать.&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;#    /* функция для зеркального отражения дерева */
    def mirrorTree(self, node):
      if  node.left and node.right:
        node.left,node.right=node.right,node.left
        self.mirrorTree(node.right)
        self.mirrorTree(node.left)
      else:
        if node.left==None and node.right:
            return self.mirrorTree(node.right)
        if node.right==None and node.left:
            return self.mirrorTree(node.left)
&lt;/pre&gt;
&lt;a href=&quot;http://www.blogger.com/goog_1167459913&quot;&gt;&lt;br /&gt;
&lt;/a&gt;&lt;br /&gt;
&lt;b&gt;&lt;a href=&quot;http://www.blogger.com/post-create.g?blogID=2551258626199289542&quot; name=&quot;N10243&quot;&gt;&lt;span class=&quot;atitle&quot;&gt;Проверка наличия узла в бинарном дереве&lt;/span&gt;&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;
Нужно только учесть, что данная функция не работает для зеркального отображения дерева!&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;#    /* функция для проверки наличия узла */
    def lookup(self, node, target):
        if node == None:return 0
        else:
            if target == node.data: return 1
            else:
                if target &amp;lt; node.data: return self.lookup(node.left, target)
                else: return self.lookup(node.right, target)
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Ширина бинарного дерева&lt;/b&gt;&lt;br /&gt;
Под шириной дерева понимается максимальное количество узлов, которые расположены на одной высоте. Чтобы определить ширину дерева, достаточно просто добавить счетчик в уже рассмотренный алгоритм для определения высоты дерева. &lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;# /* функция для вычисления ширины дерева */
    def getMaxWidth(self,root):
      maxWdth = 0
      i = 1
      width = 0 ;
      h = self.height(root)
      while( i&amp;lt; h):
        width =   self.getWidth(root, i)
        if(width &amp;gt; maxWdth):
            maxWdth  = width;
        i +=1    
      return maxWdth;

    def getWidth(self, root, level):
      if root == None:
        return 0
      if level == 1: 
        return 1
      elif level &amp;gt; 1:
          return self.getWidth(root.left, level-1) +  self.getWidth(root.right, level-1)
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Распечатка дерева:&lt;/b&gt;&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;# /* функция для распечатки элементов на определенном уровне дерева */
    def printGivenLevel(self, root, level):
      if root == None:
        return
      if level == 1:
        print (&quot;%d &quot; % root.data)
      elif level &amp;gt; 1:
          self.printGivenLevel(root.left, level-1);
          self.printGivenLevel(root.right, level-1);


# /* функция для распечатки дерева */
    def printLevelOrder(self, root):
      h = self.height(self.root)
      i=1
      while(i&amp;lt;=h):
        self.printGivenLevel(self.root, i)
        i +=1
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span class=&quot;atitle&quot;&gt;Сравнение бинарных деревьев&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;span class=&quot;atitle&quot;&gt;Вынесите её за пределы класса только) &lt;/span&gt;&lt;b&gt;&lt;span class=&quot;atitle&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def sameTree(a, b):
    if a==None and b==None: return 1
    elif a and b:
        return(
                a.data == b.data and
                sameTree(a.left, b.left) and
                sameTree(a.right, b.right)
                )
    return 0
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span class=&quot;atitle&quot;&gt;Количество узлов в бинарном дереве&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
Вычислить количество узлов в бинарном дереве также можно с помощью рекурсии.&lt;br /&gt;
Хотя с точки зрения производительности и принципов ООП, правильнее встроить счетчик в сам объект.&lt;br /&gt;
&lt;pre class=&quot;brush: python&quot;&gt;def size(node):
    if node==None:return 0;
    return(size(node.left) + 1 + size(node.right));
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Немножко о производительности&lt;/b&gt;&lt;br /&gt;
Я протестировал наш класс на поиск. К сожалению, данная его реализация проиграла бинарному поиску по списку, &lt;a href=&quot;http://py-algorithm.blogspot.com/2011/04/blog-post_2498.html&quot;&gt;описанному ранее&lt;/a&gt;. Я тестировал, запуская в 100000 цикле поиска элемента со значением 5 и результат нашего класса&lt;br /&gt;
&lt;i&gt;400003 function calls (100003 primitive calls) in 3.481 seconds&lt;/i&gt;&lt;br /&gt;
против&lt;br /&gt;
&lt;i&gt;200003 function calls in 1.791 seconds&lt;/i&gt;&lt;br /&gt;
Я считаю, что причина в рекурсивном исполнении данного метода + реализации на Python, а не Си)&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Вывод:&lt;/b&gt;&lt;br /&gt;
Организация данных с помощью бинарных деревьев  часто позволяет значительно сократить время поиска нужного элемента.  Поиск элемента в линейных структурах данных обычно осуществляется путем  последовательного перебора всех элементов, присутствующих в данной  структуре. Поиск по дереву не требует перебора всех элементов, поэтому  занимает значительно меньше времени. Максимальное число шагов при поиске  по дереву равно высоте данного дерева, т.е. количеству уровней в  иерархической структуре дерева.&lt;br /&gt;
&lt;i&gt;Вот и все, в заключение хочу сказать, что если какие то вопросы не раскрыты, не понятны или не оптимальны, просьба не стесняться и писать в комментариях!)&lt;/i&gt;&lt;br /&gt;
&lt;b&gt;Используемая литература:&lt;/b&gt;  &lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Дж. Макконнелл - Основы современных алгоритмов.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://habrahabr.ru/blogs/algorithm/65617/&quot;&gt;Структуры данных: бинарные деревья. Часть 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.ibm.com/developerworks/ru/library/l-data_structures_06/&quot;&gt;Работа со структурами данных в языках Си и Python: Часть 6. Двоичные деревья&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Может быть полезным &lt;a href=&quot;http://algolist.manual.ru/ds/walk.php&quot;&gt;Обходы бинарных деревьев&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/9046209125889754504/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2011/07/blog-post_30.html#comment-form' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/9046209125889754504'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/9046209125889754504'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2011/07/blog-post_30.html' title='Бинарные деревья'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2551258626199289542.post-8486665777715188302</id><published>2011-07-30T05:12:00.000-07:00</published><updated>2011-10-31T14:22:41.389-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="алгоритмы"/><title type='text'>Анализ алгоритма</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://seojam.ru/wp-content/uploads/2009/03/sherlock.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;200&quot; src=&quot;http://seojam.ru/wp-content/uploads/2009/03/sherlock.gif&quot; width=&quot;196&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;Что такое анализ?&lt;/b&gt;&lt;/div&gt;
Анализируя алгоритм, можно получить представление о том, сколько времени займет решение данной задачи при помощи данного алгоритма. Одну и ту же задачу можно решить с помощью различных алгоритмов. Анализ алгоритмов дает нам инструмент для выбора алгоритма.&lt;br /&gt;
Результат анализа алгоритмов — не формула для точного количества секунд или компьютерных циклов, которые потребует конкретный алгоритм. Из статьи &lt;a href=&quot;http://py-algorithm.blogspot.com/2011/04/blog-post_5358.html&quot;&gt;Порядок роста&lt;/a&gt; мы уже знаем, что разница между алгоритмом, который делает N + 5 операций, и тем, который делает N + 250 операций, становится незаметной, как только N становится очень большим.&lt;br /&gt;
&lt;i&gt;&lt;span style=&quot;color: red; font-size: xx-small;&quot;&gt;&lt;b&gt;*-Нравится статья? Кликни по рекламе! :)&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;b&gt;Что подсчитывать и что учитывать?&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;i&gt;Аддитивные операции&lt;/i&gt;: сложение и вычитание.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;Мультипликативные операции&lt;/i&gt;: умножение, деление и взятие остатка по модулю.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;Особые&lt;/i&gt;: целочисленное умножение или деление на степень двойки сводятся к сдвигу, а он по скорости эквивалентен сложению.&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Классы входных данных&lt;/b&gt;&lt;br /&gt;
При анализе алгоритма выбор входных данных может существенно повлиять на его выполнение. Скажем, некоторые алгоритмы сортировки могут работать очень быстро, если входной список уже отсортирован, тогда как другие алгоритмы покажут весьма скромный результат на таком списке. А вот на случайном списке результат может оказаться противоположным. Поэтому не будем ограничиваться анализом поведения алгоритмов на одном входном наборе данных. Практически нужно искать такие данные, которые обеспечивают как самое быстрое, так и самое медленное выполнение алгоритма. Кроме того, полезно оценивать и среднюю эффективность алгоритма на всех возможных наборах данных.&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Наилучший случай&lt;/li&gt;
&lt;blockquote&gt;
Время выполнения алгоритма в наилучшем случае очень часто оказывается маленьким или просто постоянным, поэтому подобный анализ проводится редко.&lt;/blockquote&gt;
&lt;li&gt;Наихудший случай&lt;/li&gt;
&lt;blockquote&gt;
Анализ наихудшего случая чрезвычайно важен, поскольку он позволяет представить максимальное время работы алгоритма. При анализе наихудшего случая необходимо найти входные данные, на которых алгоритм будет выполнять больше всего работы.&lt;/blockquote&gt;
&lt;li&gt;Средний случай&lt;/li&gt;
&lt;blockquote&gt;
Анализ среднего случая является самым сложным, поскольку он требует учета множества разнообразных деталей. В основе анализа лежит определение различных групп, на которые следует разбить возможные входные наборы данных. На втором шаге определяется вероятность, с которой входной набор данных принадлежит каждой группе. На третьем шаге подсчитывается время работы алгоритма на данных из каждой группы. Время работы алгоритма на всех входных данных одной группы должно быть одинаковым, в противном случае группу следует подразбить. Среднее время работы вычисляется по формуле &lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiz9njPQFDVScrPwVax8PGPAhIVUhOmOy_vfoE1NCXDBRF-3HyBhfRpYm75Sva2W9Kiq2SXDbk62Z_X9PtE_7DysmlbqKVEDIdUg_b63bbCOXXaAjZWWlQZReF9AnffKXPGZTVkgmhE/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiz9njPQFDVScrPwVax8PGPAhIVUhOmOy_vfoE1NCXDBRF-3HyBhfRpYm75Sva2W9Kiq2SXDbk62Z_X9PtE_7DysmlbqKVEDIdUg_b63bbCOXXaAjZWWlQZReF9AnffKXPGZTVkgmhE/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
где через n обозначен размер входных данных, через m — число групп. через p&lt;sub&gt;i&lt;/sub&gt; — вероятность того, что входные данные принадлежат группе с номером i, а через t&lt;sub&gt;i&lt;/sub&gt;  — время, необходимое алгоритму для обработки данных из группы с номером i.&lt;/blockquote&gt;
&lt;/ul&gt;
В большинстве случаев мы будем предполагать, что вероятности попадания входных данных в каждую из групп одинаковы. Другими словами, если групп пять, то вероятность попасть в первую группу такая же, как вероятность попасть во вторую, и т.д., то есть вероятность&lt;br /&gt;
попасть в каждую группу равна 0.2. В этом случае среднее время работы можно либо оценить по предыдущей формуле, либо воспользоваться эквивалентной ей формулой&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7tvkDMJC8GnoRaYfW_perX2uL2OJ6rVJIIKxpnm5R0apyuB2WjmKD5nScHiRrTYQP62ukxhtFH7Cxu5U8Yh8Xd0a6s3wzhn5UFIx3czwybNyA9zC52-2z3o_9OO3l7WWPlTxsPvhJ/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7tvkDMJC8GnoRaYfW_perX2uL2OJ6rVJIIKxpnm5R0apyuB2WjmKD5nScHiRrTYQP62ukxhtFH7Cxu5U8Yh8Xd0a6s3wzhn5UFIx3czwybNyA9zC52-2z3o_9OO3l7WWPlTxsPvhJ/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;&amp;nbsp;Нижние границы. Дерево решений.&lt;/b&gt;&lt;br /&gt;
Алгоритм является &lt;i&gt;оптимальным&lt;/i&gt;, если любой любой другой алгоритм, решающий данную задачу, работает не быстрее данного. Как узнать оптимальность алгоритма? Для этого мы должны знать минимальное количество операций, необходимое для решения поставленной задачи, которое называется &lt;i&gt;нижней границей&lt;/i&gt;. Но для этого нам нужно изучать именно ЗАДАЧУ, а не конкретный алгоритм!&lt;br /&gt;
Как пример, рассмотрим анализ процесса сортировки списка из 3 чисел, воспользовавшись &lt;a href=&quot;http://py-algorithm.blogspot.com/2011/07/blog-post_30.html&quot;&gt;бинарным деревом&lt;/a&gt;. Такое дерево называется &lt;i&gt;деревом решений&lt;/i&gt;.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjllql0juvmr-4v5vHbvR5ccVzgx4e_v1r-Kvn79pnq_MROB59Qwmqeoo9xQHPOCAIsJuQ2UqzA3-_zl6G2cMWOsTHxx3I5P2F2WCkCynTdn57xOM4A684aWUq0zx9SqtqsDLW3bWLP/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;233&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjllql0juvmr-4v5vHbvR5ccVzgx4e_v1r-Kvn79pnq_MROB59Qwmqeoo9xQHPOCAIsJuQ2UqzA3-_zl6G2cMWOsTHxx3I5P2F2WCkCynTdn57xOM4A684aWUq0zx9SqtqsDLW3bWLP/s400/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Самый длинный путь в данном дереве соответствует наихудшему случаю и наоборот, кратчайший - наилучшему. Средний случай описывается частным от деления числа ребер в дереве на число листов.&lt;br /&gt;
Для перестановки&amp;nbsp; 2-х элементов мы имеем 1лист, для N эл-тов, по правилам комбинаторики, N! листов. Число листов&amp;nbsp; на уровне K равно 2&lt;sup&gt;k-1&lt;/sup&gt;, поэтому в нашем дереве решений буде L -уровней, где L - наименьшее целое число, для которого N!&lt;span class=&quot;st&quot;&gt; ≤ &lt;/span&gt;2&lt;sup&gt;L-1&lt;/sup&gt;. Логарифмируя, получим &lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiciorpIRWO4zzDSSxWgS7yRoep71cLO5sRJZqXHK6vNr8iG8RQ7Kh_CrH6GeIB5ZW7f41ihXblmk6j1gjwS6QAjkx_GPMJZUQQDDUUDc6J7CmmcPkNGeO6Pv-yuBmswZFOyHc_PvHn/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiciorpIRWO4zzDSSxWgS7yRoep71cLO5sRJZqXHK6vNr8iG8RQ7Kh_CrH6GeIB5ZW7f41ihXblmk6j1gjwS6QAjkx_GPMJZUQQDDUUDc6J7CmmcPkNGeO6Pv-yuBmswZFOyHc_PvHn/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrL3jQIediYGMnHs66n8cgZjOd13DDBfaQQ_YKk7xqh_eU35xbtP6qHU5dB7V3eFueidmJyzhT273hLFRzJPUPyc9keMlCf0SNyLuGUGPVQSKTW434cqTjmCilVMHqx6-0yOQeerKl/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrL3jQIediYGMnHs66n8cgZjOd13DDBfaQQ_YKk7xqh_eU35xbtP6qHU5dB7V3eFueidmJyzhT273hLFRzJPUPyc9keMlCf0SNyLuGUGPVQSKTW434cqTjmCilVMHqx6-0yOQeerKl/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkEKvCuF9i4tKVhuFEPlufdjxR3Ijjei3R88heTCUyJmV1m-NF9U8PWPNVONNKao9CgrbSeWdR8zv3Ew1aFkxTLlwSNa-W6qdfWEyZ5TxeF7UFXaHPFB8VFxyPynUxPDpKwkQg1iH4/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;61&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkEKvCuF9i4tKVhuFEPlufdjxR3Ijjei3R88heTCUyJmV1m-NF9U8PWPNVONNKao9CgrbSeWdR8zv3Ew1aFkxTLlwSNa-W6qdfWEyZ5TxeF7UFXaHPFB8VFxyPynUxPDpKwkQg1iH4/s400/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
В конечном итоге, получаем:&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoVVQPOmuL6Ecf7w22jOv-rVg8phSiolQrJDKb7pRULiDbvIJg7XYDGTa3Ao3HcpfAw0dxp6Ra0UeP9hREw7LesD4bfrxA-NexcMQl2v_ApjwDBxu6ioe9py0prMmmbGWMgzagoyV_/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoVVQPOmuL6Ecf7w22jOv-rVg8phSiolQrJDKb7pRULiDbvIJg7XYDGTa3Ao3HcpfAw0dxp6Ra0UeP9hREw7LesD4bfrxA-NexcMQl2v_ApjwDBxu6ioe9py0prMmmbGWMgzagoyV_/s1600/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Вот мы и узнали, что любой алгоритм сортировки, порядка О(NlgN) является наилучшим и его можно считать оптимальным. Более того, из этого исследования вытекает, что алгоритм, решающий задачу сортировки быстрее О(NlgN) операций, не может работать правильно!&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Используемая литература:&lt;/b&gt;&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Дж. Макконнелл - Основы современных алгоритмов.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://py-algorithm.blogspot.com/feeds/8486665777715188302/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://py-algorithm.blogspot.com/2011/07/blog-post.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/8486665777715188302'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2551258626199289542/posts/default/8486665777715188302'/><link rel='alternate' type='text/html' href='http://py-algorithm.blogspot.com/2011/07/blog-post.html' title='Анализ алгоритма'/><author><name>Pol_uha</name><uri>http://www.blogger.com/profile/17168330284605590391</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiz9njPQFDVScrPwVax8PGPAhIVUhOmOy_vfoE1NCXDBRF-3HyBhfRpYm75Sva2W9Kiq2SXDbk62Z_X9PtE_7DysmlbqKVEDIdUg_b63bbCOXXaAjZWWlQZReF9AnffKXPGZTVkgmhE/s72-c/%25D0%2591%25D0%25B5%25D0%25B7%25D1%258B%25D0%25BC%25D1%258F%25D0%25BD%25D0%25BD%25D1%258B%25D0%25B9.jpg" height="72" width="72"/><thr:total>0</thr:total></entry></feed>