Pull to refresh

Программирование глазами (и руками ) гуманитария. Личный опыт. Немного философии

Reading time 5 min
Views 13K
У каждого, наверное, есть какая-то своя излюбленная тема в IT, помимо повседневной практической работы, приносящей порой лишь хлеб насущный. Может быть, кто-то в свободное время делает мультфильмы или работает над какой-нибудь игрой, может быть, участвует в разработке какого-нибудь социального проекта или просто изучает что-то новое без особенной на то практической нужды, одним словом — делает что-то для себя, так сказать, для души.

Мой скромной опыт программирования привел меня к мысли, что этот род деятельности может быть ценным сам по себе и не иметь конкретных практических целей. Безусловно программирование может приносить творческое удовлетворение и, может быть, кому-то своеобразное эстетическое наслаждение; в конце концов, в любой сфере люди жаждут видеть собственную гармонию. Я, когда-то давно, когда еще едва был знаком с программированием и даже плохо понимал значение слова функция применительно к написанию кода, пошутил, сказав, что программирование это искусство. Это была просто брошенная фраза за дружеским чайным столом. Кто-то подыграл мне, спросив, как я это могу доказать. Я ответил что-то вроде: «не зря же Дональд Кнут свою антологию назвал искусством программирования». А ведь он знает толк в этом.

В то время я относился к программированию, как к сухой трудно понятной мне науке, считая её смесью лингвистики и математики. Конечно, тогда я уже имел представление об HTML, но коды программ я видел только издалека и предпочитал держаться от всего этого подальше. Компьютер — это печатная машинка, энциклопедия, переводчик, иногда игрушка — вот, что такое компьютер для гуманитария, лет так 10-15 назад. Конечно, сюда еще можно включить работу с почтой, может быть, еще пару вещей, но основное назначение компьютера для гуманитария — быть печатной машинкой.

Однако все меняется, когда появляется потребность сделать сайт. Я не знаю, сколько гуманитариев трудится в сфере информационных технологий и сколько из них занимается программированием, но я точно уверен, — нашего брата к написанию кода приводит именно WEB. По крайне мере так было еще совсем недавно. Одного молодого филолога-php-программиста из Сибири я недавно встретил на форуме dapf.ru, и он такой, скорее всего, не единственный. Если копнуть глубже, то можно вспомнить, что создатель языка Perl Ларри Уолл, — у которого 27 сентября день рождения, — лингвист по образованию. Но вернусь к теме искусства.

Своё отношение к уже множество раз упомянутой деятельности в этой заметке я изменил после того, как чисто умозрительно попытался провести параллели между написанием кода и игрой в шахматы (или решением шахматных задач), а также теми эффектами, которые они приносят субъекту действия.

На мой взгляд, общего очень много. К программированию вполне возможно относиться как к своего рода игре, в которой есть место и хитрости, и психологии, и присущей только этой сфере магии. Возможно, о примерах этой магии и говорят опытные программисты, когда рассказывают о том, как получили в наследство код, который почти невозможно поддерживать, но он каким-то чудом работает?!

На мой взгляд, отношение к программированию как к игре, вероятно, может помочь преодолеть ряд психологических барьеров тем людям, которые считают написание кода уделом выпускников и студентов спецвузов. Новому поколению, правда, уже, наверное, не понять того, как наши родители еще лет 20 назад боялись нажать лишний раз не то сочетание клавиш. Теперь многое доступно, нет особенных страхов повредить домашний стационарный ПК, ибо у кого-то в запасе еще есть ноутбук, может быть, два, а под подушкой спрятан планшет. Одним словом — программировать можно не стесняясь…

Поскольку существенные этапы развития программирования прошли мимо меня, а мне всегда хотелось немножко заглянуть в эту сферу — отчасти из любопытства, отчасти в силу некоторых историко-научных интересов, — то я решил, пользуясь свободным временем, немножечко почитать учебник по языку Си Денниса Ритчи и что-нибудь закодировать, что-нибудь потестировать и что-нибудь с чем-нибудь сравнить, чтобы было веселее. Простите, что не буду оригинальным, так как я решил воспроизвести — с использованием стандартных библиотек Си — тот самый алгоритм перестановок, о котором уже писал ранее.

