This is a program written in C++, using BorlandC 5.0´s Object Windows Library (OWL). I did this for Alejandro, a friend of mine, who needed this for a class about algorithms performance. It runs 7 different sort threads concurrently (Bubble Sort, Insert Sort,Select Sort, Quick Sort, Heap Sort, Merge Sort and Bucket Sort, and displays calculation time and number of basic operations.

Download Sort.zip (Win95/NT only. Linux: Forgive me father...)

Back to erick@the net

And if you want to take a peek to the C++ source file:

/*	Sort. Aplicación para Windows 95 o NT. Evalua el desempeño de 7 diferentes
 * algoritmos:
 * - Algoritmo "Burbujas"
 * - Algoritmo "Insertar"
 * - Algoritmo "Seleccionar"
 * - Algoritmo "Quicksort" o "Rápido"
 * - Algoritmo "Heapsort" o "Montículo"
 * - Algoritmo "Mergesort" o "Mezclar"
 * - Algoritmo "Bucket" o "Casillas"

 * Esta aplicación utiliza las librerias de Object Windows Library, de
 	Borland C 5.0. No podr� compilar este programa con otros compiladores
   (Por ejemplo MS Visual C, o con una versión anterior de Borland que no
   soporte OWL. *

*/

//Sección de "includes" para las librerias que necesitamos.

#include "owl/pch.h"
#include "owl/applicat.h"
#include "owl/framewin.h"
#include "owl/inputdia.h"
#include "owl/static.h"
#include "owl/edit.h"
#include "classlib/thread.h"
#include "stdio.h"
#include "stdlib.h"
#include "values.h"
#include "sort.rh"
#include "alloc.h"
#include "time.h"

#define MAX_VALUE		1000	// Máximo entero aleatorio (Toca limitar por culpa de
									// Bucket Sort

// n: Tamaño de la matriz. Default = 1000 números
int n=1000;

// Scramble crea la matriz de enteros con elementos aleatorios.

void Scramble(int *T){
int i;

	randomize();
	for(i=0;iStatusMessage("Pensando...");
   s=clock();
	do{
   	flag=false; ops++;
      for(i=0;iT[i+1]){
         	t=T[i];			ops++;
            T[i]=T[i+1];	ops+=2;
            T[i+1]=t;		ops+=2;
				flag=true;		ops++;
			}
      }	ops++;
   } while(flag);
   e=clock();
   delay=(e-s)/CLK_TCK*1000;
   sprintf(buf,"Hecho!. Tiempo transcurrido: %6d ms. Operaciones básicas: %d"\
   		,delay,ops);
   dad->StatusMessage(buf);
   return 0;
}

// InsertSortAlgorithm es el thread que implementa el algoritmo "Insertar"

class InsertSortAlgorithm:public SortThread{
public:
	InsertSortAlgorithm(AlgorithmWindow *c):SortThread(c){};
private:
	int Run();
};

// El método Run del thread InsertSortAlgorithm es quien ejecuta el algoritmo

int InsertSortAlgorithm::Run(){
int i,j,t,delay,ops=0;
char buf[256];
clock_t s,e;

   dad->StatusMessage("Pensando...");
   s=clock();
 	for(i=1;i=0 && tStatusMessage(buf);
   return 0;
}

// SelectSortAlgorithm es el thread que implementa el algoritmo "Seleccionar"

class SelectSortAlgorithm:public SortThread{
public:
	SelectSortAlgorithm(AlgorithmWindow *c):SortThread(c){};
private:
	int Run();
};

// El método Run del thread SelectSortAlgorithm es quien ejecuta el algoritmo

int SelectSortAlgorithm::Run(){
int i,j,minj,minx,delay,ops=0;
char buf[256];
clock_t s,e;

   dad->StatusMessage("Pensando...");
   s=clock();
 	for(i=0;iStatusMessage(buf);
   return 0;
}

// QuickSortAlgorithm es el thread que implementa el algoritmo "Rápido"

class QuickSortAlgorithm:public SortThread{
public:
	QuickSortAlgorithm(AlgorithmWindow *c):SortThread(c){};
private:
	int ops;
	int Run();
   void QSort(int lo0,int hi0);
   void QSort();
};
void QuickSortAlgorithm::QSort(int lo0,int hi0){
int lo = lo0;
int hi = hi0;

	if(lo >= hi) {	ops++;
	    return;
	}
	int mid = T[(lo + hi) / 2];	ops++;
	while(lo < hi  && T[lo]!=T[hi]) {	ops+=3;
		while(lo mid) {	ops+=3;
			hi--;	ops++;
      }
      ops++;
	   if(lo < hi) {
			int t = T[lo];	ops++;
			T[lo] = T[hi];	ops++;
			T[hi] = t;	ops++;
	   }
	}
   ops++;
	if (hi < lo ) {
	   int t = hi;	ops++;
		hi = lo;	ops++;
		lo = t;	ops++;
	}
	QSort(lo0, lo);
	QSort(lo==lo0 ? lo+1 : lo, hi0);	ops+=2;
}

void QuickSortAlgorithm::QSort(){
	ops=0;
	QSort(0,n-1);
}

// El método Run del thread QuickSortAlgorithm es quien ejecuta el algoritmo

int QuickSortAlgorithm::Run(){
int delay;
char buf[256];
clock_t s,e;

   dad->StatusMessage("Pensando...");
   s=clock();
   QSort();
   e=clock();
   delay=(e-s)/CLK_TCK*1000;
   sprintf(buf,"Hecho!. Tiempo transcurrido: %6d ms. Operaciones básicas: %d",\
   		delay,ops);

   dad->StatusMessage(buf);
   return 0;
}

// HeapSortAlgorithm es el thread que implementa el algoritmo "Montículo"

class HeapSortAlgorithm:public SortThread{
public:
	HeapSortAlgorithm(AlgorithmWindow *c):SortThread(c){};
private:
	int ops;
	int Run();
   void Heapify();
   void Pushdown(int which,int limit);
};

void HeapSortAlgorithm::Pushdown(int which,int limit){
int t;

  /* we will determine the node's max child */
  int max_child = which * 2;	ops++;

  /* if this is a leaf node (i.e. it has no children) then we're done */
  ops++;
  if (max_child > limit) return;

  /* if it has a second child, make max_child the index of the greater kid */
  ops+=3;
  if (((which * 2) + 1) <= limit){
    ops+=3;
    if (T[max_child] < T[(which * 2) + 1]) { ops+=3;
    	max_child = (which * 2) + 1;
    }
  }

  /* now see if the node in question if greater than its max child... */
  ops++;
  if (T[which] < T[max_child]) {

    /* if it's not, swap them and keep going with the push down */
    t=T[which];T[which]=T[max_child];T[max_child]=t;ops+=3;
    Pushdown(max_child, limit);
  }
}

void HeapSortAlgorithm::Heapify(){

  /* we only have to start at the first node with children */
  int mid = (n-1) / 2;	ops++;
  int i;

  /* work backwards to the top of the heap calling pushdown */
  for (i = mid; i >= 0; i--) { ops+=2;
  	Pushdown(i, n-1);
  }
}

// El método Run del thread HeapSortAlgorithm es quien ejecuta el algoritmo

int HeapSortAlgorithm::Run(){
int i,t,delay;
char buf[256];
clock_t s,e;

   dad->StatusMessage("Pensando...");
   s=clock();
	ops=0;
   Heapify();
   for(i=n-1;i?i--){	ops+=2;
   	t=T[i];	ops++;
      T[i]=T[0];	ops++;
      T[0]=t;	ops++;
      Pushdown(0,i-1);
   }

   e=clock();
   delay=(e-s)/CLK_TCK*1000;
   sprintf(buf,"Hecho!. Tiempo transcurrido: %6d ms. Operaciones básicas: %d",\
   		delay,ops);

   dad->StatusMessage(buf);
   return 0;
}

// MergeSortAlgorithm es el thread que implementa el algoritmo "Seleccionar"

class MergeSortAlgorithm:public SortThread{
public:
	MergeSortAlgorithm(AlgorithmWindow *c):SortThread(c){};
private:
	int Run();
   int ops;
   void MergeSort(int left,int right);
   void merge(int first1,int last1,int first2,int last2);
   void move (int *list1, int first1, int last1, int *list2, int first2);
};

void MergeSortAlgorithm::MergeSort (int left, int right) {
  ops++;
  if (left < right) {
    MergeSort(left, (left+right)/2); ops+=2;
    MergeSort((left+right)/2 + 1, right); ops+=3;
    merge (left, (left+right)/2, (left+right)/2+1, right); ops+=5;
  }
}

void MergeSortAlgorithm::merge (int first1, int last1, int first2, int last2) {
  int *temp;
  int index, index1, index2;
  int num;

  temp=new int[n];

  index = 0;	ops++;
  index1 = first1;	ops++;
  index2 = first2;	ops++;

  num = last1 - first1 + last2 - first2 + 2; ops+=4;

  /*
   *  Merge the two lists back together until one list runs out of
   *  items...
   *
   */

  while ((index1 <= last1) && (index2 <= last2)) { ops+=3;
    ops++;
    if (T[index1] < T[index2]) {
    	temp[index++] = T[index1++]; ops+=3;
    }
    else {
    	temp[index++] = T[index2++]; ops+=3;
    }
  }

  /*
   *  At which point fill in the merged list with the "rest" of the
   *  non exhausted list.
   *
   */
  ops++;
  if (index1 > last1)
    move (T, index2, last2, temp, index);
  else
    move (T, index1, last1, temp, index);


  /* finally move our merged array in temp space to the real array */
  move(temp, 0, num-1, T, first1); ops++;
  delete[] temp;
}


void MergeSortAlgorithm::move (int *list1, int first1, int last1, int *list2,\
		 int first2) {
  while (first1 <= last1){ ops++;
    list2[first2++] = list1[first1++]; ops+=3;
  }
}

// El método Run del thread MergeSortAlgorithm es quien ejecuta el algoritmo

int MergeSortAlgorithm::Run(){
int delay;
char buf[256];
clock_t s,e;

	ops=0;
   dad->StatusMessage("Pensando...");
   s=clock();
	MergeSort(0,n-1);
   e=clock();
   delay=(e-s)/CLK_TCK*1000;
   sprintf(buf,"Hecho!. Tiempo transcurrido: %6d ms. Operaciones básicas: %d",\
   		delay,ops);

   dad->StatusMessage(buf);
   return 0;
}

// BucketSortAlgorithm es el thread que implementa el algoritmo "Seleccionar"

class BucketSortAlgorithm:public SortThread{
public:
	BucketSortAlgorithm(AlgorithmWindow *c):SortThread(c){};
private:
	int Run();
};

// El método Run del thread BucketSortAlgorithm es quien ejecuta el algoritmo

int BucketSortAlgorithm::Run(){
int i,k,delay,ops=0,U[MAX_VALUE];
char buf[256];
clock_t s,e;

   dad->StatusMessage("Pensando...");
   s=clock();

   for(k=0;kStatusMessage(buf);
   return 0;
}

// Constructor de AlgorithmWindow. Dibuja la ventana, el titulo, y le pone la
// caja de status.

AlgorithmWindow::AlgorithmWindow(TWindow *parent,char *title,int x,int y)
	: TWindow(parent){
	Attr.W=500;
	Attr.H=55;
   Attr.X=x;
   Attr.Y=y;
	Attr.Style|=WS_VISIBLE;
	SetBkgndColor(TColor::Sys3dFace);
   TStatic *f=new TStatic(this,0,"frame",0,0,500,55);
   f->Attr.Style|=SS_ETCHEDFRAME;
	new TStatic(this,0,title,5,5,120,15);
   Status=new TEdit(this,0,"Inactivo",10,25,480,20);
	Status->Attr.Style=Status->Attr.Style&~WS_HSCROLL&~WS_VSCROLL;
}

void AlgorithmWindow::StatusMessage(char *m){
Status->Clear();
Status->Insert(m);
}

// La ventana BubbleSortWindow es una AlgorithmWindow más el objeto particular
// BubbleSortAlgorithm, o sea más el thread con el algoritmo respectivo.

class BubbleSortWindow : public AlgorithmWindow{
public:
	BubbleSortWindow(TWindow *parent,char *title,int x,int y);
	BubbleSortAlgorithm *alg;
};

BubbleSortWindow::BubbleSortWindow(TWindow *parent,char *title,int x,int y)
	: AlgorithmWindow(parent,title,x,y){

   alg=NULL;
}

class InsertSortWindow : public AlgorithmWindow{
public:
	InsertSortWindow(TWindow *parent,char *title,int x,int y);
	InsertSortAlgorithm *alg;
};

InsertSortWindow::InsertSortWindow(TWindow *parent,char *title,int x,int y)
	: AlgorithmWindow(parent,title,x,y){

   alg=NULL;
}

class SelectSortWindow : public AlgorithmWindow{
public:
	SelectSortWindow(TWindow *parent,char *title,int x,int y);
	SelectSortAlgorithm *alg;
};

SelectSortWindow::SelectSortWindow(TWindow *parent,char *title,int x,int y)
	: AlgorithmWindow(parent,title,x,y){

   alg=NULL;
}

class QuickSortWindow : public AlgorithmWindow{
public:
	QuickSortWindow(TWindow *parent,char *title,int x,int y);
	QuickSortAlgorithm *alg;
};

QuickSortWindow::QuickSortWindow(TWindow *parent,char *title,int x,int y)
	: AlgorithmWindow(parent,title,x,y){

   alg=NULL;
}

class HeapSortWindow : public AlgorithmWindow{
public:
	HeapSortWindow(TWindow *parent,char *title,int x,int y);
	HeapSortAlgorithm *alg;
};

HeapSortWindow::HeapSortWindow(TWindow *parent,char *title,int x,int y)
	: AlgorithmWindow(parent,title,x,y){

   alg=NULL;
}

class MergeSortWindow : public AlgorithmWindow{
public:
	MergeSortWindow(TWindow *parent,char *title,int x,int y);
	MergeSortAlgorithm *alg;
};

MergeSortWindow::MergeSortWindow(TWindow *parent,char *title,int x,int y)
	: AlgorithmWindow(parent,title,x,y){

   alg=NULL;
}

class BucketSortWindow : public AlgorithmWindow{
public:
	BucketSortWindow(TWindow *parent,char *title,int x,int y);
	BucketSortAlgorithm *alg;
};

BucketSortWindow::BucketSortWindow(TWindow *parent,char *title,int x,int y)
	: AlgorithmWindow(parent,title,x,y){

   alg=NULL;
}
//SortWindow es la ventana principal que contiene a todas las ventanas de
//algoritmos.

class SortWindow : public TWindow{
public:
	SortWindow(TWindow *parent);
   void cmGo();
   void cmSetN();
	BubbleSortWindow *Bubbles;
   InsertSortWindow *Inserts;
   SelectSortWindow *Selections;
   QuickSortWindow *Quickies;
   HeapSortWindow *Heaps;
   MergeSortWindow *Merges;
   BucketSortWindow *Buckets;
   int *T;
   void Paint(TDC& dc,bool erase,TRect& rect);
private:
	TBitmap *b;
   TMemoryDC *memDC;
   TClientDC *mainWinDC;

DECLARE_RESPONSE_TABLE(SortWindow);
};
DEFINE_RESPONSE_TABLE1(SortWindow,TWindow)
	EV_COMMAND(CM_GO,cmGo),
   EV_COMMAND(CM_SETN,cmSetN),
END_RESPONSE_TABLE;

SortWindow::SortWindow(TWindow *parent=0)
	: TWindow(parent){

	T=NULL;
 	SetBkgndColor(TColor::Sys3dFace);
   Attr.W=640;
   Attr.H=480;
   Bubbles=new BubbleSortWindow(this,"Burbujas",5,5);
   Inserts=new InsertSortWindow(this,"Insertar",5,70);
   Selections=new SelectSortWindow(this,"Seleccionar",5,135);
   Quickies=new QuickSortWindow(this,"El Rápido",5,200);
   Heaps=new HeapSortWindow(this,"Montículo",5,265);
   Merges=new MergeSortWindow(this,"Mezclar",5,330);
   Buckets=new BucketSortWindow(this,"Casillas",5,395);
   b=new TBitmap(*GetModule(),IDB_BITMAP);
}

#pragma argsused
void SortWindow::Paint(TDC &dc,bool erase,TRect &rect){
TMemoryDC memDC;

	memDC.SelectObject(*b);
	dc.BitBlt(505, 5, b->Width(),b->He ight(), memDC, 0, 0, SRCCOPY);
}

//cmSetN en respuesta a una selección de menu CM_SETN saca el diálogo para
// introducir N.

void SortWindow::cmSetN() {
char buf[32];
	spri ntf(buf,"%d",n);
	if(TInputDialog(this,"Tamaño de la matriz","Especifique el valor para n:",\
   		buf,sizeof(buf)).Execute()==IDOK)
   	n=atoi(buf);
}

//cmGo en respuesta a la opción de menu Ejecutar (CM_GO) dispara la carrera.

void SortWindow::cmGo(){

	if(Bubbles->alg)
   	delete Bubbles->alg;
	Bubbles->alg=new BubbleSortAlgorithm(Bubbles);
   if(Inserts->alg)
   	delete Inserts->alg;
 	Inserts->alg=new InsertSortAlgorithm(Inserts);
   if(Selections->alg)
   	delete Selections->alg;
   Selections->alg=new SelectSortAlgorithm(Selections);
   if(Quickies->alg)
   	delete Quickies->alg;
   Quickies->alg=new QuickSortAlgorithm(Quickies);
	if(Heaps->alg)
   	delete Heaps->alg;
   Heaps->alg=new HeapSortAlgorithm(Heaps);
	if(Merges->alg)
   	delete Merges->alg;
   Merges->alg=new MergeSortAlgorithm(Merges);
	if(Buckets->alg)
   	delete Buckets->alg;
   Buckets->alg=new BucketSortAlgorithm(Buckets);
	if(T)
   	delete[] T;
	T=new int[n];
	::Scramble(T);
	Bubbles->alg->SetT(T);
   Inserts->alg->SetT(T);
   Selections->alg->SetT(T);
   Quickies->alg->SetT(T);
   Heaps->alg->SetT(T);
   Merges->alg->SetT(T);
   Buckets->alg->SetT(T);
  	Bubbles->alg->Start();
   Inserts->alg->Start();
   Selections->alg->Start();
   Quickies->alg->Start();
   Heaps->alg->Start();
   Merges->alg->Start();
   Buckets->alg->Start();
}

//El objeto de aplicación SortApp representa a la aplicación en si.

class SortApp : public TApplication {
public:
	SortApp():TApplication() {}
void InitMainWindow();
};

void SortApp::InitMainWindow(){

	TFrameWindow *frame=new TFrameWindow(0,"Sort Algorithms",new SortWindow);
   frame->AssignMenu(SORT_MENU);
   SetMainWindow(frame);
   EnableMultiThreading(true);
}



//.. OwlMain es el punto de entrada de la aplicación ObjectWindows.

int OwlMain(int , char* []){
	return SortApp().Run();
}