<?xml version="1.0" encoding="UTF-8"?><!-- generator="wordpress.com" -->
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	>

<channel>
	<title>Блог &amp;laquo; WordPress.com Tag Feed</title>
	<link>http://wordpress.com/tag/Блог/</link>
	<description>Feed of posts on WordPress.com tagged "Блог"</description>
	<pubDate>Sat, 19 Jul 2008 09:29:13 +0000</pubDate>

	<generator>http://wordpress.com/tags/</generator>
	<language>en</language>

<item>
<title><![CDATA[Маленький юбілей]]></title>
<link>http://grandse.wordpress.com/?p=69</link>
<pubDate>Sun, 13 Jul 2008 21:42:35 +0000</pubDate>
<dc:creator>grandse</dc:creator>
<guid>http://grandse.wordpress.com/?p=69</guid>
<description><![CDATA[Першу замітку в цьому блозі було написано шість місяці]]></description>
<content:encoded><![CDATA[<p>Першу замітку в цьому блозі було написано шість місяців тому. А саме 14 січня. Тоді я написав аж цілих три "статті". Потім були ще записи, потім мовчання.. Потім багато "проривів" коли писалось по декілька заміток на день, і перерви в тиждень. Ось так набралось вже більше 40 заміток, деякі зовсім маленькі, а деякі в декілька тисяч слів, з ілюстраціями. Коли як..</p>
<p>Сподіваюсь, що надалі мої думки сюди будуть потрапляти 2-3 рази на тиждень і що вони будуть комусь цікавими та необхідними.</p>
<p>Цікаво, а чи має цей блог хочаб декілька постійних читачів, окрім його авора звісно :). Прошу хоча б декілька слів написати всіх, хто не вперше бічить цей блог, хто хоча б іноді відкриває його перевіряючи на предмет нових заміток, чи помістив його в свій рідер. Буду дуже вдячний за ваші слова, відгуки, поради. Дякую всім за увагу.</p>
]]></content:encoded>
</item>
<item>
<title><![CDATA[4-hour workweek Тимоти Ферриса]]></title>
<link>http://voeslav.wordpress.com/?p=9</link>
<pubDate>Sun, 08 Jun 2008 19:24:17 +0000</pubDate>
<dc:creator>Voeslav</dc:creator>
<guid>http://voeslav.wordpress.com/?p=9</guid>
<description><![CDATA[Тимоти Феррис:
«Мои ладони снова вспотели.
 
Софиты сле]]></description>
<content:encoded><![CDATA[<p>Тимоти Феррис:</p>
<p>«Мои ладони снова вспотели.<br />
 <br />
Софиты слепили глаза. Уставившись в паркет, чтобы не ослепнуть, я подумал о том, что возможно являюсь одним из лучших в мире, только никому пока об этом не известно. Моя партнерша Алисия переступила с ноги на ногу; мы стояли в одном ряду ещё с девятью парами, отобранными из всего 1 000 участников от 29 стран и четырех континентов. Это был последний день полуфинала <strong>Мирового Чемпионата по Танго</strong>, и это было нашим финалом, проходящим перед судьями, телевизионными камерами, и приветствующими толпами. Все другие пары в среднем тренировались по 15 лет. Для нас же это была кульминация пяти месяцев безостановочных шестичасовых тренировок, и, наконец, шоутайм.</p>
<p>Читать статью полностью: <a title="The 4 hour workweek, Timothy Ferriss" href="http://downshifter.in/Novorossiysk/2008/06/08/the_4-hour_workweek-anons/" target="_blank"><strong>Timothy Ferris, “</strong><strong>The 4 hour workweek</strong><strong>”</strong></a></p>
<p>Видео выступления Тимоти Ферриса и его партнёрши Алисии Монти:</p>
<p><span style='text-align:center; display: block;'><object width='425' height='350'><param name='movie' value='http://www.youtube.com/v/H9pWKB2D23k'></param><param name='wmode' value='transparent'></param><embed src='http://www.youtube.com/v/H9pWKB2D23k&rel=0' type='application/x-shockwave-flash' wmode='transparent' width='425' height='350'></embed></object></span></p>
]]></content:encoded>
</item>
<item>
<title><![CDATA[Переезд]]></title>
<link>http://dmych.wordpress.com/?p=199</link>
<pubDate>Sat, 17 May 2008 16:18:46 +0000</pubDate>
<dc:creator>dmych</dc:creator>
<guid>http://dmych.wordpress.com/?p=199</guid>
<description><![CDATA[Я (надеюсь, в последний раз) переезжаю на новую площадк]]></description>
<content:encoded><![CDATA[<p>Я (надеюсь, в последний раз) переезжаю на новую площадку.</p>
<p>Мой новый сайт: <a href="http://oramezo.org/">http://oramezo.org/</a>. Добро пожаловать!</p>
]]></content:encoded>
</item>
<item>
<title><![CDATA[С нови дрехи на ново място]]></title>
<link>http://stefanstoilov.wordpress.com/?p=14</link>
<pubDate>Fri, 16 May 2008 22:42:19 +0000</pubDate>
<dc:creator>Stefan Stoilov</dc:creator>
<guid>http://stefanstoilov.wordpress.com/?p=14</guid>
<description><![CDATA[От днес личния ми дневник се хоства от wordpress.com Дано си д]]></description>
<content:encoded><![CDATA[<p>От днес личния ми дневник се хоства от <a href="http://wordpress.com" target="_blank">wordpress.com</a> Дано си допаднем !</p>
]]></content:encoded>
</item>
<item>
<title><![CDATA[Как меня находят]]></title>
<link>http://brialius.wordpress.com/2008/05/13/requests/</link>
<pubDate>Tue, 13 May 2008 13:00:19 +0000</pubDate>
<dc:creator>brialius</dc:creator>
<guid>http://brialius.wordpress.com/2008/05/13/requests/</guid>
<description><![CDATA[Ссылки на себя поискал тут на досуге..
Сразу поясню, что]]></description>
<content:encoded><![CDATA[<p>Ссылки на себя поискал тут на досуге..</p>
<p>Сразу поясню, что первые 2 буквы означают язык блогов.</p>
<p><a href="http://bg.wordpress.com/tag/Жизнь/" target="_blank">bg.wordpress.com/tag/Жизнь/</a> - Жизнь и авто&#160; по болгарски</p>
<p><a href="http://bg.wordpress.com/tag/Авто/" target="_blank">bg.wordpress.com/tag/Авто/</a> </p>
<p><a href="http://es.wordpress.com/tag/Любовь/" target="_blank">es.wordpress.com/tag/Любовь/</a> - Любовь по испанки</p>
<p><a href="http://fr.wordpress.com/tag/Блог/" target="_blank">fr.wordpress.com/tag/Блог/</a> - Блог по французски и итальянски</p>
<p>это ваще хз что за языки..</p>
<p><a href="http://it.wordpress.com/tag/Блог/" target="_blank">it.wordpress.com/tag/Блог/</a>&#160;</p>
<p><a href="http://fa.wordpress.com/tag/Блог/" target="_blank">fa.wordpress.com/tag/Блог/</a></p>
<p><a href="http://pt.wordpress.com/tag/Блог/2/" target="_blank">pt.wordpress.com/tag/Блог/2/</a></p>
<p><a href="http://ca.wordpress.com/tag/Кино/" target="_blank">ca.wordpress.com/tag/Кино/</a></p>
<p>Какой интернациональный у меня блог оказывается :) Хоть бы одна ссылка на русские тэги была :)</p>
]]></content:encoded>
</item>
<item>
<title><![CDATA[Wordpress.com  1-сағат демалды]]></title>
<link>http://huanysh.wordpress.com/?p=239</link>
<pubDate>Sun, 11 May 2008 08:57:56 +0000</pubDate>
<dc:creator>huanysh</dc:creator>
<guid>http://huanysh.wordpress.com/?p=239</guid>
<description><![CDATA[Таңңертен (Алматы уақыты бойынша) WordPress.com  1-сағат демал]]></description>
<content:encoded><![CDATA[<p class="MsoNormal"><span style="font-size:10pt;font-family:Tahoma;">Таңңертен (Алматы уақыты бойынша) Wordpress.com <span> </span>1-сағат демалды. Яғни блогымда істедемеді. </span><span style="font-size:10pt;font-family:Tahoma;">Бір қызық екен.</span><span style="font-size:10pt;font-family:Tahoma;"> </span></p>
<p class="MsoNormal"><span style="font-size:10pt;font-family:Tahoma;">Бірақ Wordpress.org<span> </span>өз жұмысын атқарып отырды.<br />
</span></p>
<p class="MsoNormal">[gallery]</p>
]]></content:encoded>
</item>
<item>
<title><![CDATA[Қазақ тілінде сөйлейміз!!!]]></title>
<link>http://huanysh.wordpress.com/?p=236</link>
<pubDate>Sat, 10 May 2008 22:13:34 +0000</pubDate>
<dc:creator>huanysh</dc:creator>
<guid>http://huanysh.wordpress.com/?p=236</guid>
<description><![CDATA[Қаскелен қаласындағы Өрттен құтқару мекемесінің наси]]></description>
<content:encoded><![CDATA[<p class="MsoNormal" style="text-align:center;"><span style="font-size:10pt;font-family:Tahoma;"><strong>Қаскелен қаласындағы Өрттен құтқару мекемесінің насихаты.</strong></span></p>
<p class="MsoNormal" style="text-align:center;">
<p class="MsoNormal" style="text-align:center;"><span style="font-size:10pt;font-family:Tahoma;"><strong>Осындай насихаттар мемлекеттің басқа мекемелерінде орын тауып жатса, <span> </span>десенші!!!</strong></span></p>
<p><a href="http://huanysh.files.wordpress.com/2008/05/d0a4d0bed182d0be000.jpg"><img class="alignnone size-full wp-image-235" src="http://huanysh.wordpress.com/files/2008/05/d0a4d0bed182d0be000.jpg" alt="" width="460" height="345" /></a></p>
]]></content:encoded>
</item>
<item>
<title><![CDATA[Emacs Muse - WYWIWYM для статей WP]]></title>
<link>http://dmych.wordpress.com/?p=189</link>
<pubDate>Sat, 10 May 2008 12:26:40 +0000</pubDate>
<dc:creator>dmych</dc:creator>
<guid>http://dmych.wordpress.com/?p=189</guid>
<description><![CDATA[Онлайновый текстовый процессор, как на WordPress.com или Ipernit]]></description>
<content:encoded><![CDATA[<p style="text-align:justify;">Онлайновый текстовый процессор, как на WordPress.com или Ipernity — это здорово, но не всегда есть возможность им воспользоваться. Я часто пишу и редактирую статьи для сайтов или блогов на карманном компьютере по дороге на работу или с работы. А на нем к моим услугам только примитивный текстовый процессор, который меня не устраивает совершенно, да несколько текстовых редакторов разной мощности. Так что по началу я редактировал HTML в Emacs'е. Некоторое время это меня устраивало, тем более, что в редакторе есть хорошая поддержка HTML - и синтаксическая подсветка, и быстрая вставка нужных тегов...</p>
<p style="text-align:justify;"><!--more--></p>
<p style="text-align:justify;">Но все-таки вычитывать и править текст, продираясь глазами сквозь многочисленные теги, не очень приятно. Да и вставлять эти теги руками быстро надоело. Хотелось такого же комфорта, как в текстовом процессоре — хотелось WYSIWYG-редактора. Я перепробовал разные варианты, но все забраковал. Странно даже, неужели нет ни одного WYSIWYG-редактора, который бы просто порождал код HTML без кучи ненужных стилей и прочего мусора? Чтобы если я выбираю стиль H1, в коде бы не появлялось кучи тегов типа «&#60;h1 class="the-best-html-editor-header-one-style"&#62;&#60;span style="color: 000000;"&#62;...» — неужели это так трудно?</p>
<p style="text-align:justify;">Наконец, я вспомнил о таком замечательном изобретении, как разметка вики. С одной стороны, не надо загромождать текст тегами HTML, а с другой — форматирование и вёрстка производится просто вставкой нужных символов (например, чтобы выделить текст жирным, вместо &#60;strong&#62;таких тегов&#60;/strong&#62; текст просто обрамляется **двойными звездочками**). А учитывая, что тот же <a href="emacs-wiki-intro">EmacsWikiMode</a> красиво и удобно выделяет шрифтами и цветом синтаксис вики, а также прячет часть символов разметки, работа с вики-текстом напоминает скорее работу в текстовом процессоре.</p>
<p style="text-align:justify;">В конце концов, я остановился на Muse — более новом пакете, пришедшем на смену EmacsWiki. Правда, пришлось повозиться с настройкой пакета, чтобы он конвертировал вики-текст в HTML именно так, как надо для WordPress: во-первых, нужно удалить содержимое <code>muse-html-header</code> и <code>muse-html-footer</code>, а также <code>muse-html-style-sheet</code>, чтобы в результат не попадали разные &#60;html&#62;&#60;head&#62;.... Потом нужно отключить <code>auto-fill-mode</code> в <code>muse-mode-hook</code> и вместо него добавить <code>longlines-mode</code> — это чтобы не было не нужных разрывов строк (который WordPress оставляет как есть). Последнее, что я сделал — это создал два проекта в <code>muse-projects</code> и настроил их.</p>
<p style="text-align:justify;">Теперь я могу набирать текст в «почти WYSIWYG» (или WYSIWYM — What You See Is What You Mean) в своем любимом Emacs'е:</p>
<p class="image" style="text-align:justify;"><img src="http://dmych.wordpress.com/files/2008/05/muse-mode1.jpg" alt="" /></p>
<p style="text-align:justify;">На десктопе могу даже видеть картинки:</p>
<p class="image" style="text-align:justify;"><img src="http://dmych.wordpress.com/files/2008/05/muse-mode2.jpg" alt="" /></p>
<p style="text-align:justify;">После того, как пост или статья готовы, я нажимаю <code>C-c C-t</code>, загружаю получившийся HTML-файл в редактор WP и вношу окончательные коррективы (загружаю картинки и исправляю ссылки на них, выравниваю текст по ширине и т.п.).</p>
]]></content:encoded>
</item>
<item>
<title><![CDATA[Опубликована еще пара статей про Питон на Заурусе]]></title>
<link>http://dmych.wordpress.com/?p=185</link>
<pubDate>Sat, 10 May 2008 11:28:16 +0000</pubDate>
<dc:creator>dmych</dc:creator>
<guid>http://dmych.wordpress.com/?p=185</guid>
<description><![CDATA[
FileDialog для Qtopia
Программирование на Питоне под Qtopia

]]></description>
<content:encoded><![CDATA[<ul>
<li><a href="qtopia-file-dialog">FileDialog для Qtopia</a></li>
<li><a href="/articles/python-qpe-tutorial/">Программирование на Питоне под Qtopia</a></li>
</ul>
]]></content:encoded>
</item>
<item>
<title><![CDATA[Программирование на Питоне под Qtopia]]></title>
<link>http://dmych.wordpress.com/?page_id=160</link>
<pubDate>Sat, 10 May 2008 11:18:00 +0000</pubDate>
<dc:creator>dmych</dc:creator>
<guid>http://dmych.wordpress.com/?page_id=160</guid>
<description><![CDATA[Введение
Это небольшое введение в программирование на]]></description>
<content:encoded><![CDATA[<h3 style="text-align:justify;">Введение</h3>
<p class="first" style="text-align:justify;">Это небольшое введение в программирование на Питоне на Заурусе. Предполагается, что вы уже знакомы с языком <a href="http://ru.wikipedia.org/wiki/Python">Python</a>, имеете представление о <a href="http://ru.wikipedia.org/wiki/Qt">Qt</a> и <a href="http://www.qtopia.net/">Qtopia</a>, а также владеете навыками работы в командной строке и сможете заставить свой текстовый редактор правильно сохранять код программ на Питоне.</p>
<p style="text-align:justify;">Здесь вы <strong>не</strong> найдете информацию о том:</p>
<ul style="text-align:justify;">
<li>как программировать на Питоне</li>
<li>как программировать с использованием Qt</li>
<li>как программировать под Заурус на C++</li>
</ul>
<p style="text-align:justify;">Эта работа посвящена вопросам написания и адаптации программ на Питоне для Зауруса с использованием библиотек Qt и Qtopia и расширения <a href="http://ru.wikipedia.org/wiki/PyQT">PyQt</a> для Питона.</p>
<p style="text-align:justify;">Сначала рекомендуется прочитать <a href="http://wiki.python.org/moin/JonathanGardnerPyQtTutorial">Jonathan Gardner's PyQt Tutorial</a> (<a href="pyqttutorial">мой русский перевод</a>)</p>
<h4 style="text-align:justify;">Почему Питон?</h4>
<p style="text-align:justify;"><a href="http://www.python.org">Python</a> - интерпретируемый объектно-ориентированный язык, позволяющий писать в высшей степени переносимые программы. Его синтаксис предельно прост, а возможности - просто огромны.</p>
<p style="text-align:justify;">Вместе с кросс-платформенной библиотекой и набором инструментов Qt он позволяет создавать приложения, которые даже не надо перекомпилировать под каждую новую платформу.</p>
<p style="text-align:justify;">Однако, в программировании для Зауруса есть свои нюансы. Прежде всего, желательно использовать не только саму Qt, но и ее вариант, созданный для мобильных устройств, Qtopia.</p>
<h3 style="text-align:justify;">Требования</h3>
<p class="first" style="text-align:justify;">Вам потребуется установить Питон на свой Заурус. Также, если вы захотите проверить работоспособность кода на десктопе, вам потребуется также установить на ней Питон (не ниже версии 2.3), а также саму библиотеку Qt и библиотеку-"обертку" PyQt (в версии для Зауруса она поставляется "в комплекте").</p>
<p style="text-align:justify;">О том, как установить Питон на Заурус см. статью <a href="zaurus-python-image">Установка Питона на Заурусе</a>.</p>
<p style="text-align:justify;">Если ваш десктоп работает под управлением операционной системы Linux, Питон скорее всего у вас уже стоит. Проверить это можно набрав в командной строке <code>python</code> (выход - <code>Ctrl-D</code>). Однако, PyQt скорее всего придется устанавливать дополнительно.</p>
<p style="text-align:justify;">Аналогично, Qt может уже стоять (особенно если вы используете KDE или какие-то программы из него).</p>
<p style="text-align:justify;">Для других операционных систем вам скорее всего потребуется установить все три вещи.</p>
<p>Подробности см. на сайте <a href="http://www.python.org">http://www.python.org</a> (найти дистрибутив для вашей ОС можно по адресу <a href="http://www.python.org/download/">http://www.python.org/download/</a>), <a href="http://www.trolltech.com/products/qt/index.html">http://www.trolltech.com/products/qt/index.html</a>, <a href="http://www.qtopia.net/modules/developers/">http://www.qtopia.net/modules/developers/</a></p>
<p style="text-align:justify;">Также вам нужен будет текстовый редактор, поддерживающий UTF-8 и пригодный для написания кода на Питоне. Одной из характерных черт этого языка является чувствительность к лидирующим пробелам в строках — их количество определяет вложенность операторов (служит операторными скобками). Поэтому неправильная работа редактора с пробелами и табуляциями может привести к трудноуловимым ошибкам в программе. Из всех имеющихся для Зауруса редакторов на мой взгляд лучше всего подходит <a href="http://ru.wikipedia.org/wiki/Emacs">Emacs</a>. Этот редактор имеет замечательный режим для работы с программами на Питоне. Другой альтернативой является <a href="http://ru.wikipedia.org/wiki/Vim">Vim</a>.</p>
<h3 style="text-align:justify;">Hello, Zaurus</h3>
<h4 style="text-align:justify;">Просто Qt</h4>
<p class="first" style="text-align:justify;">Итак, приступим. Создайте в редакторе файл <strong>hello.py</strong> со следующим содержанием:</p>
<p>[sourcecode language='python']<br />
#!/usr/bin/python<br />
import sys<br />
from qt import *<br />
app = QApplication(sys.argv)<br />
label = QLabel(None, 'label')<br />
label.setText("<br />
<h1><i>Hello</i>, Qt!</h1>
<p>")<br />
label.resize(QSize(300, 200))<br />
app.setMainWidget(label)<br />
label.show()<br />
app.exec_loop()<br />
[/sourcecode]</p>
<p>Прежде, чем запустить эту программу, рассмотрим по порядку каждую строчку.</p>
<p>Первая строка — стандартный заголовок, сообщающий командному интерпретатору где находится интерпретатор для данного языка.</p>
<p>Далее мы инпортируем модуль sys (откуда мы вызываем функцию, возвращающую список аргументов командной строки), в следующей строке мы импортируем главный модуль PyQt — библиотеки-"обертки", транслирующий наши запросы из Питона в саму Qt. Обратите внимание, что в отличие от C++, мы не импортируем отдельных модулей для каждого используемого виджета, а сразу все.</p>
<p>В четвертой строке мы создаем объект-приложение и передаем ему список параметров командной строки (Qt сама распознает некоторое количество параметров командной строки).</p>
<p>В трех следующих строках мы создаем и настраиваем текстовую метку, которая используется как главный виджет нашего приложения: сначала мы создаем соответствующий объект, потом задаем текст для него (обратите внимание, что для форматирования можно воспользоваться языком HTML — многие виджеты Qt "понимают" его), наконец, задаем размер.</p>
<p>Далее мы делаем метку центральным виджетом нашего приложения, отображаем ее и передаем управление в цикл обработки событий приложения (обратите внимание, что в Питоне слово "exec" является зарезервированным, поэтому в PyQt функция <code>exec()</code> назвается <code>exec_loop()</code>).</p>
<h4 style="text-align:justify;">Особенности запуска из консоли</h4>
<p>Вы можете запустить эту программу из консоли, набрав</p>
<pre style="text-align:justify;">python ./hello.py</pre>
<p style="text-align:justify;">или же сделайте его исполняемым командой <code>chmod</code> (я предпочитаю второй вариант). После запуска откроется окно нашего приложения, которое будет выглядеть примерно так:</p>
<p class="image" style="text-align:justify;"><img src="/files/2008/05/hello.png" alt="" width="640" height="480" /></p>
<p style="text-align:justify;">Вы можете перемещать окно по экрану, распахивать его на весь экран, работает также системное меню (вызываемое щелчком на иконке Qt в левом верхнем углу), закрыть окно можно, как обычно, кнопкой с крестиком.</p>
<p style="text-align:justify;">Однако будьте осторожны: если вы переключитесь сейчас на другое приложение (напимер, ткнете пером в окно консоли, видимое из-под окна "Hello, Zaurus", вы не сможете нормально продолжить работу с нашим приложением: Заурус переключится в режим "Magnified screen", что обычно в подобной ситуации приводит к отображению только белого экрана.</p>
<p style="text-align:justify;">Но не пугайтесь. Достаточно любым доступным способом "убить" наше приложение:</p>
<ul style="text-align:justify;">
<li>открыть новую консоль нажатием Fn-N и выполнить команду <code>killall python</code></li>
<li>или же запустить "System Info" и послать процессу hello.py сигнал "9: SIGKILL".</li>
</ul>
<p style="text-align:justify;">Такое поведение, по-видимому, связано с какой-то ошибкой в реализации консоли или самой Qtopia.</p>
<p style="text-align:justify;">Обратите также внимание на отсутствие иконки для нашей программы в таскбаре — система по-видимому считает нашу программу подпроцессом консоли. Когда мы научимся запускать программы с рабочего стола, все встанет на свои места.</p>
<h4 style="text-align:justify;">Qtpe — делаем приложение в стиле Qtopia</h4>
<p class="first" style="text-align:justify;">Однако, наше приложение пока не очень похоже на окошки Зауруса. Скорее оно выглядит как обычная программа для десктопа. Давайте займемся адаптацией его под Qtopia.</p>
<p style="text-align:justify;">Много для этого делать не придется: вместо <strong>QApplication</strong> нужно использовать класс <strong>QPEApplication</strong> (импортируемый из модуля <strong>qtpe</strong>), кроме того, мы сразу изменим размер окна на 640x480, чтобы оно занимало весь экран (когда мы будем запускать эту программу с рабочего стола, размер ее окна автоматически будет изменяться таким образом, чтобы оно занимало всю площадь экрана, кроме таскбара).</p>
<p style="text-align:justify;">File: <strong>helloqtopia.py</strong></p>
<p>[sourcecode language='python']<br />
#!/usr/bin/python<br />
import sys<br />
from qt import *<br />
from qtpe import *<br />
app = QPEApplication(sys.argv)<br />
label = QLabel(None, 'label')<br />
label.setText('<br />
<h1 align="center"><i>Hello</i>, Zaurus!</h1>
<p>')<br />
label.resize(QSize(640, 480))<br />
app.setMainWidget(label)<br />
label.show()<br />
app.exec_loop()<br />
[/sourcecode]</p>
<p>Буквы PE в названиях модуля и класс означают "Palmtop Edition" и происходят от первоначального названия Кутопии (также как и название каталога QtPalmtop).</p>
<p>Когда вы запустите эту программу, вы увидите такое окно:</p>
<p><img src="http://dmych.wordpress.com/files/2008/05/hello-qtopia.png" alt="" /></p>
<p>Обратите внимание на отсутствие курсивного выделения слова "Hello". Если вы уберете заголовочные теги вокруг надписи, то курсив снова "проявится". Видимо, это связано как-то либо с ошибками, либо с особенностями рендеринга HTML в Кутопии.</p>
<h4 style="text-align:justify;">Запускаем везде!</h4>
<p>Но тепеь при попытке запуска программы не на Заурусе, Питон будет жаловаться, что не может найти модуль qtpe, и не захочет выполнять программу дальше.</p>
<p>Тут нам на помощь придут обработка исключительных ситуаций в Питоне и преимущества динамической типизации (то, что в Питоне переменная сама по себе не связана типами или классами — в каждый момент времени она может принимать значение любого типа).</p>
<p>Более точно, мы будем перехватывать возникающую исключительную ситуацию, когда Питон не находит нужный нам модуль, и подменять один класс другим. Вот, как это делается:</p>
<p>File: <strong>helloqt.py</strong></p>
<p>[sourcecode language='python']<br />
#!/usr/bin/python<br />
# -*- coding: utf-8 -*-</p>
<p>import sys<br />
from qt import *<br />
try:                                    # перехватываем ошибку импорта<br />
    from qtpe import *                  # пытаемся импортировать<br />
    isQtopia = True                     # все в порядке<br />
except:<br />
    isQtopia = False                    # ошибка - это не Qtopia<br />
    QPEApplication = QApplication       # это будет один и тот же класс</p>
<p>app = QPEApplication(sys.argv)<br />
label = QLabel(None, 'label')<br />
label.setText('<br />
<h1 align="center"><i>Hello</i>, Zaurus!</h1>
<p>')<br />
label.resize(QSize(640, 480))<br />
app.setMainWidget(label)<br />
label.show()<br />
app.exec_loop()<br />
[/sourcecode]</p>
<p>Комментарий во второй строке обрабатывается самим Питоном (также он используется Emacs'ом) — он указывает кодировку файла. Если ее не указать, то Питон будет ругаться на наши комментарии, написанные по-русски.</p>
<p>Переменная <code>isQtopia</code> может быть использована в дальнейшем, если в других местах программы потребуется узнать, где исполняется программа.</p>
<h3 style="text-align:justify;">Цифровые часы</h3>
<p>Возьмем теперь пример посложнее. Наша следующая программа будет основана на программе <strong>dclock.py</strong> из демонстрационных примеров PyQt. Если вы не понимаете, что и как делает эта программа, прочтите руководство по Qt. Вот ее адаптированный исходный текст:</p>
<p>File: <strong>dclock.py</strong></p>
<p>[sourcecode language='python']<br />
#!/usr/bin/python<br />
# -*- coding: utf-8 -*-<br />
# A port to PyQt of the dclock example from Qt v2.x.<br />
# Версия, адаптированная для Qtopia</p>
<p>import sys, string<br />
from qt import *<br />
try:<br />
    from qtpe import *<br />
    isQtopia = True<br />
except:<br />
    QPEApplication = QApplication<br />
    isQtopia = False</p>
<p>class DigitalClock(QLCDNumber):<br />
    def __init__(self, parent=None, name=None):<br />
        QLCDNumber.__init__(self, parent, name)<br />
        self.setCaption('Digital Clock')<br />
        self.showingColon = 0<br />
        if isQtopia:<br />
          black=QColor(0,0,0)<br />
          self.setBackgroundColor(black)<br />
        self.setFrameStyle(QFrame.Panel &#124; QFrame.Raised)<br />
        self.setLineWidth(2)<br />
        self.showTime()<br />
        self.normalTimer = self.startTimer(500)<br />
        self.showDateTimer = -1</p>
<p>    def timerEvent(self, e):<br />
        if e.timerId() == self.showDateTimer:<br />
            self.stopDate()<br />
        else:<br />
            if self.showDateTimer == -1:<br />
                self.showTime()</p>
<p>    def mousePressEvent(self, e):<br />
        if e.button() == Qt.LeftButton:<br />
            self.showDate()</p>
<p>    def showDate(self):<br />
        if self.showDateTimer != -1:<br />
            return<br />
        d = QDate.currentDate()<br />
        self.display('%2d %2d' % (d.month(), d.day()))<br />
        self.showDateTimer = self.startTimer(2000)</p>
<p>    def stopDate(self):<br />
        self.killTimer(self.showDateTimer)<br />
        self.showDateTimer = -1<br />
        self.showTime()</p>
<p>    def showTime(self):<br />
        self.showingColon = not self.showingColon<br />
        s = list(str(QTime.currentTime().toString())[:5]) #.left(5)<br />
        if not self.showingColon:<br />
            s[2] = ' '<br />
        if s[0] == '0':<br />
            s[0] = ' '<br />
        s = string.join(s,'')<br />
        self.display(s)</p>
<p>a = QPEApplication(sys.argv)<br />
clock = DigitalClock()<br />
clock.resize(170,80)<br />
a.setMainWidget(clock)<br />
clock.show()<br />
a.exec_loop()<br />
[/sourcecode]</p>
<p>Обратите внимание, как используется переменная <code>isQtopia</code> в конструкторе класса: на десктопе цвет часов останется по умолчанию (серым), в то время как на Заурусе часы будут на черном фоне.</p>
<h4 style="text-align:justify;">Делаем ярлык на рабочем столе</h4>
<p>Давайте, наконец, создадим иконку на рабочем столе Зауруса, чтобы запускать наши часы оттуда.</p>
<p>Есть по крайней мере два варианта, как это сделать:</p>
<ul style="text-align:justify;">
<li>положить файл <code>dclock.py</code> в каталог <code>/home/QtPalmtop/bin</code> и создать ярлык, указывающий на него, или</li>
<li>положить файл в любое место (например, в домашний каталог <code>/home/zaurus</code>), а в каталоге <code>/home/QtPalmtop/bin</code> создать символическую ссылку ("симлинк") на этот файл.</li>
</ul>
<p>Я предпочитаю второй вариант, т.к. в этом случае мне не нужны права суперпользователя чтобы отредактировать файл, кроме того это удобнее, если программа состоит из нескольких файлов (модулей), что обычно для Питона. Чтобы не сваливать все их в <code>/home/QtPalmtop/bin</code> или возиться с настройкой переменной <code>PYTHONPATH</code>, я делаю лишь ссылку на главный запускаемый файл.</p>
<p>Давайте так и поступим:</p>
<ul style="text-align:justify;">
<li>скопируйте файл <code>dclock.py</code> в домашний каталог</li>
<li>сделайте его исполняемым: <code>$ chmod +x ./dclock.py</code></li>
<li>станьте суперпользователем и перейдите в <code>/home/QtPalmtop/bin</code>:</li>
</ul>
<pre style="text-align:justify;"> $ su
 # cd /home/QtPalmtop/bin</pre>
<ul style="text-align:justify;">
<li>создайте симлинк на наш файл:</li>
</ul>
<pre style="text-align:justify;"> /home/QtPalmtop/bin# ln -s /home/zaurus/dclock.py dclock</pre>
<ul style="text-align:justify;">
<li>теперь откройте "Tab Settings" на закладке "Settings" рабочего стола</li>
<li>выберите в левой части окна подходящую закладку и создайте новый ярлык (кнопка с чистым листочком на панели внизу)</li>
<li>введите имя "Digital Clock", выберите иконку "Clock", введите имя программы "dclock"</li>
<li>сохраните изменения, нажимая "Ok"</li>
<li>перейдите на нужную закладку и снимите у созданной иконки флаг "Display with magnified screen" (почему-то все ярлыки создаются с этим флагом)</li>
</ul>
<p style="text-align:justify;">Voila! Нажимаем на ярлык и через несколько секунд наслаждаемся результатом:</p>
<p class="image" style="text-align:justify;"><img src="http://dmych.wordpress.com/files/2008/05/dclock1.png" alt="" /></p>
<p style="text-align:justify;">Наше приложение занимает всю полезную площадь экрана, имеет иконку в панели задач, а также правильно масштабируется при повороте экрана.</p>
<p style="text-align:justify;">Щелчок по окну вызывает краткосрочное переключение на отображение даты.</p>
<h4 style="text-align:justify;">Главное меню</h4>
<p class="first" style="text-align:justify;">Давайте усовершенствуем наши часы: добавим меню с пунктами "About" и "Exit". На Заурусе меню может вызываться нажатием кнопки "Menu".</p>
<p style="text-align:justify;">Для начала создадим новый класс, являющийся наследником <strong>QMainWindow</strong>. Добавьте следующий фрагмент кода после класса <strong>DigitalClock</strong> перед главной программой (начинающейся со строки "<code>a = QPEApplication(sys.argv)</code>"):</p>
<p>[sourcecode language='python']<br />
class MainWindow(QMainWindow):<br />
    def __init__(self, parent=None):<br />
        QMainWindow.__init__(self, parent, '', 0)<br />
        self.setCaption('Digital Clock')<br />
        self.setCentralWidget(QWidget(self, "qt_central_widget"))<br />
        self.setupMainMenu()<br />
        mainFormLayout = QVBoxLayout(self.centralWidget(), 1, 2, "mainFormLayout")<br />
        self.clock = DigitalClock(self.centralWidget())<br />
        mainFormLayout.addWidget(self.clock)</p>
<p>    def setupMainMenu(self):<br />
        self.actionAbout = QAction(self, "actionAbout")<br />
        self.actionAbout.setText("About Digital Clock")<br />
        self.actionAbout.setMenuText("&About")<br />
        self.actionExit = QAction(self, "actionExit")<br />
        self.actionExit.setText("Exit")<br />
        self.actionExit.setMenuText("E&xit")<br />
        self.actionExit.setAccel(Qt.CTRL+Qt.Key_Q)<br />
        if isQtopia:<br />
            self.menubar = QPEMenuBar(self,"menubar")<br />
        else:<br />
            self.menubar = QMenuBar(self,"menubar")<br />
        self.clockMenu = QPopupMenu(self)<br />
        self.actionAbout.addTo(self.clockMenu)<br />
        self.clockMenu.insertSeparator()<br />
        self.actionExit.addTo(self.clockMenu)<br />
        self.menubar.insertItem("&Clock", self.clockMenu, 0)<br />
        self.connect(self.actionAbout, SIGNAL("activated()"),<br />
                     self.showAboutBox)<br />
        self.connect(self.actionExit, SIGNAL("activated()"),<br />
                     self.close)</p>
<p>    def showAboutBox(self):<br />
        QMessageBox.about(self, "About",<br />
                          "<br />
<h2>Digital Clock</h2>
<p>" +<br />
                          "PyQt demo for Qtopia")<br />
[/sourcecode]</p>
<p>Обратите внимание, что мы создаем главное меню как <strong>QMenuBar</strong> или <strong>QPEMenuBar</strong> в зависимости от флага <strong>isQtopia</strong>.</p>
<p>Затем измените конструктор <strong>DigitalClock</strong> — уберите оттуда вызов <strong>showCaption</strong>.</p>
<p>Наконец, внесите изменения в главную программу:</p>
<p>[sourcecode language='python']<br />
a = QPEApplication(sys.argv)<br />
clock = MainWindow()<br />
clock.resize(170,80)<br />
a.setMainWidget(clock)<br />
clock.show()<br />
a.exec_loop()<br />
[/sourcecode]</p>
<p>Вот, как теперь это выглядит:</p>
<p><img src="http://dmych.wordpress.com/files/2008/05/dclock2.png" alt="" /></p>
<p><img src="http://dmych.wordpress.com/files/2008/05/dclock3.png" alt="" /></p>
<h3 style="text-align:justify;">Диалоговые окна — кнопки Ok и Cancel</h3>
<p>В диалоговых окнах Кутопии нет необходимости вручную создавать кнопки "Ok" и "Cancel" — каждый диалог уже имеет их в заголовке, а также откликается на нажатие соответствующих кнопок.</p>
<p>Я пользуюсь примерно следующим кодом, помещающим кнопки в диалог только в случае необходимости (опять-таки, основываясь на значении флага <strong>isQtopia</strong>):</p>
<p>[sourcecode language='python']<br />
if not utils.isQtopia:<br />
    layout10 = QHBoxLayout(None,0,6,"layout10")<br />
    self.btnOk = QPushButton(self,"btnOk")<br />
    self.btnOk.setText("O&K")<br />
    layout10.addWidget(self.btnOk)<br />
    self.btnCancel = QPushButton(self,"btnCancel")<br />
    self.btnCancel.setText("&Cancel")<br />
    layout10.addWidget(self.btnCancel)<br />
    MainDialogLayout.addLayout(layout10)<br />
    self.btnOk.setDefault(True)<br />
    self.connect(self.btnOk,SIGNAL("clicked()"),self.accept)<br />
    self.connect(self.btnCancel,SIGNAL("clicked()"),self.reject)<br />
[/sourcecode]</p>
<p>Этот код выполнятся только когда программа запущена не на Заурусе (точнее не под Кутопией): создаются две кнопки, связываются с соответствующими слотами диалога и пакуются в QHBoxLayout.</p>
<p>Этот код я вставляю в конец конструктора диалога, когда все другие виджеты уже определены и размещены в окне. Таким образом, кнопки "OK" и "Cancel" всегда будут выводиться в самом низу формы, одна возле другой.</p>
<h3 style="text-align:justify;">Совместимость версий Qt</h3>
<p>В настоящий момент на Заурусе используется Qt версии 2.3.2, в то время как в большинстве других ОС уже давно используется Qt версии не ниже 3. Это необходимо учитывать при написании программ. Дело в том, что в версиях до третьей отсутствуют многие классы и методы. Тут можно, опять-таки, в зависимости от того, где выполняется программа, либо использовать имеющиеся классы, либо заменять их собственными реализациями.</p>
<h4 style="text-align:justify;">Использование Qt Designer'а и утилиты pyuic</h4>
<p>Из-за разницы в версиях иногда бывает вручную доводить код, созданный при помощи Qt Designer'а и pyuic. Иногда бывает достаточно выкинуть пару вызовов несущественных методов, либо заменить их на код, работающий в данной версии.</p>
<h3 style="text-align:justify;">Ссылки</h3>
<ul style="text-align:justify;">
<li>Jonathan Gardner's PyQt Tutorial по-русски: <a href="http://pyqt.wikispaces.com/PyQtTutorial">http://pyqt.wikispaces.com/PyQtTutorial</a></li>
<li>Qt: <a href="http://www.trolltech.com/products/qt/index.html">http://www.trolltech.com/products/qt/index.html</a></li>
<li>Qtopia: <a href="http://www.qtopia.net/modules/developers/">http://www.qtopia.net/modules/developers/</a></li>
<li>Все о Питоне (а также дистрибутивы для всех платформ) можно найти на главном сайте Питона <a href="http://www.python.org">http://www.python.org</a></li>
</ul>
<p>Copyright (C) Дмитрий Бречалов aka D.Mych, 2005</p>
]]></content:encoded>
</item>
<item>
<title><![CDATA[Библиотека разных алгоритмов: классических, оригинальных, красивых, любопытных]]></title>
<link>http://dmych.wordpress.com/?page_id=178</link>
<pubDate>Fri, 09 May 2008 17:52:31 +0000</pubDate>
<dc:creator>dmych</dc:creator>
<guid>http://dmych.wordpress.com/?page_id=178</guid>
<description><![CDATA[Источники:
[Knuth] ::    Дональд Кнут Искусство программиро]]></description>
<content:encoded><![CDATA[<p><strong>Источники:</strong></p>
<p><code>[Knuth]</code> ::    Дональд Кнут Искусство программирования</p>
<p><code>[Wirth]</code> ::    Никлаус Вирт Алгоритмы и структуры данных</p>
<p><code>[Bentley]</code> ::  Джон Бентли Жемчужины программирования</p>
<h3><a id="sec1" name="sec1"></a><br />
Содержание</h3>
<div class="contents">
<dl>
<dt> <a href="#sec1">Содержание</a> </dt>
<dt> <a href="#sec2">ПОИСК</a> </dt>
<dt> <a href="#sec3">СОРТИРОВКА</a> </dt>
<dt> <a href="#sec4">ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ</a> </dt>
<dt> <a href="#sec5">КУЧИ</a> </dt>
<dt> <a href="#sec6">ПЕРЕСТАНОВКИ</a> </dt>
<dt> <a href="#sec7">РАЗНОЕ</a> </dt>
</dl>
</div>
<h3><a id="sec2" name="sec2"></a><br />
ПОИСК</h3>
<p class="first">Здесь собраны алгоритмы поиска в массивах.</p>
<h4>Линейный поиск</h4>
<p><code>[Wirth, 1.12.1]</code></p>
<pre>    a: ARRAY[0..N-1] OF item;
    i:=0; WHILE (i&#60;N)&#38;(a[i]#x) DO i:=i+1 END
</pre>
<h4>Линейный поиск с барьером</h4>
<p><code>[Wirth, 1.12.1]</code></p>
<pre>    a: ARRAY[0..N] OF item;
    a[N]:=x; i:=0; WHILE a[i]#x DO i:=i+1 END
</pre>
<h4>Бинарный поиск</h4>
<p><code>[Wirth, 1.12.2]</code></p>
<pre>    a: ARRAY[0..N] OF item
</pre>
<p><strong>Условие:</strong> массив упорядочен:</p>
<pre>    A k : 1 &#60;= k &#60; N : a[k-1] &#60;= a[k]
</pre>
<p><strong>Вариант 1</strong></p>
<pre>    L:=0; R:=N-1; found:=FALSE;
    WHILE (L&#60;=R) &#38; ~found DO
      m:=AnyValueBetween(L,R);
      IF a[m]=x THEN found:=TRUE
      ELSIF a[m]&#60;x THEN L:=m+1
      ELSE R:=m-1
      END
    END
</pre>
<p><strong>Вариант 2</strong></p>
<pre>    L:=0; R:=N;
    WHILE L&#60;R DO
      m:=(L+R) DIV 2;
      IF a[m]&#60;x THEN L:=m+1 ELSE R:=m END
    END
</pre>
<p>(R &#60; N)&#38;(a[R]=x) фиксирует совпадение</p>
<p><strong>Вариант 3</strong></p>
<p>Псевдокод:</p>
<p><code>[Bentley L.4.3]</code></p>
<pre>    l = 0; u = n - 1
    loop
        { t mustbe(l, u) }
        if l &#62; u
            p = -1; break
        m = (l + u) / 2
        case
            x[m] &#60; t: l = m + 1
            x[m] == t: p = m; break
            x[m] &#62; t: u = m - 1
</pre>
<p>Программа на C:</p>
<p><code>[Bentley L.5.1]</code></p>
<pre>    typedef int DataType;
    int n;
    DataType x[MAXN];

    int binarysearch(DataType t)
        /* возвращает любое вхождение t в отсортированный
           массив x[0..n-1] либо -1 в случае отсутствия
           вхождений */
    {
        int l, u, m;
        l = 0;
        u = n - 1;
        while (l &#60;= u)
        {
            m = (l + u) / 2;
            if (x[m] &#60; t)
                l = m + 1;
            else if (x[m] == t)
                return m;
            else /* x[m] &#62; t */
                u = m - 1;
        }
        return -1;
    }
</pre>
<h4>Поиск строк</h4>
<p><code>[Wirth, 1.12.3]</code></p>
<pre>    String = ARRAY[0..M-1] OF CHAR  (* ASCIIZ-строка *)
</pre>
<p>Отношение порядка для строк:</p>
<pre>(x=y) = (A j: 0 &#60;= j &#60; M : x[j] =y[j] )

(x &#60; y) = $ i: 0 &#60;= i &#60; N :
    ((A j: 0 &#60;= j &#60; i : x[j] =y[j] )&#38;(x[i] &#60; y[i] ))
</pre>
<h5>Сравнение строк</h5>
<pre>    i:=0;
    WHILE (x[i]=y[i])&#38;(x[i])#0C) DO i:=i+1 END
</pre>
<h5>Поиск строки методом деления пополам</h5>
<pre>    T: ARRAY[0..N-1] OF String;
    x: String;

    L:=0; R:=N;
    WHILE L&#60;R DO
      m:=(L+R) DIV 2; i:=0;
      WHILE (T[m,i]=x[i])&#38;(x[i]#0C) DO i:=i+1 END;
      IF T[m,i]&#60;x[i] THEN L:=L+1 ELSE R:=m END
    END
    IF R&#60;N THEN
      i:=0;
      WHILE (T[R,i]=x[i])&#38;(x[i]#0C) DO i:=i+1 END
    END
</pre>
<p>(R &#60; N)&#38;(T[R,i]=x[i]) фиксирует совпадение</p>
<h5>Прямой поиск строки</h5>
<p><code>[Wirth, 1.12.4]</code></p>
<p>Пусть задан массив <em>s</em> из <em>N</em> элементов и массив <em>p</em> из <em>M</em> элементов, причем 0 &#60; M &#60;= N. Описаны они так:</p>
<pre>    s: ARRAY[0..N-1] OF item;
    p: ARRAY[0..M-1] OF item;
</pre>
<p>Поиск обнаруживает первое вхождение <em>p</em> в <em>s</em>.</p>
<pre>    i:=1;
    REPEAT i:=i+1; j:=0;
      WHILE (j&#60;M)&#38;(s[i+j]=p[j]) DO j:=j+1 END
    UNTIL (j=M)OR(i=N-M)
    (* j=M - found; i=N-M - not found *)
</pre>
<h4>Хеширование</h4>
<p><code>[Bentley, 15.1]</code></p>
<pre>    typedef struct node *nodeptr;
    typedef struct node {
        char *word;
        int count;
        nodeptr next;
    } node;

    #define NHASH 29989
    #define MULT 31
    nodeptr bin[NHASH]; /* хеш-таблица */

    /* хеш-функция */
    unsigned int hash(char *p)
    {
        unsigned int h = 0;
        for ( : *p; p++)
            h = MULT * h + *p;
        return h % NHASH;
    }
</pre>
<h3><a id="sec3" name="sec3"></a><br />
СОРТИРОВКА</h3>
<h4>СОРТИРОВКА МАССИВОВ</h4>
<p class="first">Сортируем массивы "на месте":</p>
<pre>     TYPE index = INTEGER;
     VAR a: ARRAY[1..n] OF item;
</pre>
<h5>StraightInsertion - Сортировка прямым включением</h5>
<p><code>[Wirth, 2.1]</code></p>
<pre>    PROCEDURE StraightInsertion;
      VAR i, j: index; x: item;
    BEGIN
      FOR i:=2 TO n DO
        x:=a[i]; a[0]:=x; j:=i;
        WHILE x&#60;a[j-1] DO a[j]:=a[j-1]; j:=j-1 END;
        a[j]:=x
      END
    END StraightInsertion;
</pre>
<h5>BinaryInsertion - Сортировка методом деления пополам</h5>
<p><code>[Wirth, 2.2]</code></p>
<pre>    PROCEDURE BinaryInsertion;
      VAR i, j, m, L, R: index; x: item;
    BEGIN
      FOR i:=2 TO n DO
        x:=a[i]; L:=1; R:=i;
        WHILE L&#60;R DO
          m:=(L+R) DIV 2;
          IF a[m]&#60;=x THEN L:=m+1 ELSE R:=m END
        END;
        FOR j:=i TO R+1 BY -1 DO a[j]:=a[j-1] END;
        a[R]:=x
      END
    END BinaryInsertion;
</pre>
<h5>StraightSelection - Сортировка методом прямого выбора</h5>
<p><code>[Wirth, 2.3]</code></p>
<pre>    PROCEDURE StraightSelection;
      VAR i, j, k: index; x: item;
    BEGIN
      FOR i:=1 TO n-1 DO
        k:=i; x:=a[i];
        FOR j:=i+1 TO n DO
          IF a[j]&#60;x THEN k:=j; x:=a[k] END
        END;
        a[k]:=a[i]; a[i]:=x
      END
    END StraightSelection;
</pre>
<h5>BubbleSort - Пузырьковая сортировка</h5>
<p><code>[Wirth, 2.4]</code></p>
<pre>    PROCEDURE BubbleSort;
      VAR i, j: index; x: item;
    BEGIN
      FOR i:=2 TO n DO
        FOR j:=n TO i BY -1 DO
          IF a[i-1]&#62;a[j] THEN
            x:=a[j-1]; a[j-1]:=a[j]; a[j]:=x
          END
        END
      END
    END BubbleSort;
</pre>
<h5>ShakerSort - Шейкерная сортировка</h5>
<p><code>[Wirth, 2.5]</code></p>
<pre>    PROCEDURE ShakerSort;
      VAR j, k, L, R: index; x: item;
    BEGIN
      L:=2; R:=n; k:=n;
      REPEAT
        FOR j:=R TO L BY -1 DO
          IF a[j-1]&#62;a[j] THEN
            x:=a[j-1]; a[j-1]:=a[j]; a[j]:=x; k:=j;
          END
        END;
        L:=L+1;
        FOR j:=L TO R BY +1 DO
          IF a[j-1]&#62;a[j] THEN
            x:=a[j-1]; a[j-1]:=a[j]; a[j]:=x; k:=j;
          END
        END
        R:=k-1
      UNTIL L&#62;R;
    END ShakerSort;
</pre>
<h5>ShellSort - Сортировка Шелла</h5>
<p><code>[Wirth, 2.6]</code></p>
<pre>    PROCEDURE ShellSort;
      CONST t=4;	(* расстояние *)
      VAR i, j, k, s: index;
          x: item;
          m: 1..t;
          h: ARRAY[1..t] OF INTEGER;
    BEGIN
      h[1]:=9; h[2]:=5; h[3]:=3; h[4]:=1;
      FOR m:=1 TO t DO
        k:=h[m]; s:=-k;  (* место барьера *)
        FOR i:=k+1 TO n DO
          x:=a[i]; j:=i-k;
          IF s=0 THEN s:=-k END;
          s:=s+1; a[s]:=x;
          WHILE x&#60;a[j] DO a[j+k]:=a[j]; j:=j-k END;
          a[j+k]:=x
        END
      END
    END ShellSort;
</pre>
<h5><a id="heapsort" name="heapsort"></a>HeapSort - Сортировка с помощью дерева</h5>
<p><code>[Wirth, 2.8]</code><br />
(См. также <a href="AlgoLib#heaps">Кучи</a>)</p>
<pre>    PROCEDURE HeapSort;
      VAR L,R: index; x: item;

      PROCEDURE sift(L, R: index);
        VAR i, j: index; x: item;
      BEGIN
        i:=L; j:=2*L; x:=a[L];
        IF (j&#60;R)&#38;(a[j]&#60;a[j+1] THEN j:=j+1 END;
        WHILE (j&#60;=R)&#38;(x&#60;a[j]) DO
          a[i]:=a[j]; i:=j; j:=2*j;
          IF (j&#60;R)&#38;(a[j]&#60;a[j+1]) THEN j:=j+1 END
        END
      END sift;

    BEGIN
      L:=(n DIV 2)+1; R:=n;
      WHILE L&#62;1 DO L:=L-1; sift(L,R) END;
      WHILE R&#62;1 DO
        x:=a[1]; a[1]:=a[R]; a[R]:=x;
        R:=R-1;
        sift(L,R);
      END
    END HeapSort;
</pre>
<h5>QuickSort - Быстрая сортировка Хоара</h5>
<p><code>[Wirth, 2.10]</code></p>
<pre>    PROCEDURE QuickSort;

      PROCEDURE sort(L, R: index);
        VAR i, j: index; w, x: item;
      BEGIN
        i:=L; j:=R;
        x:=a[(L+R) DIV 2];
        REPEAT
          WHILE a[i]&#60;x DO i:=i+1 END;
          WHILE x&#60;a[j] DO j:=j-1 END;
          IF i&#60;=j THEN
            w:=a[i]; a[i]:=a[j]; a[j]:=w;
            i:=i+1; j:=j-1
          END
        UNTIL i&#62;j;
        IF L&#60;j THEN sort(L,j) END;
        IF i&#60;R THEN sort(i,R) END;
      END sort;

    BEGIN sort(1,n);
    END QuickSort;
</pre>
<p><code>[Bentley 11.2-3]</code></p>
<p><span style="text-decoration:underline;">Набросок</span></p>
<pre>    void qsort(l, u)
        if l &#62;= u
            /* не более одного элемента - ничего не делаем */
            return
        /* цель: разбить массив относительно какого-либо
        элемента, который оказывается на правильном месте */
        qsort(l, p-1)
        qsort(p+1, u)
</pre>
<p><span style="text-decoration:underline;">Версия 1</span></p>
<pre>    void qsort(l, u)
        if (l &#62;= u)
            return
        m = 1
        for i = [l+1, u]
            /* инвариант: x[l+1..m] &#60; x[l] &#38;&#38;
             * x[m+1..i-1] &#62;= x[l] */
            if (x[i] &#60; x[l])
                swap(++m, i)
        swap(l, m)
        /* x[l..m-1] &#60; x[m] &#60;= x[m+1, u] */
        qsort(l, m-1)
        qsort(m+1, u)
</pre>
<p><span style="text-decoration:underline;">Версия 3</span></p>
<pre>    void qsort(l, u)
        if l &#62;= u
            return
        t = x[l]; i = l; j = u+1
        loop
            do i++ while i &#60;= u &#38;&#38; x[i] &#60; t
            do j-- while x[j] &#62; t
            if i &#62; j
                break
            swap(i, j)
        swap(l, j)
        qsort(l, j-1)
        qsort(j+1, u)
</pre>
<h5>Рекомендации по выбору алгоритмов сортировки</h5>
<p><code>[Wirth]</code></p>
<ul>
<li>Для достаточно малых n прямые методы оказываются быстрее, хотя при больших n ими пользоваться не стоит.</li>
<li>Прямой выбор предпочтительнее строгого включения. Однако, если ключи вначале упорядочены, то прямое включение будет оставаться несколько более быстрым.</li>
<li>Шейкерная сортировка с успехом используется в случаях, когда элементы почти упорядочены.</li>
<li>HeapSort: чем больше n, тем лучше она работает. Она даже становится сравнимой с сортировкой Шелла.</li>
<li>Пузырьковая сортировка - наихудшая из всех метолов, но ее улучшение приводит к самому лучшему из известных методов сортировки - QuickSort.</li>
<li>QuickSort - чем неупорядоченее, тем лучше.</li>
</ul>
<h3><a id="sec4" name="sec4"></a><br />
ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ</h3>
<h4>Основные операциии с линейными списками</h4>
<p><code>[Wirth, гл. 4.3]</code></p>
<p>Представление списка</p>
<pre>    TYPE Ptr = POINTER TO Node;
    TYPE Node = RECORD
                  key: INTEGER;
                  next: Ptr;
                  data: ...;
                END;
    VAR p, q: Ptr;
</pre>
<p>Включение нового элемента в начало списка</p>
<pre>    Allocate(q,SIZE(Node)); q^.next:=p; p:=q;
</pre>
<p>Формирование списка из n элементов</p>
<pre>    p:=NIL;  (* в начале список пуст *)
    WHILE n&#62;0 DO
      Allocate(q,SIZE(Node)); q^.next:=p; p:=q;
      q^.key:=n; n:=n-1
    END;
</pre>
<p>Включение элемента в список после элемента, на который указывает p</p>
<pre>    q^.next:=p^.next; p^.next:=q;
</pre>
<p>Проход по списку</p>
<p>Проход по списку с выполнением над каждым его элементом<br />
операции P(x)</p>
<pre>    WHILE p#NIL DO
      P(p^);
      p:=p^.next;
    END;
</pre>
<p>Поиск элемента в списке</p>
<pre>    WHILE (p#NIL)&#38;(p^.key#x) DO
      p:=p^.next;
    END
</pre>
<h4>Последовательное распределение</h4>
<p><code>[Knuth, 2.2.2]</code></p>
<p>Наиболее простой и естественный способ хранения линейного списка в памяти компьютера заключается в расположении элементов в последовательных ячейках, при котором один узел списка следует сразу же за другим. Тогда</p>
<pre>LOC(X[j+1])=LOC(X[j])+c,
</pre>
<p>где c - размер одного узла.</p>
<pre>LOC(X[j])=L[0] +cj,
</pre>
<p>где L[0] - константа, которая называется <em>базовым адресом (base address)</em>, т. е. является адресом некоего узла X[0]. стр. 286</p>
<h3><a id="sec5" name="sec5"></a><br />
<a id="heaps" name="heaps"></a>КУЧИ</h3>
<p><code>[Bentley 14]</code></p>
<p>Куча представляет собой структуру данных, используемую для представления множеств элементов.</p>
<pre>                            12
                        ___/  \___
                       /          \
                      /            \
                    20              15
                   /  \            /  \
                  /    \          /    \
                29      23      17      22
                /\      /\      /
               /  \    /  \    /
              35  40  26  51  19
</pre>
<p>Это двоичное дерево является кучей благодаря двум свойствам.</p>
<p>Первое свойство мы назовем "порядком": значение любого узла не превышает значения любого из его дочерних узлов. Отсюда следует, что наименьший элемент набора находится на вершине дерева. Однако о соотношении левого и правого дочерних узлов ничего не говорится.</p>
<p>Второе свойство кучи называется "формой". Идея формы лучше всего передается следующим рисунком:</p>
<pre>                            /\
                           /  \
                          /    \
                         /      \
                        /     ___\
                       /_____&#124;
</pre>
<p>Другими словами, двоичное дерево, обладающее свойством "формы", заканчивается не более чем на двух уровнях (то есть заключительные узлы расположены не более чем на двух уровнях), причем находящиеся на нижнем уровне узлы сгруппированы слева. В дереве не должно быть незанятых узлов. Если в нем содержится n узлов, ни один из них не может отстоять более чем на log2(n).</p>
<h4>Представление кучи в виде массива</h4>
<pre>                            x[1]
                       /           \
                x[2]                   x[3]
              /      \               /     \
          x[4]         x[5]       x[6]      x[7]
         /  \         /  \       /
      x[8]  x[9]  x[10]  x[11]  x[12]
</pre>
<p>Обратите внимание, что для представления куч массивы нумеруются с единицы. Типичные функции для такого дерева определяются следующим образом:</p>
<pre>    root = 1
    value(i) = x[i]
    leftchild(i) = 2*i
    rightchild(i) = 2*i + 1
    parent(i) = i/2
    null(i) = (i &#60; 1) or (i &#62; n)
</pre>
<p>Неявное дерево из n элементов обязательно будет обладать свойством формы: отсутствие элементов в нем просто не предусмотрено.</p>
<p>Вышеприведенная куча из 12 элементов может быть представлена в виде следующего массива:</p>
<pre>          &#124; 12 20 15 29 23 17 22 35 40 26 51 19 &#124;
           -------------------------------------
           1                                  12
</pre>
<p>Второе свойство: массив x[1..n] обладает свойством кучи, если</p>
<pre>                A: 2&#60;=i&#60;=n: x[i/2] &#60;= x[i]
</pre>
<h4>Добавление нового элемента</h4>
<p class="first">Добавление произвольного элемента в поле x[n] при условии, что x[1..n-1] является кучей, не обязательно даст кучу. Восстановление свойства кучи обеспечивается функцией siftup. Имя функции описывает стратегию, лежащую в ее основе: новый элемент просеивается и всплывает вверх до полагающегося ему места, обмениваясь позициями с вышестоящими элементами:</p>
<pre>    void siftup(n)
            /* предусловие: n &#62; 0 &#38;&#38; heap(1, n-1)
             * постусловие: heap(1, n) */
        loop
            /* инвариант: heap(1, n) за исключением, быть
             * может, элемента i и его родителя */
            if i == 1
                break
            p = i/2
            if x[p] &#60;= x[i]
                break
            swap(p, i)
            i = p
</pre>
<p>Если x[1..n] — куча, а мы присваиваем элементу x<sup><a class="footref" name="fnr.1" href="#fn.1">1</a></sup> новое значение, то в любом случае остается верным утверждение heap(2, n). Функция siftdown предназначена для расширения этого утверждения до heap(1, n). Это осуществляется путем просеивания элемента x<sup><a class="footref" name="fnr.1" href="#fn.1">1</a></sup> вниз по массиву, до тех пор, пока у него не закончатся дочерние элементы или пока элемент не окажется не превышающим значени всех его дочерних элементов.</p>
<pre>    void siftdown(n)
            /* предусловие: heap(2, n) &#38;&#38; n &#62;= 0
             * постусловие: heap(1, n) */
        i = 1
        loop
            /* инвариант: heap(1, n) верно, за
             * исключением, быть может, i и его дочерних
             * элементов (0, 1 или 2) */
            c = 2*i
            if c &#62; n
                break
            /* c - левый дочерний эл-т i */
            if c+1 &#60;= n
                /* c+1 - правый дочерний эл-т i */
                if x[c+1] &#60; x[c]
                    c++
            /* c - наименьший из дочерних эл-тов */
            if x[i] &#60;= x[c]
                break
            swap(c, i)
            i = c
</pre>
<h4>Сортировка с помощью кучи (heapsort)</h4>
<p class="first">[Bentley 14.4]<br />
(См. также <a href="AlgoLib#heapsort">HeapSort - Сортировка с помощью дерева</a>)</p>
<pre>    for i = [2, n]
        siftup(i)
    for (i=n; i &#62;= 2; i--)
        swap(1, i)
        siftdown(i-1)
</pre>
<h3><a id="sec6" name="sec6"></a><br />
ПЕРЕСТАНОВКИ</h3>
<h4>Перемножение перестановок, представленных в виде циклов</h4>
<p><code>[Knuth, 1.3.3]</code></p>
<p>Произведение перестановок можно выполнять непосредственно с помощью циклической записи. Например, вычислив произведение перестановок</p>
<pre>(a c f g)(b c d)(a e d)(d a d e)(b g f a e),
</pre>
<p>находим (двигаясь слева направо), что «a переходит в c, c переходит в d, d переходит в a, a переходит в d и d остается без изменений». Таким образом, конечным результатом является то, что a переходит в d, и мы запишем «(a d)» в качестве частичного ответа. Теперь выясним, что происходит с d: «d переходит в b, которое затем переходит в g»; следовательно, имеем частичный результат «(a d g)». Рассмотрев, что происходит с g, находим, что «g переходит в a, затем в e, в f и в a»; таким образом, первый цикл замыкается: «(a d g)». Теперь выберем новый элемент, который еще не встречался, напимер, c. Находим, что c переходит в e... Окончательным ответом будет «(a d g)(c e b)».</p>
<h5>Алгоритм A</h5>
<p><code>[Knuth 1.3.3 A]</code></p>
<p>Этот алгоритм берет произведение циклов вида</p>
<pre>(a c f g)(b c d)(a e d)(d a d e)(b g f a e)
</pre>
<p>и вычисляет получающуюся в результате перестановку в виде произведения непересекающихся циклов. Для простоты здесь не приводится описание процедуры удаления единичных циклов; это было бы лишь незначительным обобщением алгоритма. По мере выполнения алгоритма последовательно «помечаем» элементы исходной формулы, т.е. те символы, которые уже «обработаны».</p>
<ol>
<li>[Первый проход] Отметить все левые скобки и заменить все правые скобки помеченной копией входного символа, который следует за соответствующей левой скобкой.</li>
<li>[Раскрытие скобок] Выполнив поиск слева направо, найти первый непомеченный элемент входной формулы. (Если все элементы помечены, то работа алгоритма заканчивается.) Установить START равным этому элементу; вывести левую скобку; вывести элемент и пометить его.</li>
<li>[Установка CURRENT] Установить CURRENT равным следующему элементу формулы.</li>
<li>[Просмотр формулы] Продвигаться вправо, пока не будет либо достигнут конец формулы, либо найден элемент, равный CURRENT; в последнем случае пометить его и вернуться к шагу 3.</li>
<li>[CURRENT = START?] Если CURRENT &#60;&#62; START, вывести CURRENT и вернуться к шагу 4, снова начав с левого края формулы (продолжая тем самым вывод искомого цикла).</li>
<li>[Закрытие] (Полный искомый цикл выведен.) Вывести правую скобку и вернуться к шагу 2.</li>
</ol>
<h5>Алгоритм B</h5>
<p><code>[Knuth 1.3.3 B]</code></p>
<p>Этот алгоритм дает, в сущности, тот же результат, что и алгоритм A. Предположим, что переставляемыми элементами являются x<sup><a class="footref" name="fnr.1" href="#fn.1">1</a></sup> , x<sup><a class="footref" name="fnr.2" href="#fn.2">2</a></sup> , ..., x[n] . Будем использовать вспомогательную таблицу T<sup><a class="footref" name="fnr.1" href="#fn.1">1</a></sup>, T<sup><a class="footref" name="fnr.2" href="#fn.2">2</a></sup>, ..., T[n]; по окончании работы алгоритма x[i] переходит в x[j] в перестановке тогда и только тогда, когда T[i] = j.</p>
<ol>
<li>[Инициализация] Присвоить <code>T[k] &#60;- k, где 1 &#60;= k &#60;= n</code>. Подготовиться также к просмотру справа налево.</li>
<li>[Следующий элемент] Рассмотреть следующий элемент ввода (справа налево). Если ввод исчерпан, то работа алгоритма заканчивается. Если рассматривается элемент &#60;&#60;)&#62;&#62;, то присвоить Z &#60;- 0 и повторить шаг 2; если это элемент &#60;&#60;(&#62;&#62;, то перейти к шагу 4. В противном случае рассматривается элемент x[i] для некоторого i; тогда перейти к шагу 3.</li>
<li>[Замена T[i]] Выполнить взаимный обмен Z&#60;-&#62;T[i]. Если в результате получится T[i] = 0, то присвоить j &#60;- i. Вернуться к шагу 2.</li>
<li>[Замена T[j]] Присвоить T[j] &#60;- Z. (Здесь j - это строка, определяющая элемент &#60;&#60;)&#62;&#62;, т.е. правую скобку, которая соответствует только что просмотренной левой скобке.) Вернуться к шагу 2.</li>
</ol>
<h4>Обратная перестановка на месте</h4>
<h5>Алгоритм I</h5>
<p><code>[Knuth 1.3.3 I]</code></p>
<p>Заменить X<sup><a class="footref" name="fnr.1" href="#fn.1">1</a></sup>X<sup><a class="footref" name="fnr.2" href="#fn.2">2</a></sup>... X[n], которая является перестановкой чисел {1,2,... n}. Этот алгоритм был предложен Бин-Чао Хуан (Bing-Chao Huang).</p>
<ol>
<li>[Инициализация] Присвоить m &#60;- n, j &#60;- -1.</li>
<li>[Следующий элемент] Присвоить i &#60;- X[m]. Если i &#60; 0, перейти к шагу 5 (этот элемент уже был обработан).</li>
<li>[Обратить один элемент] (В этот момент j &#60; 0 и i=X[m]. Если m не является наибольшим элементом своего цикла, то первоначальная перестановка давала X[-j]=m.) Присвоить X[m] &#60;- j, j &#60;- -m, m &#60;- i,  i &#60;- X[m].</li>
<li>[Конец цикла?] Если i &#62; 0, перейти к шагу 3 (этот цикл не закончен); иначе - присвоить i &#60;- j. (В последнем случае первоначальная перестановка давала X[-j]=m, где m - наибольший элемент в цикле.)</li>
<li>[Сохранить окончательное значение] Присвоить  X[m] &#60;- -i. (Первоначально X[-i] было равно m.)</li>
<li>[Цикл по m] Уменьшить m на 1. Если m &#62; 0, перейти к шагу 2; в противном случае работа алгоритма заканчивается.</li>
</ol>
<h5>Алгоритм J</h5>
<p><code>[Knuth 1.3.3 J]</code></p>
<p>Следующий остроумный алгоритм был предложен Дж. Бутройдом (J. Boothroyd). Этот алгоритм дает такой же результат, как и алгоритм I, но на основании другого метода.</p>
<ol>
<li>[Сделать все величины отрицательными] Присвоить  X[k] &#60;- -X[k] для 1 &#60;= k &#60;= n. Присвоить также  m &#60;- n.</li>
<li>[Инициализация j] Присвоить j &#60;- m.</li>
<li>[Нахождение отрицательного элемента] Присвоить  i &#60;- X[j]. Если i &#62; 0, присвоить j &#60;- i и повторить этот шаг.</li>
<li>[Обращение] Присвоить X[j] &#60;- X[-i], X[-i] &#60;- m.</li>
<li>[Цикл по m] Уменьшить m на 1; если m &#62; 0, вернуться к шагу 2. В противном случае работа алгоритма заканчивается.</li>
</ol>
<h3><a id="sec7" name="sec7"></a><br />
РАЗНОЕ</h3>
<h4>Ввод/вывод чисел (без знака)</h4>
<p><code>[Wirth, 1.11.3]</code></p>
<pre>    x: WORD;
    i: CARDINAL;
    ch: CHAR;
    d: ARRAY[0..N] OF WORD;

    (* ввод и преобразование *)
    x:=0; Read(ch);
    WHILE ("0"&#60;=ch)&#38;(ch&#60;="9") DO
      x:=10*x+(ORD(ch)-ORD("0"));
      Read(ch)
    END;

    (* преобразование и вывод *)
    i:=0;
    REPEAT d[i]:=x MOD 10; x:=x DIV 10; i:=i+1;
    UNTIL x=0;
    REPEAT i:=i-1; Write(CHR(d[i]+ORD("0")))
    UNTIL i=0;
</pre>
<h4>Простейший кольцевой буфер</h4>
<p><code>[Wirth, 1.11.2]</code></p>
<p>для использования одной программой</p>
<pre>    MODULE Buffer;
    EXPORT deposit, fetch;
    CONST N=1024; (* размер *)
    VAR n, in, out: CARDINAL;
        buf: ARRAY[0..N-1] OF WORD;

    PROCEDURE deposit(x: WORD);
    BEGIN
      IF n=N THEN HALT END;
      n:=n+1; buf[in]:=x; in:=(in+1) MOD N
    END deposit;

    PROCEDURE fetch(VAR x: WORD);
    BEGIN
      IF n=0 THEN HALT END;
      n:=n-1; x:=buf[out]; out:=(out+1) MOD N
    END fetch;

    BEGIN n:=0; in:=0; out:=0
    END Buffer.
</pre>
<h4>Алгоритм Евклида</h4>
<p><code>[Knuth, 1.1 E]</code></p>
<p>Даны два целых положительных числа m и n. Требуется найти их наибольший общий делитель.</p>
<ol>
<li>[Нахождение остатка] Разделим m на n, и пусть остаток от деления будет равен r (где 0 &#60;= r &#60; n).</li>
<li>[Сравнение с нулем] Если r=0, то выполнение алгоритма прекращается; n - искомое значение.</li>
<li>[Замещение] Присвоить m &#60;- n, n &#60;- r и вернуться к  шагу 1.</li>
</ol>
<h4>Обобщенный алгоритм Евклида</h4>
<p><code>[Knuth, 1.2.1 E]</code></p>
<p>Даны два целых положительных числа m и n. Требуется найти их наибольший общий делитель (gcd - greatest common divisor) d и два целых числа a и b, таких, что am+bn=d.</p>
<ol>
<li>[Инициализация] Присвоить a' &#60;- b &#60;- 1,  a &#60;- b' &#60;- c &#60;- m, d &#60;- n.</li>
<li>[Деление] Пусть q и r - это частное и остаток от деления c на d соответственно. (Тогда c=qd+r, где  0 &#60;= r &#60; d.)</li>
<li>[Остаток - нуль?] Если r=0, то выполнение алгоритма прекращается; в этом случае имеем am+bn=d, как и требовалось.</li>
<li>[Повторение цикла] Присвоить c &#60;- d, d &#60;- r,  t &#60;- a', a' &#60;- a, a &#60;- t-qa, t &#60;- b',b' &#60;- b,  b &#60;- t-qb и вернуться к шагу 2.</li>
</ol>
<h4>Циклический сдвиг массива</h4>
<p><code>[Bentley 2.3]</code></p>
<p>Циклический сдвиг массива x из n элементов влево на i позиций за время, пропорциональное n, причем доступно лишь несколько десятков байт оперативной памяти.</p>
<p>Циклический сдвиг массива x сводится фактически к замене ab на ba, где a — первые i элементов, а b — оставшиеся элементы.</p>
<p>Итак, нужно преобразовать массив ab в ba. Предположим, что у нас есть функция reverse, переставляющая элементы некоторой части массива в противоположном порядке. В исходном состоянии массив имеет вид ab. Вызвав эту функцию для первой части, получим a'b. Затем вызовем ее для второй части: получим a'b'. Затем вызовем функцию для всего массива, что даст (a'b')', а это в точности соответствует ba. Посмотрим, как будет такая функция действовать на массив abcdefgh, который нужно сдвинуть влево на три элемента:</p>
<pre>    reverse(0, i-1)	/* cbadefgh */
    reverse(i, n-1)	/* cbahgfed */
    reverse(0, n-1)	/* defghabc */
</pre>
<p>Дуг Макилрой (Doug McIlroy) предложил наглядную иллюстрацию циклического сдвига массива из десяти элементов вверх на пять позиций; начальное положение: обе руки ладонями к себе, левая над правой.</p>
<pre>    --== 1     &#124;  --=== 5   &#124;  --=== 5   &#124;    6 ==--
      ==== 2   &#124;    ==== 4  &#124;    ==== 4  &#124;  7 ====
      ===== 3  X    ===== 3 &#124;    ===== 3 &#124; 8 =====
      ==== 4   &#124;    ==== 2  &#124;    ==== 2  &#124;  9 ====
    --=== 5    &#124;  --== 1    &#124;  --== 1    &#124;  10 ===--
               &#124;            &#124;            X
       6 ==--  &#124;    6 ==--  &#124;  10 ===--  &#124; --== 1
     7 ====    &#124;  7 ====    &#124;  9 ====    &#124;   ==== 2
    8 =====    &#124; 8 =====    X 8 =====    &#124;   ===== 3
     9 ====    &#124;  9 ====    &#124;  7 ====    &#124;   ==== 4
     10 ===--  &#124;  10 ===--  &#124;    6 ==--  &#124; --=== 5
               &#124;            &#124;            &#124;
           повернуть    повернуть     повернуть
          левую руку   правую руку  обе (как целое)
</pre>
<h4>Поиск максимальной подпоследовательности</h4>
<p><code>[Bentley 8.1]</code></p>
<p>На входе имеется массив x из n вещественных чисел, на выходе должна быть получена максимальная сумма любой непрерывной последовательности элементов массива.</p>
<p><strong>Вариант 1</strong></p>
<p>Перебор всех пар целых i и j, где 0&#60;=i&#60;=j&#60;n; для каждой пары чисел вычисляется сумма x[i..j], после чего проверяется, преверяется, превосходит ли она предыдущее найденное максимальное значение.</p>
<pre>    maxsofar = 0
    for i = [0, n)
        for j = [i, n)
            sum = 0
            for k = [i, j]
                sum += x[k]
            /* sum - сумма элементов x[i..j] */
            maxsofar = max(mazsofar, sum)
</pre>
<p><strong>Вариант 2a</strong></p>
<p>Данный алгоритм позволяет быстро вычислить сумму благодаря тому, что сумма x[i..j] легко получается из предыдущей: x[i..j-1].</p>
<pre>    maxsofar = 0
    for i = [0, n)
        sum = 0
        for j = [i, n)
            sum += x[j]
            /* sum - сумма x[i..j] */
            maxsofar = max(maxsofar, sum)
</pre>
<p><strong>Вариант 2b</strong></p>
<p>Алгоритм вычисляет сумму во внутреннем цикле, обращаясь к структуре данных, которая строится отдельно, до начала первого цикла. Создается массив cumarr, i-й элемент которого содержит кумулятивную сумму значений x[0..i], поэтому сумму x[i..j] можно получить как разность cumarr[j] - cumarr[i-1].</p>
<pre>    cumarr[-1] = 0
    for i = [0, n)
        cumarr[i] = cumarr[i-1] + x[i]
    maxsofar = 0
    for i = [0, n)
        for j = [i, n)
            sum = cumarr[j] - cumarr[i-1]
            /* sum - сумма x[i..j] */
            maxsofar = max(maxsofar, sum)
</pre>
<p><strong>Вариант 3 "Разделяй и властвуй"</strong></p>
<p>Алгоритм основан на правиле:</p>
<blockquote><p>Если нужно решить задачу размера n, следует рекурсивно решить две подзадачи размера приблизительно n/2, а затем оббъединить их решения в одно целое.</p></blockquote>
<pre>    float maxsum3(l, u)
        if (l &#62; u)    /* пустой массив */
            return 0
        if (l == u)   /* один элемент */
            return max(0, x[l])
        m = (1 + u) / 2
        /* m: поиск макс. посл. слева от границы */
        lmax = sum = 0
        for (i = m; i &#62;= l; i--)
            sum += x[i]
            lmax = max(lmax, sum)
        /* m: поиск макс. посл. справа от границы */
        rmax = sum = 0
        for i = (m, u]
            sum += x[i]
            rmax = max(rmax, sum)
        return max(lmax+rmax, maxsum3(l, m), maxsum3(m+1, u))
</pre>
<p>Алгоритм запускается вызовом</p>
<pre>answer = maxsum3(0, n-1)
</pre>
<p><strong>Вариант 4 Сканирующий алгоритм</strong></p>
<pre>    maxsofar = 0
    maxendinghere = 0
    for i = [0, n)
        /* инвариант: значения maxendinghere и maxsofar
           точны для x[0..i-1] */
        maxendinghere = max(maxendinghere + x[i], 0)
        maxsofar = max(maxsofar, maxendinghere)
</pre>
<h4>Функция comlen - вычисление длины общей части двух строк</h4>
<p><code>[Bentley 15.2]</code></p>
<pre>    int comlen(char *p, char *q)
        i = 0
        while *p &#38;&#38; (*p++ == *q++)
            i++
        return i
</pre>
<h4>Установка, проверка и сброс отдельных битов</h4>
<p><code>[Bentley p.239]</code></p>
<pre>    #define BITSPERWORD 32
    #define SHIFT 5
    #define MASK 0x1F
    #define N 10000000
    int a[1+N/BITSPERWORD];

    void set(int i) { a[i&#62;&#62;SHIFT] &#124;= (1&#60;&#60;(i &#38; MASK)); }
    void clr(int i) { a[i&#62;&#62;SHIFT] &#38;= ~(1&#60;&#60;(i &#38; MASK)); }
    int test(int i) { return a[i&#62;&#62;SHIFT] &#38; (1&#60;&#60;(i &#38; MASK)); }
</pre>
]]></content:encoded>
</item>
<item>
<title><![CDATA[Ұялы телефон &amp;  Wordpress – тегі блогым]]></title>
<link>http://huanysh.wordpress.com/?p=224</link>
<pubDate>Sun, 04 May 2008 13:25:11 +0000</pubDate>
<dc:creator>huanysh</dc:creator>
<guid>http://huanysh.wordpress.com/?p=224</guid>
<description><![CDATA[Ұялы телефоныңыз егер интернетке қосыған болса, сіз оз]]></description>
<content:encoded><![CDATA[<p class="MsoNormal"><span style="font-family:Tahoma;">Ұялы телефоныңыз егер интернетке қосыған болса, сіз оз блогыңызды жаңартуыңызға болады. Бірақ ұялы телефон қазақ тілін қолдамайды, сурет қоса алмайсыз, телефоннан ұзын жазба жазу уақыт алады тек қысқа жазбалар ыңғайлы. (смс жазған секілді боласыз)</span><!--more--></p>
<p class="MsoNormal"><span style="font-family:Tahoma;">Бірінші ұялы телефоныңыздың интернет браузерінен <a href="http://m.wordpress.com/">http://m.wordpress.com</a> <span> </span>мекен-жайын теріңіз. <span> </span></span></p>
<p class="MsoNormal"><span style="font-family:Tahoma;">Екінші сізден Wordpress – тегі блогыңыздағы қолданушы аты мен кілт сөзін сұрайды.</span></p>
<p class="MsoNormal"><span style="font-family:Tahoma;">Үшінші сізге блогыңыздың санақ (Stat) көрсеткіш орта ашылады.</span></p>
<p class="MsoNormal"><a href="http://huanysh.files.wordpress.com/2008/05/11.jpg"><img class="alignleft size-full wp-image-226" src="http://huanysh.wordpress.com/files/2008/05/11.jpg" alt="" width="276" height="171" /></a></p>
<p class="MsoNormal">
<p class="MsoNormal">
<p class="MsoNormal">
<p class="MsoNormal">
<p class="MsoNormal"><span style="font-family:Tahoma;">Төртінші Post (Жазба) бөліміне өтіп жазбаңызды жазуға мүмкіндік аласыз.</span></p>
<p class="MsoNormal"><span style="font-family:Tahoma;">Сонда Жазба атауын (Title) енгізіңіз, келесі жазба Мәтінін (Content) жазыңыз, <span> </span>келесі әрекет жазбаға байланысты Ілмектерді (Tags) енгізіңіз. Жазбаны жазып бітсеңіз Жариялау (Publish) <span> </span>батырмасын басып көріңіз.</span></p>
<p class="MsoNormal"><a href="http://huanysh.files.wordpress.com/2008/05/31.jpg"><img class="alignnone size-full wp-image-228" src="http://huanysh.wordpress.com/files/2008/05/31.jpg" alt="" width="393" height="293" /></a></p>
<p class="MsoNormal"><span style="font-family:Tahoma;">Енді блогыңызды ашып қарап көрсеңіз болады.</span></p>
]]></content:encoded>
</item>
<item>
<title><![CDATA[Знову на зв'язку]]></title>
<link>http://grandse.wordpress.com/?p=29</link>
<pubDate>Sat, 03 May 2008 22:03:03 +0000</pubDate>
<dc:creator>grandse</dc:creator>
<guid>http://grandse.wordpress.com/?p=29</guid>
<description><![CDATA[Як можна побачити, блог зовсім трошки змінився. Всюди, ]]></description>
<content:encoded><![CDATA[<p>Як можна побачити, блог зовсім трошки змінився. Всюди, де це необхідно, повний варіант замітки на першій сторінці було замінено на короткий, що спрощує перегляд, прискорює завантаження та відображення сторінки.</p>
<p>Окрім цього дякі замітки були доволі серйозно допрацьовані, особливо в плані виправлень помилок в тексті, деякого редагування з метою більш простого сприйняття інформації.</p>
<p>А сьогодні-завтра вже на сторінках з'являться вже нові свіжі думки.</p>
]]></content:encoded>
</item>
<item>
<title><![CDATA[Google Reader қолданушысына көмек.]]></title>
<link>http://huanysh.wordpress.com/?p=222</link>
<pubDate>Thu, 01 May 2008 23:36:46 +0000</pubDate>
<dc:creator>huanysh</dc:creator>
<guid>http://huanysh.wordpress.com/?p=222</guid>
<description><![CDATA[



Навигация




j/k:


келесі немесе алдыңғы жазба




пробе]]></description>
<content:encoded><![CDATA[<table class="MsoNormalTable" border="0" cellpadding="0">
<tbody>
<tr>
<td style="padding:0.75pt;" colspan="2">
<p class="MsoNormal"><span style="font-family:Tahoma;">Навигация</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">j/k:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">келесі немесе алдыңғы жазба</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">пробел.</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">келесі жазба немесе бет</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">&#60;Shift&#62; + пробел:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">предыдущая запись или   страница</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">n/p:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">э</span><span style="font-family:Tahoma;">лемент</span><span style="font-family:Tahoma;">терді төмен немесе жоғары сканділеу</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">&#60;Shift&#62; + n/p:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">келесі немесе алдыңғы жазылым</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">&#60;Shift&#62; + x:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">п</span><span style="font-family:Tahoma;">ап</span><span style="font-family:Tahoma;">каны жаю</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">&#60;Shift&#62; + o:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">жазылым немесе папка ашу</span></p>
</td>
</tr>
</tbody>
</table>
<p class="MsoNormal"><span style="font-family:Tahoma;"> </span><!--more--></p>
<table class="MsoNormalTable" border="0" cellpadding="0">
<tbody>
<tr>
<td style="padding:0.75pt;" colspan="2">
<p class="MsoNormal"><span style="font-family:Tahoma;">Жазбалармен әрекет</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">s:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">жазбаны таңбалау</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">&#60;Shift&#62; + s:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">жазбаны жалпыға қосу</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">v:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">түпнұсқасын көру</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">t:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">ілмекті жазбаға беру</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">m:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">жазбаны оқылған немесе оқылмаған ретінде белгілеу</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">o/</span><span style="font-family:Tahoma;">енгізу</span><span style="font-family:Tahoma;">:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">жазбаны бүктеу немесе жаю</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">&#60;Shift&#62; + a:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">балығын оқылған есебінде белгілеу</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">e:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">жазбаны е-почта арқылы жібер</span></p>
</td>
</tr>
</tbody>
</table>
<p class="MsoNormal"><span style="font-family:Tahoma;"> </span></p>
<table class="MsoNormalTable" border="0" cellpadding="0">
<tbody>
<tr>
<td style="padding:0.75pt;" colspan="2">
<p class="MsoNormal"><span style="font-family:Tahoma;">Өту</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">g, </span><span style="font-family:Tahoma;">кейін</span><span style="font-family:Tahoma;"> h:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">басты бетке өту</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">g, </span><span style="font-family:Tahoma;">кейін</span><span style="font-family:Tahoma;"> a:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">барлық жазбаларға өту</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">g, </span><span style="font-family:Tahoma;">кейін</span><span style="font-family:Tahoma;"> s:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">таңдалған жазбаларға өту</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">g, </span><span style="font-family:Tahoma;">кейін</span><span style="font-family:Tahoma;"> &#60;Shift&#62; + s:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">жалпы жазбаларға өту</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">g, </span><span style="font-family:Tahoma;">кейін</span><span style="font-family:Tahoma;"> u:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">жазылымдар таңдау бетін ашу</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">g, </span><span style="font-family:Tahoma;">кейін</span><span style="font-family:Tahoma;"> t:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">ілмектер таңдау бетіне өту</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">g, </span><span style="font-family:Tahoma;">кейін</span><span style="font-family:Tahoma;"> &#60;Shift&#62; + t:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">санақ бетіне өту</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">g, </span><span style="font-family:Tahoma;">кейін</span><span style="font-family:Tahoma;"> d:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">қарау бетіне өту</span></p>
</td>
</tr>
</tbody>
</table>
<p class="MsoNormal"><span style="font-family:Tahoma;"> </span></p>
<table class="MsoNormalTable" border="0" cellpadding="0">
<tbody>
<tr>
<td style="padding:0.75pt;" colspan="2">
<p class="MsoNormal"><span style="font-family:Tahoma;">Қосымша </span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">r:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">жаңарту</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">u:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">түгел экрандық режимге көшу</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">1:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">бүктелген түріне асуысу</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">2:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">тізімдер түріне ауысу</span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">/:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">к</span><span style="font-family:Tahoma;">урсор</span><span style="font-family:Tahoma;"> <span>іздеу алаңына   апару</span></span></p>
</td>
</tr>
<tr>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">a:</span></p>
</td>
<td style="padding:0.75pt;">
<p class="MsoNormal"><span style="font-family:Tahoma;">жазылым қосу</span></p>
</td>
</tr>
</tbody>
</table>
<p class="MsoNormal"><span style="font-family:Tahoma;"> </span></p>
]]></content:encoded>
</item>
<item>
<title><![CDATA[Введение в разработку приложений для Qtopia]]></title>
<link>http://dmych.wordpress.com/?page_id=172</link>
<pubDate>Wed, 30 Apr 2008 10:20:22 +0000</pubDate>
<dc:creator>dmych</dc:creator>
<guid>http://dmych.wordpress.com/?page_id=172</guid>
<description><![CDATA[В статье приводится пошаговое руководство по написани]]></description>
<content:encoded><![CDATA[<p style="text-align:justify;">В статье приводится пошаговое руководство по написанию, отладке и созданию дистрибутива (очень) простого приложения под Qtopia на КПК Sharp Zaurus.</p>
<p style="text-align:justify;">Предполагается, что читатель знаком с языком C++ и умеет работать в командном интерпретаторе Линукс.</p>
<p style="text-align:justify;">Все примеры проверены на Sharp Zaurus SL-C860 с прошивкой Cacko 1.22a и Developer Image 1.6 на борту.</p>
<h3>Матчасть</h3>
<p style="text-align:justify;"><a href="http://www.qtopia.net/" target="_blank"><strong>Qtopia</strong></a> -- графический интерфейс и менеджер программ для небольших устройств, работающих на Линуксе. Пользовательский интерфейс Qtopia основан на библиотеке Qt-embedded, являющейся уменьшенной версией библиотеки Qt. Qtopia, Qt-embedded и Qt производятся небольшой софтверной компанией Trolltech из Норвегии.</p>
<p style="text-align:justify;">Qt широко используется для разработки приложений в Линуксе, наиболее известным проектом, использующим эту библиотеку, является KDE.</p>
<p style="text-align:justify;">Qtopia написана на языке C++, "родные" (native) Qtopia-приложения также должны писаться на этом языке. Приложение должно быть реализовано как класс C++. Так полагается реализовывать любой элемент пользовательского интерфейса.</p>
<p style="text-align:justify;">Вы не обязаны создавать дистрибутивный пакет, чтобы установить и запустить приложение на Заурусе. Возможно просто перенести исполняемый файл на машинку и запустить из командной строки. Однако, этот способ подходит для отладки программ и некоторых компьютерных маньяков, но не для обычного пользователя. Если вы заинтересованы в распространении своего приложения, вы должны упаковать его в ipk-файл, являющийся упакованным архивом. Пакеты ipk являются стандартным форматом дистрибутива для Зауруса, при установке они просто распаковываются в файловую систему на устройстве. Чтобы создавать ipk-файлы, вы должны знать в общих чертах устройство файловой системы на Qtopia-устройствах.</p>
<p style="text-align:justify;">Сама Qtopia устанавливается в каталог /opt/Qtopia на устройстве. По историческим причинам также имеется каталог /opt/QtPalmtop. Реально это символические ссылки, указывающие на /home/QtPalmtop. На каждом сменном носителе (карте памяти) также создается каталог /opt/QtPalmtop. Приложение может быть установлено в любой из них, поэтому разработчик не должен "привязываться", например, к /opt/Qtopia. На практике это означает, что при пакет должен создаваться так, чтобы при установке он распаковывался в ./opt/QtPalmtop. Точка в начале пути при установке будет заменена инсталлятором на имя соответствующего корневого  каталога. Поступая таким образом, разработчик предоставляет пользователю возможность установки пакета в несколько разных мест (как правило установка в основную память или на одну из карт памяти или жесткий диск).</p>
<p style="text-align:justify;">Внутри /opt/QtPalmtop (и ее аналогов на сменных носителях) может находиться несколько подкаталогов, которые должен знать и использовать разработчик.</p>
<ul>
<li> <strong>./opt/QtPalmtop/bin</strong> предназначен для исполняемых файлов (программ). Это единственное место где гарантированно происходит поиск исполняемых файлов системой запуска Qtopia.</li>
<li> <strong>./opt/QtPalmtop/lib</strong> предназначен для динамических библиотек. И снова, это единственное место, где система будет искать библиотеки. На практике поиск также производится в стандартных юниксовых каталогах /lib и /usr/lib, но устанавливать туда ничего не рекомендуется (например, /lib является частью ROM-памяти, соответственно, вы ничего не можете туда поместить).</li>
<li><strong>./opt/QtPalmtop/apps</strong> содержит конфигурационные файлы для системы запуска. В файле с расширением .desktop, вы говорите системе запуска как нужно вызывать ваше приложение, какую пиктограмму использовать для него, какие особые у него есть особые требования (например, разрешение экрана).</li>
<li> <strong>./opt/QtPalmtop/etc</strong> -- здесь находятся различные файлы данных и конфигурационные файлы.</li>
</ul>
<h3>Инструменты</h3>
<p style="text-align:justify;">Разработку можно вести как на самом Заурусе, так и на десктрпе под Линуксом. В первом случае вам понадобится Developer Image, во втором -- кросс-компилятор. Здесь описывается только первого варианта.</p>
<p style="text-align:justify;"><strong>Developer Image</strong> содержит все необходимые инструменты, заголовочные файлы и документацию, необходимую для разработки программ на C++ прямо на Заурусе.</p>
<p style="text-align:justify;">Кроме Developer Image вам, конечно же, понадобится текстовый редактор. Вы можете пользоваться vim, который находится в Developer Image, либо вы можете использовать vi (elvis), имеющийся в Cacko ROM. Также вы можете поставить Emacs или Jed, использовать встроенный редактор Midnight Commander'а. Существует еще несколько редакторов с графическим интерфейсом (VisiScript, ZEditor). Используйте тот, что вам удобнее.</p>
<h4>Установка</h4>
<p>Скачать dev-image можно, например, с Zaurus User Group (прямая ссылка: <a href="http://www.zaurususergroup.org/UpDownload+index-req-getit-lid-207.phtml">http://www.zaurususergroup.org/UpDownload+index-req-getit-lid-207.phtml</a>)</p>
<p style="text-align:justify;">Далее распакуйте архив и скопируйте файлы <tt>dev_img-1.6</tt> и <tt>image_setup.sh</tt> на карточку. Например, в <tt>/mnt/card/devel</tt>.</p>
<p style="text-align:justify;">Станьте суперпользователем (su), перейдите в каталог <tt>/mnt/card/devel</tt> и выполните следующую команду:</p>
<p><code># image_setup.sh ./dev_img-1.6 /mnt/dev</code></p>
<p style="text-align:justify;">Образ файловой системы смонтирован теперь в /mnt/dev, также настроены все нужные переменные окружения. Выйдите из команды su и перезапустите Qkonsole (в дальнейшем этого делать не надо будет).</p>
<p style="text-align:justify;"><strong>Совет</strong> Скрипт image_setup.sh добавляет строки в файлы /etc/fstab и ~/.profile при каждом запуске. Поэтому после первого удачного запуска я открыл его в редакторе и закоментировал все команды, которые что-либо пишут в эти файлы.</p>
<h4>Структура /mnt/dev</h4>
<p>Что мы теперь имеем? Заглянем в /mnt/dev.</p>
<p style="text-align:justify;">В каталоге bin мы обнаруживаем gcc, make, as и прочие нужные вещи. В usr/bin находим perl и vim.</p>
<p style="text-align:justify;">В каталоге include лежат все нужные заголовочные файлы, а в lib -- динамические библиотеки.</p>
<p style="text-align:justify;">Наконец, в каталоге docs располагается вся нужная нам документация:</p>
<ul>
<li><strong>docs/qt/html/</strong> -- полная документация по Qt от Trolltech</li>
<li><strong>docs/qtopia/</strong> -- документация по Qtopia</li>
<li><strong>docs/sharp/dtm</strong> -- SL Data Manager Class References</li>
<li><strong>docs/BusyBox.html</strong> -- справка по командам BusyBox</li>
</ul>
<h3>Hello, world!</h3>
<p style="text-align:justify;">Давайте начнем с чего-нибудь самого простого, например, с <em>Hello, world!</em>. Почему? Чтобы, во-первых, проверить работоспособность Developer Image, а во-вторых, показать как писать и отлаживать программы на Заурусе.</p>
<p style="text-align:justify;">Запустите Qkonsole, откройте редактор (я обычно сразу открываю две сессии -- в одной запускаю Emacs, в другой запускаю компилятор и саму отлаживаемую программу).</p>
<p>Создайте новый файл с таким содержимым:</p>
<p>Filename: <strong>hello1.cpp</strong></p>
<p>[sourcecode language='cpp']<br />
 #include <stdio .h><br />
 int main(int argc, char **argv)<br />
 {<br />
     printf("Hello, world!\n");<br />
     return 0;<br />
 }<br />
[/sourcecode]</p>
<p>Откомпилируйте его:</p>
<p><code>$ gcc -o hello1.o -c hello1.cpp</code></p>
<p style="text-align:justify;">После компиляции у вас должен появиться файл hello1.o. Затем запустите сборку этого объектного файла со стандартными библиотеками:</p>
<p><code>$ gcc -o hello1 hello1.o</code></p>
<p style="text-align:justify;">Вы можете заметить, что мы могли бы выполнить обе операции за один шаг, но часто лучше разделять фазы компиляции и сборки.</p>
<p style="text-align:justify;">Линкер создал исполняемый файл hello1. Если вы проверите его утилитой file, вы увидите следующее:</p>
<p><code>$ file hello1<br />
hello1: ELF 32-bit LSB executable, ARM, version 1 (ARM),<br />
for GNU/Linux 2.0.0, dynamically linked (uses shared libs), not stripped </code></p>
<p>"Not stripped" означает, что файл содержит отладочную информацию. Команда</p>
<p><code>$ ls -l hello1</code></p>
<p style="text-align:justify;">покажет, что файл занимает 11K -- многовато для программы из нескольких строк. Можно его сжать, выбросив ненужную информацию:</p>
<p><code>$ strip hello1</code></p>
<p>Теперь файл занимает чуть больше двух килобайт.</p>
<p>Запустите его:</p>
<p><code>$ ./hello1<br />
Hello, world!<br />
$</code></p>
<p>Отлично! Все работает.</p>
<p style="text-align:justify;">В реальной работе вы, конечно же, не станете каждый раз вводить все эти команды в терминале. Вы напишите небольшой скрипт, или, более вероятно, Makefile. Мы не будем рассказывать здесь как использовать программу make, так как это часть стандартного процесса разработки на любом Юниксе и в ее использовании на Заурусе нет ничего особенного.</p>
<h3>Простейшая программа с GUI</h3>
<p style="text-align:justify;">Теперь самое время написать "Hello, world!" с использованием графического интерфейса. Ниже приведен исходный текст файла hello2.cpp.</p>
<p>Filename: <strong>hello2.cpp</strong></p>
<p>[sourcecode language='cpp']<br />
 #include <qmainwindow .h><br />
 #include <qpe /qpeapplication.h></p>
<p> int main(int argc, char** argv)<br />
 {<br />
   QPEApplication app(argc, argv);<br />
   QMainWindow* mainWindow = new QMainWindow();<br />
   mainWindow->setCaption("Hello, World!");<br />
   app.showMainWidget(mainWindow);<br />
   return app.exec();<br />
 }<br />
[/sourcecode]</p>
<p style="text-align:justify;">В первой строке функции main создается объект класса QPEApplication. Этот класс описывает модель всего приложения и содержит, среди прочего, код для обработки событий, запуска и остановки. Затем мы создаем главное окно приложения. Класс QMainWindow описывает главное окно, то есть то, которое может иметь меню, панель инструментов и рамку с заголовком. Метод setCaption() вызываемый для главного окна задает текст заголовка. Затем мы говорим, что только что созданное окно будет главным виджетом приложения (виджетом называется любой элемент GUI). Наконец, мы вызываем метод exec() чтобы запустить приложение. Этот метод является главной точкой входа в приложение и не завершается, пока работает приложение.</p>
<p>Давайте теперь откомпилируем его:</p>
<p><code>$ g++ -I/home/QtPalmtop/include -DQT_QWS_EBX -DQT_QWS_CUSTOM \<br />
-DQWS -fno-exceptions -fno-rtti -march=armv4 -mtune=strongarm -o \<br />
hello2.o -c hello2.cpp</code></p>
<p style="text-align:justify;">Не пугайтесь, сейчас вам все станет ясно (а ближе к концу мы расскажем как избежать набора руками таких длинных строк в командном интерпретаторе).</p>
<ul>
<li>Ключ -I сообщает компилятору, что искать заголовочные файлы нужно в /opt/QtPalmtop/include. Этот ключ нужен, чтобы компилятор смог найти qpeapplication.h и qmainwindow.h.</li>
<li>-DQT_QWS_EBX -DQT_QWS_CUSTOM -DQWS определяют необходимые макросы для правильной компиляции заголовочных файлов Qt (и указывают, что мы компилируем для Qtopia).</li>
<li>-march=armv4 -mtune=strongarm -- означают, что мы собираем приложение для архитектуры ARM, точнее для процессоров Strong Arm.</li>
<li>-fno-rtti приказывает компилятору не включать информацию о типах времени исполнения (run-time type information) в откомпилированные классы. Так как классы самой Qtopia откомпилированы без RTTI, включение этой информации в наш код приведет к ошибкам сборки.</li>
</ul>
<p>Теперь соберем приложение:</p>
<p><code>$ g++ -L /opt/QtPalmtop/lib/ -o hello2 hello2.o -lqte -lqpe -ljpeg</code></p>
<p style="text-align:justify;">Ключ -L сообщает линковщику где нужно искать библиотеки, указанные дальше в командной строке:</p>
<ul>
<li>-lqte: содержит классы Qt-embedded, такие как QMainWindow;</li>
<li>-lqpe: содержит классы приложений Qtopia, такие как QPEApplication;</li>
<li>-ljpeg: содержит код для работы с изображениями в формате JPEG.<br />
Несмотря на то, что мы сами не использовали код из последней библиотеки напрямую, некоторые классы из библиотек Qtopia и Qt-embedded вполне могут его использовать. По умолчанию ключ -l указывает на динамические библиотеки, так что задание какой-либо библиотеки (или даже всех имеющихся) практически не увеличит размер исполняемого файла приложения.</li>
</ul>
<p style="text-align:justify;">Если сборка прошла успешно, вы получите исполняемый файл hello2, который при необходимости может быть сжат утилитой strip и запущен из командной строки. При запуске вы увидите новое чистое окно на весь экран с заголовком и кнопкой закрытия. Вы можете закрыть его нажав на кнопку.</p>
<p style="text-align:justify;"><strong>Примечание</strong> Qtopia имеет один неприятный баг. При запуске из командной строки никогда не переключайтесь на Qkonsole или какое-либо другое приложение, пока работает ваша программа. Если вы сделаете это, то при переключении обратно на ваше приложение система перейдет в режим Magnified Screen, но как-то криво: вы увидите только белый экран и как правило ничего более. Если с вами произошла такая неприятность, нажмите несколько раз Cancel и немного подождите -- приложение закроется и экран вернется на место.</p>
<p style="text-align:justify;">Если вы переключились на консоль, лучше и быстрее будет открыть новую сессию и убить ваше приложение командой <tt>kill -9</tt>.</p>
<h3>Более сложная графическая программа</h3>
<p style="text-align:justify;">Теперь пример посложнее. На нем мы покажем основы концепцию слотов и сигналов (одну из самых важных в Qt), а также расскажем как пользоваться компилятором метаобъектов (Meta-Object Compiler, MOC).</p>
<p style="text-align:justify;">В предыдущем примере главное окно приложения было просто экземпляром классы QMainWindow. Оно мало что умело делать, так как мы не добавили никакой новой функциональности в предопределенный объект. В реальном приложении мы должны как минимум создать новый класс окна. Во многих простых приложениях это может быть единственный класс, который нужно определить -- приложение может состоять целиком из одного окна, содержащего все необходимые графические элементы (кнопки, списки и т.п.).</p>
<p style="text-align:justify;">В этом примере мы определим новый класс FrmMain, который будет наследовать QMainWindow. По соглашению, окна Qtopia, которые содержат поля для ввода данных, называются формами (forms). Это слово, обычно в виде Frm, входит в названия классов. У этого окна будет строка меню, содержащая пункт "File", в котором будет находится команда "Quit". Выбор этой команды будет закрывать приложение.</p>
<h4>Интерфейс класса главного окна</h4