Код получился очень громоздким, так как я старался побольше функций реализовать самостоятельно. Собственно, написание данного кода и было для меня своего рода игрой, так сказать, наслаждением для разума.

Должен добавить, что я бы не стал тревожить сообщество Хабра своим «гуманитарным кодом», а просто опубликовал бы эту заметку без кода и вообще упоминания каких-либо алгоритмов, если бы не один довольно интересный момент: мой длиннющий код с достаточным количеством функций и циклов после компиляции на Linux-системе оказался крайне шустрым. Я даже полез по старым ссылкам, чтобы найти наиболее быстрые реализации на других языках.

По данной ссылке, в самом низу, рекурсивный алгоритм перестановок на awk, который помечен автором как наиболее быстрый.

Я решил сравнить скорость со своим учебным примером и, честно говоря, результаты меня удивили. Для n = 10 awk выдал вот такой результат: real time 1m16.770s (на всякий случай, машина: AMD Phenom T1100 6x)

В итоге: я допил холодный чай, который простоял на столе 2 часа и нажал Enter, так я запустил свой только что откомпилированный код.
Терминал выдал мне: real time 0m13.411s

Си, амиго, — это фантастика!

Код Си. Полный нерекурсивный алгоритм порождения всех перестановок в лексикографическом порядке (если читать справа налево :)).
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

 //This reverse x. Переворачиваем х
char revstring(char * x) {
     
      int i = strlen(x);
      int k=0;
      char c;
 
while( i > k ) {  
         i--;      
         c=x[k];
         x[k]=x[i];
         x[i]=c;
         k++;
             
        }
}
 
//This cut x
  char  subb (char * x, int i) {
               x[i]='\0';   
}
//This cut y
  char  subb2 (char * y, int i) {
               int k = 0;
               while (k != strlen(y)+1) {
                     y[k]=y[i];
                    i++;
                    k++;
              }  
  }
//It gets an argumet like 1234 or abcd. All symbols must be uniqe
        int main (int argc, char *argv[]) {
             if (argc < 2) {
             printf("Enter an argument. Example 1234");
             return 0;         
                      }           
             char b[strlen(argv[1])];
             char a[strlen(argv[1])];
             int ij=0;
             while (ij!=strlen(argv[1])) {
                   a[ij]=argv[1][ij];
                   b[ij]=argv[1][ij];
                   ij++;
                   }
                   a[ij]='\0';
                   b[ij]='\0';
                    revstring(a);
                    printf("%s\n", a);
             int i;
             int j;
             char c;
             
          while (strcmp (a, b) !=0 ) {
          i=1;
 
          while(a[i] > a[i-1]) {
          i++;
          }
          
          j=0;
          while(a[j] < a[i]) {
          j++;    
}
 
      c=a[j];
      a[j]=a[i];
      a[i]=c;
    
      char x[strlen(a)+1];
      char y[strlen(a)+1];
      strcpy(x,a);
      strcpy(y,a);
      subb(x, i);
      
     revstring(x);
   
      subb2(y, i);
      sprintf(a, "%s%s", x,y);       
      printf("%s\n", a);
       
 
   }
 
}


Update:
Код исправлен, сравнение с i-1 больше не приводит к выходу за пределы массива.

Также приятно сознавать, что данная реализация работает по времени сопоставимо (приемлемо, а может, и быстрее для малых n) с рекурсивным алгоритмом на том же Си.
Сравнение проводилось с кодом по следующей ссылке.

Рекурсивный алгоритм выдал время работы для n=11:
real 2m9.213s
user 0m2.920s
sys 0m26.290s
Алгоритм из этой заметки выдал для n=11:
real 2m15.510s
user 0m19.750s
sys 0m34.300s

Для n=10
Рекурсивный:
real 0m11.919s
user 0m0.340s
sys 0m2.390s

Из этой заметки:
real 0m12.128s
user 0m1.490s
sys 0m3.040s
Tags:
Hubs:
+12
Comments 28
Comments Comments 28

Articles