knightL

sortings

Feb 28th, 2011
266
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 38.57 KB | None | 0 0
  1. ---/sorts.h/---
  2. #ifndef COURSEWORK_H
  3. #define COURSEWORK_H
  4.  
  5. #include <gtk/gtk.h>
  6.  
  7. // координаты левого верхнего угла прямоугольника,в котором будет нарисовано дерево
  8. #define TREEOFFSETX 10
  9. #define TREEOFFSETY 70
  10.  
  11. // координаты левого верхнего угла прямоугольника, в котором будет нарисован массив
  12. #define LINEOFFSETX 20
  13. #define LINEOFFSETY 300
  14. // на сколько вверх и вниз будут выдвигаться элементы массива при обменах
  15. #define RISE 30
  16.  
  17. // сколько должно быть точек в пути при горизонтальном и вертикальном перемещении объекта
  18. #define VCOUNT 10
  19. #define HCOUNT 20
  20.  
  21. // отступ относительно верха окна для текста о текущем действии
  22. #define CENTERTEXTOFFSETY 20
  23. #define CENTERTEXTHEADER "Текущее действие:"
  24. // на каком расстоянии от текста нужно рисовать тень
  25. #define SHADOWOFFSET -1
  26.  
  27. // настройки для рисования легенды:
  28. // отступ, на котором будет рисоватся легенда, относительно правого края
  29. #define LEGENDOFFSETX 5
  30. // положение легенды относительно верха окна
  31. #define LEGENDY 60
  32. // координаты левого верхнего угла прямоугольника, в котором будет рисоваться легенда
  33. #define LEGENDINNEROFFSETX 10
  34. #define LEGENDINNEROFFSETY 10
  35. // ширина легенды
  36. #define LEGENDWIDTH 290
  37. // высота, которая отводится под заголовок в легенде
  38. #define LEGENDHEADERHEIGHT 20
  39. #define LEGENDHEADER "Легенда"
  40.  
  41. // радиус окружности / половина ширины прямоугольника элемента массива и дерева
  42. #define RAD 14
  43. // расстояние между элементами в массиве и на последнем уровне дерева
  44. #define GAP 0
  45.  
  46. // количество элементов в массивах
  47. #define N 26
  48. // массив будет заполнятся случайными значениями из диапазона 0..MOD-1
  49. #define MOD 100
  50.  
  51. // количество состояний, в которых может находится каждый элемент
  52. #define STATECNT 9
  53.  
  54. // задержки между событиями:
  55. // между перемещениями элементов
  56. #define MOVEDELAY 10
  57. // после отрисовки объектов
  58. #define REDRAWDELAY 300
  59. // промежутки между вызовом визуализатора и некоторыми фазами сортировки
  60. #define SORTDELAY 400
  61.  
  62. // ширина и высота окна
  63. #define WIDTH 800
  64. #define HEIGHT 360
  65.  
  66. typedef struct elpath elpath;
  67. typedef struct element element;
  68. typedef struct action action;
  69. typedef enum elstate elstate;
  70. typedef enum actiontype actiontype;
  71. typedef union actionparameter actionparameter;
  72.  
  73. // возможные состояния вершин
  74. enum elstate
  75. {
  76.     normal,
  77.     inplace,
  78.     inheap,
  79.     processed,
  80.     active,
  81.     activeinplace,
  82.     activeinheap,
  83.     activeproc,
  84.     activeinterval
  85. };
  86.  
  87. // варианты действий для визуализатора: подождать, обменять два элемента, поменять состояние элемента и сменить название фазы сортировки
  88. enum actiontype
  89. {
  90.     acsleep,
  91.     acswap,
  92.     acchangestate,
  93.     acchangephase
  94. };
  95.  
  96. // параметры для каждого из действий: сколько ждать, какие элементы менять, какое состояние какому элементу установить и номер фазы
  97. union actionparameter
  98. {
  99.     int time;
  100.     struct
  101.     {
  102.         int id1,id2;
  103.     } swap;
  104.     struct
  105.     {
  106.         int id;
  107.         elstate state;
  108.     } chgst;
  109.     int phase;
  110. };
  111.  
  112. // структура, содержащая информацию о номере элемента, который нужно перемещать и по какой траектории двигать его в массиве и в дереве
  113. struct elpath
  114. {
  115.     GList *linecurve,*treecurve;
  116.     int elnum;
  117. };
  118.  
  119. // элемент это совокупность точки в дереве и массиве, значения, по которому идёт сортировка и состояния, в котором он находится
  120. struct element
  121. {
  122.     GdkPoint linecoord,treecoord;
  123.     int value;
  124.     elstate state;
  125. };
  126.  
  127. // структура, описывающая действия для визуализатора
  128. struct action
  129. {
  130.     actiontype type;
  131.     actionparameter param;
  132. };
  133.  
  134. void init_gc();
  135. void init_sort();
  136. void init_legend();
  137. void draw_element(GtkWidget *w,GdkDrawable *d, element *e);
  138. void draw_text_in_center(gchar * text, GtkWidget *w, GdkDrawable *d, GdkGC *gc, gint xc, gint yc);
  139. void draw_text_in_center_y(gchar * text, GtkWidget *w, GdkDrawable *d, GdkGC *gc, gint x, gint yc);
  140. void draw_legend();
  141. void startmoving(elpath *p1,elpath *p2);
  142. void swap(int idx1,int idx2);
  143. void swapvis(int idx1,int idx2);
  144. void displayphasetxt();
  145. void genline(GdkPoint s, GdkPoint t,int cnt,GList ** l);
  146. void insertswap(int idx1,int idx2);
  147. void insertchangestate(int idx,elstate newstate);
  148. void insertsleep(int t);
  149. void insertchangephase(int np);
  150. void sort(int *array);
  151. void quicksort(int n,int *a,int offset);
  152. GdkPoint getlinecoord(int n);
  153. GdkPoint gettreecoord(int n,int maxh);
  154. elpath makepath(gint idx,GdkPoint listb,GdkPoint liste, gint dy, gint listc1, gint listc2,gint listc3,GdkPoint treep1,GdkPoint treep2, gint treec);
  155. gboolean move(elpath* p);
  156. gboolean expose_event(GtkWidget *w,GdkEvent *e, gpointer data);
  157. gboolean delete_event(GtkWidget *w,GdkEvent *e, gpointer data);
  158. gboolean visualize(gpointer data);
  159.  
  160.  
  161. #endif
  162. ---/sorts.c/---
  163. // По умолчанию компилируется визуализатор QuickSort.
  164. // Чтобы скомпилировать другие визуализаторы, нужно определить один из следующих идентификаторов:
  165. // HEAPSORTA - пирамидальная сортировка, первая фаза которой заключается в проходе по массиву от начала к концу и просеивании элемента вверх
  166. // HEAPSORTB - пирамидальная сортировка, первая фаза которой заключается в проходе по массиву от конца к началу и просеивании элемента вниз
  167. // SHELLSORT - сортировка шелла
  168. // BUBBLESORT - пузырьковая сортировка
  169.  
  170. #include <stdio.h>
  171. #include <stdlib.h>
  172. #include <time.h>
  173. #include <gtk/gtk.h>
  174. #include "sorts.h"
  175.  
  176. GtkWidget *window;
  177. // буффер, в котором будет хранится уже нарисованная легенда
  178. GdkPixmap *legend;
  179. // настройки цветов для рисования фона и переднего плана
  180. GdkGC *gcbg[STATECNT],*gcfg[STATECNT];
  181. // очередь, в которую будут добавляться действия, которые будет необходимо визуализировать; заполняется по мере обычной сортировки массива
  182. GSList *actionqueue=NULL;
  183. // массивы элементов и чисел, которые будут упорядочиваться
  184. element el[N];
  185. int arrv[N];
  186.  
  187. // в зависимости от того, какую сортировку будет визуализировать нам необходимо выводить описания фаз
  188. #if HEAPSORTA || HEAPSORTB
  189. char phasetxt[4][100]={"Построение кучи","Исключение наибольшего элемента","Восстановление кучи","Сортировка окончена"};
  190. #else
  191. char phasetxt[4][100]={"Сортировка","","","Сортировка окончена"};
  192. #endif
  193. // какие типы элементов будут показываться в легенде
  194. #if HEAPSORTA
  195. gboolean legendshow[STATECNT]={TRUE,TRUE,TRUE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE};
  196. #elif HEAPSORTB
  197. gboolean legendshow[STATECNT]={TRUE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE};
  198. #elif SHELLSORT
  199. gboolean legendshow[STATECNT]={TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE,FALSE};
  200. #elif BUBBLESORT
  201. gboolean legendshow[STATECNT]={TRUE,TRUE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE,FALSE};
  202. #else
  203. gboolean legendshow[STATECNT]={TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,FALSE,FALSE,TRUE};
  204. #endif
  205.  
  206. // высота легенды с учётом заголовка и описания элементов
  207. int legendheight;
  208. // описание состояний в легенде
  209. char legendtext[STATECNT][100]={"Обычный","На своём месте","В куче","Обрабатывается","Перемещается","Перемещается на своё место","","","Текущий интервал"};
  210. // номер текущей фазы
  211. int phase;
  212. // сколько элементов ещё нужно переместить
  213. int finished;
  214. // координаты левого верхнего угла легенды
  215. int legx,legy;
  216.  
  217. int main(int argc,char * argv[])
  218. {
  219.     int i;
  220.     int maxh;
  221.  
  222.     gtk_init(&argc,&argv);
  223.     // создаём окно и задаём его размер
  224.     window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
  225.     gtk_widget_set_size_request(window,WIDTH,HEIGHT);
  226.  
  227.     srand(time(0));
  228.     // считаем высоту дерева
  229.     for(maxh=0;(1<<maxh)<=N;maxh++);
  230.     // генерируем массив элементов
  231.     for(i=0;i<N;i++)
  232.     {
  233.         el[i].linecoord=getlinecoord(i);
  234.         el[i].treecoord=gettreecoord(i,maxh);
  235.         arrv[i]=el[i].value=rand()%MOD;
  236.         el[i].state=normal;
  237.     }
  238.  
  239.     gtk_widget_show(window);
  240.  
  241.     // подготавливаем программу к визуализации
  242.     init_gc();
  243.     init_sort();
  244.     init_legend();
  245.     g_signal_connect(G_OBJECT(window),"delete-event",G_CALLBACK(delete_event),NULL);
  246.     g_signal_connect(G_OBJECT(window),"expose-event",G_CALLBACK(expose_event),NULL);
  247.  
  248.     // прорисовываем содержимое окна
  249.     expose_event(window,NULL,NULL);
  250.  
  251.     // запускаем бесконечный цикл
  252.     gtk_main();
  253.     return 0;
  254. }
  255.  
  256.  
  257. void init_gc() // создаём цвета, которыми мы будем рисовать элементы в различных состояниях
  258. {
  259.     GdkColor c;
  260.     gcbg[normal]=gdk_gc_new(window->window);
  261.     gcfg[normal]=gdk_gc_new(window->window);
  262.     gcbg[active]=gdk_gc_new(window->window);
  263.     gcfg[active]=gdk_gc_new(window->window);
  264.     gcbg[inplace]=gdk_gc_new(window->window);
  265.     gcfg[inplace]=gdk_gc_new(window->window);
  266.     gcbg[activeinheap]=gcbg[active];
  267.     gcfg[activeinheap]=gcfg[active];
  268.     gcbg[inheap]=gdk_gc_new(window->window);
  269.     gcfg[inheap]=gdk_gc_new(window->window);
  270.     gcbg[activeinplace]=gdk_gc_new(window->window);
  271.     gcfg[activeinplace]=gdk_gc_new(window->window);
  272.     gcbg[inheap]=gdk_gc_new(window->window);
  273.     gcfg[inheap]=gdk_gc_new(window->window);
  274.     gcbg[activeinplace]=gdk_gc_new(window->window);
  275.     gcfg[activeinplace]=gdk_gc_new(window->window);
  276.     gcbg[processed]=gdk_gc_new(window->window);
  277.     gcfg[processed]=gdk_gc_new(window->window);
  278.     gcbg[activeproc]=gcbg[active];
  279.     gcfg[activeproc]=gcfg[active];
  280.     gcbg[activeinterval]=gcbg[inplace];
  281.     gcfg[activeinterval]=gcfg[inplace];
  282.    
  283.     c.red=255*257;
  284.     c.green=250*257;
  285.     c.blue=173*257;
  286.     gdk_gc_set_rgb_fg_color(gcbg[normal],&c);
  287.    
  288.     c.red=97*257;
  289.     c.green=78*257;
  290.     c.blue=0*257;
  291.     gdk_gc_set_rgb_fg_color(gcfg[normal],&c);
  292.    
  293.     c.red=255*257;
  294.     c.green=255*257;
  295.     c.blue=255*257;
  296.     gdk_gc_set_rgb_fg_color(gcbg[active],&c);  
  297.    
  298.     c.red=118*257;
  299.     c.green=0*257;
  300.     c.blue=0*257;  
  301.     gdk_gc_set_rgb_fg_color(gcfg[active],&c);
  302.        
  303.     c.red=205*257;
  304.     c.green=188*257;
  305.     c.blue=0*257;  
  306.     gdk_gc_set_rgb_fg_color(gcbg[inplace],&c);
  307.    
  308.     c.red=0*257;
  309.     c.green=0*257;
  310.     c.blue=0*257;  
  311.     gdk_gc_set_rgb_fg_color(gcfg[inplace],&c);
  312.    
  313.     c.red=246*255;
  314.     c.green=197*255;
  315.     c.blue=0*255;
  316.     gdk_gc_set_rgb_fg_color(gcbg[inheap],&c);
  317.    
  318.     c.red=97*257;
  319.     c.green=78*257;
  320.     c.blue=0*257;
  321.     gdk_gc_set_rgb_fg_color(gcfg[inheap],&c);
  322.  
  323.     c.red=255*257;
  324.     c.green=255*257;
  325.     c.blue=255*257;
  326.     gdk_gc_set_rgb_fg_color(gcbg[activeinplace],&c);   
  327.    
  328.     c.red=97*257;
  329.     c.green=78*257;
  330.     c.blue=0*257;
  331.     gdk_gc_set_rgb_fg_color(gcfg[activeinplace],&c);
  332.    
  333.     c.red=169*257;
  334.     c.green=255*257;
  335.     c.blue=142*257;
  336.     gdk_gc_set_rgb_fg_color(gcbg[processed],&c);   
  337.    
  338.     c.red=0*257;
  339.     c.green=0*257;
  340.     c.blue=0*257;
  341.     gdk_gc_set_rgb_fg_color(gcfg[processed],&c);
  342.    
  343. }
  344.  
  345. void init_sort() // подготавливаем визуализатор к работе
  346. {
  347.     // устанавливаем в качестве текущей фазы нулевую
  348.     phase=0;
  349.     // говорим, что все элементы перемещены
  350.     finished=0;
  351.     // сортируем массив arrv, чтобы заполнить очередь событий задержками, обменами и т.д.
  352.     sort(arrv);
  353.     // визуализируем очередь
  354.     g_timeout_add(SORTDELAY,(GSourceFunc) visualize,NULL);
  355. }
  356.  
  357. // создаёт легенду в буфере GdkPixmap* legend, инициализируем положение легенды
  358. // и рассчитываем высоту легенды
  359. void init_legend()
  360. {
  361.     int i;
  362.     int legendshowcnt;
  363.     element e;
  364.     legx=-1;
  365.     legy=-1;
  366.     legendshowcnt=0;
  367.     for(i=0;i<STATECNT;i++)
  368.         if(legendshow[i]) legendshowcnt++;
  369.     legendheight=LEGENDINNEROFFSETY+2*RAD*legendshowcnt+GAP*(legendshowcnt-1)+LEGENDINNEROFFSETY+LEGENDHEADERHEIGHT;
  370.     legend=gdk_pixmap_new(window->window,LEGENDWIDTH+2,legendheight+2,-1);
  371.     gdk_draw_rectangle(legend,window->style->bg_gc[GTK_WIDGET_STATE(window)],TRUE,0,0,LEGENDWIDTH+2,legendheight+2);
  372.  
  373.     draw_text_in_center(LEGENDHEADER,window,legend,window->style->black_gc,LEGENDWIDTH/2,LEGENDHEADERHEIGHT/2);
  374.     gdk_draw_rectangle(legend,window->style->white_gc,FALSE,1,LEGENDHEADERHEIGHT,LEGENDWIDTH-1,legendheight-LEGENDHEADERHEIGHT-1);
  375.     gdk_draw_rectangle(legend,window->style->black_gc,FALSE,2,LEGENDHEADERHEIGHT+1,LEGENDWIDTH-1,legendheight-LEGENDHEADERHEIGHT-1);
  376.     e.linecoord.x=LEGENDINNEROFFSETX;
  377.     e.linecoord.y=LEGENDINNEROFFSETY+LEGENDHEADERHEIGHT;
  378.     e.treecoord.x=LEGENDINNEROFFSETX+2*RAD+5;
  379.     e.treecoord.y=LEGENDINNEROFFSETY+LEGENDHEADERHEIGHT;
  380.     e.value=00;
  381.  
  382.     for(i=0;i<STATECNT;i++)
  383.     {
  384.         if(!legendshow[i]) continue;
  385.         e.state=i;
  386.         draw_element(window,legend,&e);
  387.         draw_text_in_center_y(legendtext[i],window,legend,window->style->black_gc,e.linecoord.x+4*RAD+2*GAP+LEGENDINNEROFFSETX,e.linecoord.y+RAD);
  388.         e.linecoord.y+=2*RAD+GAP;
  389.         e.treecoord.y+=2*RAD+GAP;
  390.     }
  391. }
  392.  
  393. // визуализируем очередь actionqueue, последовательно доставая элементы из неё и обробатывая их
  394. gboolean visualize(gpointer data)
  395. {
  396.     action cur;
  397.     while(actionqueue) // пока очередь действий не пустая
  398.     {
  399.         cur=*((action*) actionqueue->data); //получаем действие из головы очереди
  400.         free(actionqueue->data); // освобождаем память выделенную под действие
  401.         actionqueue=g_slist_remove(actionqueue,actionqueue->data); //удаляем первый элемент списка
  402.         switch(cur.type)
  403.         {
  404.         case acsleep:
  405.             //если текущее действие - ждать, то мы добавляем ожидание и прекращаем выполнение этой функции
  406.             g_timeout_add(cur.param.time,(GSourceFunc) visualize,actionqueue);
  407.             return FALSE;
  408.         case acswap:
  409.             //если текущее действие - обмен, мы активируем функцию обмена двух элементов и прекращаем выполнение этой функции
  410.             swapvis(cur.param.swap.id1,cur.param.swap.id2);
  411.             return FALSE;
  412.         case acchangestate:
  413.             //если текущее действие - смена статуса, мы меняем его и перерисовываем элемент
  414.             el[cur.param.chgst.id].state=cur.param.chgst.state;
  415.             draw_element(window,window->window,&(el[cur.param.chgst.id]));
  416.             break;
  417.         case acchangephase:
  418.             //если текущее действие - смена фазы, мы меняем номер текущей фазы и отображаем новый текст
  419.             phase=cur.param.phase;
  420.             displayphasetxt();
  421.             break;
  422.         }
  423.     }
  424.     return FALSE;
  425. }
  426.  
  427. gboolean expose_event(GtkWidget *w, GdkEvent *e, gpointer data) // если необходима перересовка, то перерисуем всё
  428. {
  429.     int i;
  430.     displayphasetxt();
  431.     draw_legend();
  432.     for(i=0;i<N;i++)
  433.     {
  434.         draw_element(w,w->window,&el[i]);
  435.     }
  436.     return TRUE;
  437. }
  438.  
  439. // получаем координаты вершины в дереве
  440. GdkPoint gettreecoord(int n,int maxh)
  441. {
  442.     GdkPoint res;
  443.     int h;
  444.     // определяем слой, в котором находится вершина
  445.     for(h=0;(1<<h)<=n+1;h++);
  446.     // высчитываем по формуле координаты вершины
  447.     res.x=TREEOFFSETX+((1<<(maxh-h))-1)*(2*RAD+GAP)/2.0+( (1<<(maxh-h))*GAP+((1<<(maxh-h)))*2*RAD)*(n-(1<<(h-1))+1);
  448.     res.y=TREEOFFSETY+(h-1)*(2*RAD+GAP);
  449.     return res;
  450. }
  451.  
  452. // получаем координаты вершины в массиве
  453. GdkPoint getlinecoord(int n)
  454. {
  455.     GdkPoint res;
  456.     res.x=LINEOFFSETX+(2*RAD+GAP)*n;
  457.     res.y=LINEOFFSETY;
  458.     return res;
  459. }
  460.  
  461. // отрисовка элемента e в d, используя w для получения PangoContext в draw_text_in_center
  462. void draw_element(GtkWidget *w,GdkDrawable *d, element *e)
  463. {
  464.     // печатаем число в массив s
  465.     char s[10];
  466.     sprintf(s,"%.2d",e->value);
  467.    
  468.     // рисуем элемент массива в виде прямоугольник с рамкой и текстом s
  469.     gdk_draw_rectangle(d,gcbg[e->state],TRUE,e->linecoord.x,e->linecoord.y,2*RAD,2*RAD);
  470.     gdk_draw_rectangle(d,gcfg[e->state],FALSE,e->linecoord.x,e->linecoord.y,2*RAD,2*RAD);
  471.     draw_text_in_center(s,w,d,gcfg[e->state],e->linecoord.x+RAD,e->linecoord.y+RAD);
  472. #if HEAPSORTA || HEAPSORTB
  473.     // если происходит отрисовка дерева, то мы рисуем элемент дерева в виде окружности с рамкой и текстом s
  474.     gdk_draw_arc(d,gcbg[e->state],TRUE,e->treecoord.x,e->treecoord.y,2*RAD,2*RAD,0,64*360);
  475.     gdk_draw_arc(d,gcfg[e->state],FALSE,e->treecoord.x,e->treecoord.y,2*RAD,2*RAD,0,64*360);
  476.     draw_text_in_center(s,w,d,gcfg[e->state],e->treecoord.x+RAD,e->treecoord.y+RAD);
  477. #endif
  478. }
  479.  
  480. // рисуем текст text в d при помощи графического контекста gc с центром в (xc,yc) используя w для получения PangoContext
  481. void draw_text_in_center(gchar * text, GtkWidget *w, GdkDrawable *d, GdkGC *gc, gint xc, gint yc)
  482. {
  483.     PangoContext *context=gtk_widget_create_pango_context(w);
  484.     PangoLayout *layout= pango_layout_new(context);
  485.     gint width,height;
  486.     pango_layout_set_text(layout,text,-1);
  487.     pango_layout_get_pixel_size(layout,&width,&height);
  488.     gdk_draw_layout (d,gc,xc-width/2,yc-height/2,layout);
  489.     g_object_unref(context); g_object_unref(layout);
  490. }
  491.  
  492. // рисуем текст text в d при помощи графического контекста gc с центром по y в yc и координатой по x x
  493. // используя w для получения PangoContext
  494. void draw_text_in_center_y(gchar * text, GtkWidget *w, GdkDrawable *d, GdkGC *gc, gint x, gint yc)
  495. {
  496.     PangoContext *context=gtk_widget_create_pango_context(w);
  497.     PangoLayout *layout= pango_layout_new(context);
  498.     gint width,height;
  499.     pango_layout_set_text(layout,text,-1);
  500.     pango_layout_get_pixel_size(layout,&width,&height);
  501.     gdk_draw_layout (d,gc,x,yc-height/2,layout);
  502.     g_object_unref(context); g_object_unref(layout);
  503. }
  504.  
  505.  
  506. // отрисовать легенду
  507. void draw_legend()
  508. {
  509.     // если легенда уже была нарисована, то очищаем её предыдущее местонахождение
  510.     if(legx>0&&legy>0)
  511.         gdk_window_clear_area(window->window,legx,legy,legx+LEGENDWIDTH,legy+legendheight);
  512.     // устанавливаем новое положение легенды
  513.     legx=window->allocation.width-LEGENDOFFSETX-LEGENDWIDTH;
  514.     legy=LEGENDY;
  515.     // отрисовываем легенду из GdkPixmap *legend по новым координатам
  516.     gdk_draw_drawable(window->window,window->style->fg_gc[GTK_WIDGET_STATE(window)],legend,0,0,legx,legy,-1,-1);
  517. }
  518.  
  519. // отрисовываем описание фазы
  520. void displayphasetxt()
  521. {
  522.     // очищаем верхнюю часть окна
  523.     gdk_window_clear_area(window->window,0,0,window->allocation.width,2*CENTERTEXTOFFSETY+2);
  524.     // рисуем описание фазы с тенью
  525.     draw_text_in_center(phasetxt[phase],window,window->window,window->style->white_gc,window->allocation.width/2+SHADOWOFFSET,CENTERTEXTOFFSETY+SHADOWOFFSET);
  526.     draw_text_in_center(phasetxt[phase],window,window->window,window->style->black_gc,window->allocation.width/2,CENTERTEXTOFFSETY);
  527.     // пишем CENTERTEXTHEADER в той же строке, что и описание фазы, но только слева, а не по центру
  528.     draw_text_in_center_y(CENTERTEXTHEADER,window,window->window,window->style->black_gc,10,CENTERTEXTOFFSETY);
  529. }
  530.  
  531. // начинаем перемещение элементов по путям p1 и p2 ( в каждом пути также хранится номер элемента, который перемещается)
  532. void startmoving(elpath *p1,elpath *p2)
  533. {
  534.     // говорим, что перемещаются ещё 2 элемента
  535.     finished+=2;
  536.     // добавляем два таймера, которые будут периодически вызывать функцию move. В качестве параметра будет передаваться адрес на путь,
  537.     // чтобы его можно было изменять в процессе изменения
  538.     g_timeout_add(MOVEDELAY,(GSourceFunc) move,(gpointer) p1);
  539.     g_timeout_add(MOVEDELAY,(GSourceFunc) move,(gpointer) p2);
  540. }
  541.  
  542. //добавляем в очередь actionqueue события:
  543. //обмен двух элментов
  544. void insertswap(int idx1,int idx2)
  545. {
  546.     action *n=(action*) malloc(sizeof(action));
  547.     n->type=acswap;
  548.     n->param.swap.id1=idx1;
  549.     n->param.swap.id2=idx2;
  550.     actionqueue=g_slist_append(actionqueue,n);
  551. }
  552. //смена состояния элемента
  553. void insertchangestate(int idx,elstate newstate)
  554. {
  555.     action *n=(action*) malloc(sizeof(action));
  556.     n->type=acchangestate;
  557.     n->param.chgst.id=idx;
  558.     n->param.chgst.state=newstate;
  559.     actionqueue=g_slist_append(actionqueue,n);
  560. }
  561. //ожидание t милисекунд
  562. void insertsleep(int t)
  563. {
  564.     action *n=(action*) malloc(sizeof(action));
  565.     n->type=acsleep;
  566.     n->param.time=t;
  567.     actionqueue=g_slist_append(actionqueue,n);
  568. }
  569. //смена текущей фазы
  570. void insertchangephase(int np)
  571. {
  572.     action *n=(action*) malloc(sizeof(action));
  573.     n->type=acchangephase;
  574.     n->param.phase=np;
  575.     actionqueue=g_slist_append(actionqueue,n);
  576. }
  577. //перемещение элемента p->elnum по траектории, указанной в p->linecurve и p->treecurve
  578. gboolean move(elpath* p)
  579. {
  580.     int i;
  581.     GdkPoint lc,tc;
  582.     // получчаем текущие координаты
  583.     lc=el[p->elnum].linecoord;
  584.     tc=el[p->elnum].treecoord;
  585.     // очищаем окно в том месте, где находился элемент
  586.     gdk_window_clear_area(window->window,el[p->elnum].linecoord.x,el[p->elnum].linecoord.y,2*RAD+1,2*RAD+1);
  587.     gdk_window_clear_area(window->window,el[p->elnum].treecoord.x,el[p->elnum].treecoord.y,2*RAD+1,2*RAD+1);
  588.    
  589.     // если мы ещё не исчерпали очередь точек p->linecurve, которая является путём элемента в массиве,
  590.     // то мы достаём из очереди координаты и удаляем первый элемент
  591.     if(p->linecurve!=NULL)
  592.     {
  593.         el[p->elnum].linecoord=*((GdkPoint*) p->linecurve->data);
  594.         free(p->linecurve->data);
  595.         p->linecurve=g_list_remove(p->linecurve,p->linecurve->data);
  596.     }
  597.     // аналогично для элемента в дереве
  598.     if(p->treecurve!=NULL)
  599.     {
  600.         el[p->elnum].treecoord=*((GdkPoint*) p->treecurve->data);
  601.         free(p->treecurve->data);
  602.         p->treecurve=g_list_remove(p->treecurve,p->treecurve->data);
  603.     }
  604.     //перерисовываем все те элементы, которые мы могли затронуть при обмене, кроме своего элемента
  605.     for(i=0;i<N;i++)
  606.     {
  607.         if(i==p->elnum) continue;
  608.         if((el[i].linecoord.x+2*RAD+1>=lc.x&&el[i].linecoord.x<=lc.x+2*RAD+1&&el[i].linecoord.y+2*RAD+1>=lc.y&&el[i].linecoord.y<=lc.y+2*RAD+1)||
  609.            (el[i].treecoord.x+2*RAD+1>=tc.x&&el[i].treecoord.x<=tc.x+2*RAD+1&&el[i].treecoord.y+2*RAD+1>=tc.y&&el[i].treecoord.y<=tc.y+2*RAD+1))
  610.         {
  611.             draw_element(window,window->window,&el[i]);
  612.         }
  613.     }
  614.     if(p->linecurve==NULL&&p->treecurve==NULL)
  615.     {
  616.         //если очередь закончилась, то тогда возвращаем элемент в его обычное состояние
  617.         switch(el[p->elnum].state)
  618.         {
  619.             case activeinplace:
  620.                 el[p->elnum].state=inplace;
  621.                 break;
  622.             case activeinheap:
  623.                 el[p->elnum].state=inheap;
  624.                 break;
  625.             case activeproc:
  626.                 el[p->elnum].state=processed;
  627.                 break;
  628.             default:
  629.                 el[p->elnum].state=normal;
  630.         }
  631.     }
  632.     // рисуем текущий элемент
  633.     draw_element(window,window->window,&el[p->elnum]);
  634.     if(p->linecurve==NULL&&p->treecurve==NULL)
  635.     {
  636.         //если списки закончились, то тогда мы говорим, что перемещаются на один элемент меньше
  637.         // и освобождаем память, которая была занята под путь
  638.         finished--;
  639.         free(p);
  640. //      if(finished==0&&phase==1)
  641. //          phase=2;
  642.         // если мы закончили перемещать все элементы, вызываем визуализацию
  643.         if(finished==0)
  644.             g_timeout_add(SORTDELAY,(GSourceFunc) visualize,NULL);
  645.         return FALSE;
  646.     }
  647.     return TRUE;
  648. }
  649.  
  650. // обменивает два элемента массива arrv и сохраняем в очередь действий этот обмен
  651. void swap(int idx1,int idx2)
  652. {
  653.     int t=arrv[idx1];
  654.     arrv[idx1]=arrv[idx2];
  655.     arrv[idx2]=t;
  656.     insertswap(idx1,idx2);
  657. }
  658.  
  659. // обменивает два элемента массива el, генерирует путь для перемещения элементов и запускает процесс перемещения
  660. void swapvis(int idx1,int idx2)
  661. {
  662.     elpath *p1,*p2;
  663.     int i;
  664.     element t;
  665.     t=el[idx1];
  666.     el[idx1]=el[idx2];
  667.     el[idx2]=t;
  668.     // создаём два пути
  669.     p1=(elpath*) malloc(sizeof(elpath));
  670.     p2=(elpath*) malloc(sizeof(elpath));
  671.     // генерируем путь для вершин idx1 и idx2 соответственно. для вершины idx1 и idx2 в массиве создадим путь вида
  672.     //       ___idx2___
  673.     //       |        /|\
  674.     //      \|/        |
  675.     //-------------------------
  676.     //       |        /|\
  677.     //      \|/        |
  678.     //  ____idx1____
  679.     //
  680.     // и прямой обмен между вершинами в дереве
  681.     *p1=makepath(idx1,el[idx1].linecoord,el[idx2].linecoord,-RISE,VCOUNT,HCOUNT,VCOUNT,el[idx1].treecoord,el[idx2].treecoord,2*VCOUNT+HCOUNT-2);
  682.     *p2=makepath(idx2,el[idx2].linecoord,el[idx1].linecoord,+RISE,VCOUNT,HCOUNT,VCOUNT,el[idx2].treecoord,el[idx1].treecoord,2*VCOUNT+HCOUNT-2);
  683.     switch(el[idx1].state)
  684.     {
  685.         case inplace:
  686.             el[idx1].state=activeinplace;
  687.             break;
  688.         case inheap:
  689.             el[idx1].state=activeinheap;
  690.             break;
  691.         case processed:
  692.             el[idx1].state=activeproc;
  693.             break;
  694.         default:
  695.             el[idx1].state=active;
  696.     }
  697.     switch(el[idx2].state)
  698.     {
  699.         case inplace:
  700.             el[idx2].state=activeinplace;
  701.             break;
  702.         case inheap:
  703.             el[idx2].state=activeinheap;
  704.             break;
  705.         case processed:
  706.             el[idx2].state=activeproc;
  707.             break;
  708.         default:
  709.             el[idx2].state=active;
  710.     }
  711.    
  712.     // запускаем перемещение по путям p1 и p2 соответственно
  713.     startmoving(p1,p2);
  714. }
  715.  
  716. // возвращает в списке l очередь точек, начиная с точки s до t исключительно, разделённый на (cnt-1) вершин
  717. void genline(GdkPoint s, GdkPoint t,int cnt,GList ** l)
  718. {
  719.     GdkPoint m,*c;
  720.     int i;
  721.     m=s;
  722.     for(i=1;i<cnt;i++)
  723.     {
  724.         c=(GdkPoint*) malloc(sizeof(GdkPoint));
  725.         *c=m;
  726.         *l=g_list_append(*l,c);
  727.         m.x=s.x+i*1.0*(t.x-s.x)/(cnt-1);
  728.         m.y=s.y+i*1.0*(t.y-s.y)/(cnt-1);
  729.     }
  730. }
  731.  
  732. // создаёт путь для вершины idx путь в массиве начиная с точки listb до точки liste
  733. // точка сначала поднимется на dy вверх, перемещается до liste.x и опускается на dy вниз.
  734. // на каждом этапе будет соответственно listc1-1, listc2-1 и listc3-1 точки. Также в конце будет добавлена точка t
  735. // для дерева будет создан отрезок из treep1 в treep2 исключительно длинной в treec-1 и добавлена вершина treep2
  736. elpath makepath(gint idx,GdkPoint listb,GdkPoint liste, gint dy, gint listc1, gint listc2,gint listc3,GdkPoint treep1,GdkPoint treep2, gint treec)
  737. {
  738.     GdkPoint s,t,*c;
  739.     elpath res;
  740.     double tx,ty;
  741.     GList *listl=NULL,*treel=NULL;
  742.     int i;
  743.     s=t=listb;
  744.     t.y+=dy;
  745.     genline(s,t,listc1,&listl);
  746.    
  747.     s=listb;
  748.     s.y+=dy;
  749.     t=liste;
  750.     t.y+=dy;
  751.     genline(s,t,listc2,&listl);
  752.    
  753.     s=liste;
  754.     s.y+=dy;
  755.     t=liste;
  756.     genline(s,t,listc3,&listl);
  757.    
  758.     c=(GdkPoint*) malloc(sizeof(GdkPoint));
  759.     *c=t;
  760.     listl=g_list_append(listl,c);
  761.    
  762.     genline(treep1,treep2,treec,&treel);
  763.    
  764.     c=(GdkPoint*) malloc(sizeof(GdkPoint));
  765.     *c=treep2;
  766.     treel=g_list_append(treel,c);
  767.    
  768.     res.linecurve=listl;
  769.     res.treecurve=treel;
  770.     res.elnum=idx;
  771.    
  772.     return res;
  773. }
  774.  
  775. // Один из этапов пирамидальной сортировки. Мы пытаемся поднять вершину наверх.
  776. // Для этого мы сравниваем текущую вершину i  с вершиной (i-1)/2. Если он больше, то мы
  777. // меняем элементы и поднимаемся наверх
  778. void upHeap(int* array, int i)
  779. {
  780.     if(i>0)
  781.     {
  782.         if(array[i]>array[(i-1)/2])
  783.         {
  784.             swap(i,(i-1)/2);
  785.             upHeap(array,(i-1)/2);
  786.         }
  787.     }
  788. }
  789.  
  790. // Один из этапов пирамидальной сортировки. Мы пытаемся опустить вершину вниз.
  791. // Для этого мы определяем наибольшую вершину среди детей i-той вершины и сравниваем. Если наш
  792. // элемент меньше, то мы меняем их и спускаемся вниз
  793. void downHeap(int* array, int i,int cnt)
  794. {
  795.     int child=i*2+1;
  796.     if(child<cnt)
  797.     {
  798.         if(child+1<cnt&&array[child]<array[child+1])
  799.             child++;
  800.         if(array[child]>array[i])
  801.         {
  802.             swap(child,i);
  803.             downHeap(array,child,cnt);
  804.         }
  805.     }
  806. }
  807.  
  808. // упорядочиваем массив array, составляю очередь действий
  809. void sort(int *array)
  810. {
  811.     int i;
  812. #ifdef HEAPSORTA
  813.     //добавляем в очередь смену состояния корня и добавляем задержку
  814.     insertchangestate(0,inheap);
  815.     insertsleep(SORTDELAY);
  816.     for(i=1;i<N;i++)
  817.     {
  818.         //меняем состояние i-той вершины, добавляем задержку и пытаемся просеять эту вершину вверх
  819.         insertchangestate(i,inheap);
  820.         insertsleep(REDRAWDELAY);
  821.         upHeap(array,i);
  822.         insertsleep(SORTDELAY);
  823.     }
  824.     // очищаем состояния всех вершин
  825.     for(i=0;i<N;i++)
  826.     {
  827.         insertchangestate(i,normal);
  828.     }
  829.     insertsleep(SORTDELAY);
  830.     for(i=N-1;i>0;i--)
  831.     {
  832.         // меняем фазу на "Исключение наибольшего элемента", говорим, что первый элемент на месте и меняем его с последним элементом массива
  833.         insertchangephase(1);
  834.         insertchangestate(0,inplace);
  835.         swap(i,0);
  836.         insertchangephase(2);
  837.         insertsleep(REDRAWDELAY);
  838.         //просеиваем новый первый элемент вниз
  839.         downHeap(array,0,i);
  840.         insertsleep(SORTDELAY);
  841.     }
  842.     insertchangestate(0,inplace);
  843.     insertchangephase(3);
  844. #elif HEAPSORTB
  845.     // говорим, что обработали последнюю половину элементов
  846.     for(i=N-1;2*i+1>=N;i--)
  847.     {
  848.         insertchangestate(i,processed);
  849.     }
  850.     for(i=N/2-1;i>=0;i--)
  851.     {
  852.         //меняем состояние i-той вершины и пытаемся просеять её вниз
  853.         insertchangestate(i,processed);
  854.         downHeap(array,i,N);
  855.         insertsleep(SORTDELAY);
  856.     }
  857.     // очищаем состояния всех вершин
  858.     for(i=0;i<N;i++)
  859.     {
  860.         insertchangestate(i,normal);
  861.     }
  862.     insertsleep(SORTDELAY);
  863.     for(i=N-1;i>0;i--)
  864.     {
  865.         // меняем фазу на "Исключение наибольшего элемента", говорим, что первый элемент на месте и меняем его с последним элементом массива
  866.         insertchangephase(1);
  867.         insertchangestate(0,inplace);
  868.         swap(i,0);
  869.         insertchangephase(2);
  870.         insertsleep(REDRAWDELAY);
  871.         //просеиваем новый первый элемент вниз
  872.         downHeap(array,0,i);
  873.         insertsleep(SORTDELAY);
  874.     }
  875.     insertchangestate(0,inplace);
  876.     insertchangephase(3);
  877. #elif SHELLSORT
  878.     int h = 1;
  879.     int prev;
  880.     // в качестве последовательности шагов мы будем рассматривать последовательность 1, 4, 13, 40,...
  881.     while ( h <= N / 9 )
  882.         h = 3 * h + 1;
  883.  
  884.     while ( h > 0 ) {
  885.         // сортируем массив какой-нибудь сортировкой. ниже реализован алгоритм, похожий на сортировку вставками
  886.         for ( i = h; i < N; i++ ) {
  887.             int k;
  888.             // рассмотрим последовательность вершин, которые находятся раньше текущей и расположены на расстоянии h,2*h,3*h,... от ней
  889.             // подсветим их все
  890.             for(k=i;k>=0;k-=h)
  891.                 insertchangestate(k,processed);
  892.             insertsleep(REDRAWDELAY);
  893.             int j;
  894.             prev=i;
  895.             // так как эта последовательность отсортирована, то достаточно перемещать последний элемент массива влево, пока он меньше предыдущего
  896.             for ( j = i; j >= h && array[j - h] > array[j]; j -= h )
  897.             {
  898.                 swap(j,j-h);
  899.             }
  900.             // возвращаем всем вершинам нашей последовательности состояние normal
  901.             for(k=i;k>=0;k-=h)
  902.                 insertchangestate(k,normal);
  903.             insertsleep(REDRAWDELAY);
  904.         }
  905.         h /= 3;
  906.     }
  907.     insertchangephase(3);
  908. #elif BUBBLESORT
  909.     for(i=0;i<N;i++)
  910.     {
  911.         int j;
  912.         for(j=0;j<N-i-1;j++)
  913.         {
  914.             // подсвечиваем j тый и j+1 ый элементы
  915.             insertchangestate(j,processed);
  916.             insertchangestate(j+1,processed);
  917.             insertsleep(REDRAWDELAY);
  918.             if(array[j]>array[j+1])
  919.             {
  920.                 // если они неправильно стоят, меняем их местами
  921.                 swap(j,j+1);
  922.             }
  923.             //возвращаем нормальное состояние элементам
  924.             insertchangestate(j,normal);
  925.             insertchangestate(j+1,normal);
  926.             insertsleep(REDRAWDELAY);
  927.         }
  928.         // говорим, что последний элемент на месте
  929.         insertchangestate(j,inplace);
  930.         insertsleep(REDRAWDELAY);
  931.     }
  932.     insertchangephase(3);
  933. #else
  934.     quicksort(N-1,array,0);
  935.     insertchangephase(3);
  936. #endif
  937. }
  938.  
  939. // сортируем массив a, содержащий n элементов, который является массивом array с пропущенными offset первыми элементами
  940. void quicksort(int n,int *a,int offset)
  941. {
  942.     int i=0,j=n,k;
  943.     int p=a[n>>1];
  944.    
  945.     // подсвечиваем текущий интервал
  946.     for(k=0;k<=n;k++)
  947.     {
  948.         insertchangestate(k+offset,activeinterval);
  949.     }
  950.     insertsleep(REDRAWDELAY);
  951.     insertchangestate(i+offset,processed);
  952.     insertchangestate(j+offset,processed);
  953.     do
  954.     {
  955.         // находим первый элемент с начала массива, который не меньше p
  956.         while(a[i]<p)
  957.         {
  958.             insertchangestate(i+offset,activeinterval);
  959.             i++;
  960.             if(i<=j)insertchangestate(i+offset,processed);
  961.             insertsleep(REDRAWDELAY);
  962.         }
  963.         insertsleep(REDRAWDELAY);
  964.         // находим первый элемент с конца массива, который не больше p
  965.         while(a[j]>p)
  966.         {
  967.             insertchangestate(j+offset,activeinterval);
  968.             j--;
  969.             if(i<=j)insertchangestate(j+offset,processed);
  970.             insertsleep(REDRAWDELAY);
  971.         }
  972.         insertsleep(REDRAWDELAY);
  973.         // если индекс i, который пробегает массив с начала, больше, чем индекс j, который пробегает массив с конца,
  974.         // то обменивать нечего, иначе
  975.         if(i<=j)
  976.         {
  977.             // меняем эти два элемента и перемещаем указатели i и j
  978.             swap(offset+i,offset+j);
  979.             insertchangestate(i+offset,activeinterval);
  980.             insertchangestate(j+offset,activeinterval);
  981.             i++;
  982.             j--;
  983.             if(i<=j)
  984.             {
  985.                 insertchangestate(i+offset,processed);
  986.                 insertchangestate(j+offset,processed);
  987.                 insertsleep(REDRAWDELAY);
  988.             }
  989.         }
  990.     }
  991.     while(i<=j);
  992.     // убираем подсветку активного диапазона
  993.     for(k=0;k<=n;k++)
  994.     {
  995.         insertchangestate(k+offset,normal);
  996.     }
  997.     // если интервал 0..j не состоит из одного элемента, то вызываем quicksort для него
  998.     if(j>0) quicksort(j,a,offset);
  999.     // если интервал i..n не состоит из одного элемента, то вызываем quicksort для него
  1000.     if(i<n) quicksort(n-i,a+i,offset+i);
  1001. }
  1002.  
  1003. //если окно было закрыто, завершаем работу
  1004. gboolean delete_event(GtkWidget *w,GdkEvent *e, gpointer data)
  1005. {
  1006.     gtk_main_quit();
  1007.     return TRUE;
  1008. }
Add Comment
Please, Sign In to add comment