Ćwiczenie laboratoryjne
„Algorytm sortowania przez scalanie”
Sprawozdanie
Na każdym zajęciu laboratoryjnym sporządza się za pomocą edytora Word sprawozdanie.
Bazowa zawartość sprawozdania musi być przygotowana w domu przed ćwiczeniem (sprawozdanie do ćwiczenia pierwszego jest przygotowywane w czasie ćwiczenia).
W czasie ćwiczenia do sprawozdania są dodawane wyniki testowania.
Treść sprawozdania:
strona tytułowa,
spis treści sporządzony za pomocą Word'a,
dla każdego zadania rozdziały "Zadanie ", "Opracowanie zadania" (rozdział z tekstem programu i komentarzami),
"Testowanie" (rozdział z opisem danych wejściowych i wynikami testowania, w tym zrzuty aktywnego okna).
Wzorzec strony tytułowej znajduje się w pliku Strona_tytulowa_niestac_AiSD.doc.
Nazwa (bez polskich liter, żeby można było archiwizować) pliku ze sprawozdaniem musi zawierać skrót "AiSD_", numer grupy, numer ćwiczenia i nazwisko studenta.
Pliki ze sprawozdaniem są przekazywane do archiwum grupy.
Sortowanie przez scalanie Zadanie
Zadanie polega na oprogramowaniu algorytmu sortowania przez scalanie.
Jest to bazowy algorytm przy sortowaniu danych w plikach.
Sortować dane według wariantu z tabeli wariantów.
Wygenerować do pliku 100000 pseudolosowych danych, posortować, zmierzyć i wyświetlić czas sortowania.
Opracowanie zadania
( t e k s t p r o g r a m u )
Testowanie
Sprawdzić swój program na 10 danych.
Zmierzyć czas sortowania 100000 danych.
( p r z e d s t a w i ć z r z u t o k n a i f r a g m e n t y p l i k ó w )
Tabela wariantów Np Typ
danej Zakres danych Na początku tablicy N
p Typ
danej Zakres danych Na początku tablicy 1 liczba 0 .. 99 najmniejszy 17 liczba 0 .. 99 największy 2 liczba -99 .. 99 najmniejszy 18 liczba -99 .. 99 największy 3 liczba 100 .. 199 najmniejszy 19 liczba 100 .. 199 największy 4 liczba -199 .. +199 najmniejszy 20 liczba -199 .. +199 największy 5 liczba 200 .. 299 najmniejszy 21 liczba 200 .. 299 największy 6 liczba -299 ..299 najmniejszy 22 liczba -299 ..299 największy 7 liczba 300 .. 399 najmniejszy 23 liczba 300 .. 399 największy 8 liczba -399 .. +399 najmniejszy 24 liczba -399 .. +399 największy 9 litera A .. G najmniejszy 25 litera A .. G największy 10 litera D .. J najmniejszy 26 litera D .. J największy 11 litera G .. M najmniejszy 27 litera G .. M największy 12 litera J .. P najmniejszy 28 litera J .. P największy 13 litera M .. S najmniejszy 29 litera M .. S największy 14 litera P .. V najmniejszy 30 litera P .. V największy 15 litera S .. Y najmniejszy 31 litera S .. Y największy 16 litera T .. Z najmniejszy 32 litera T .. Z największy
Wskazówki
Opracowanie graficznej części aplikacji Nadać formularzowi nagłówek
„Sortowanie przez scalanie. Autor ... ”.
Wprowadzić do formularza obiekty graficzne do inicjalizacji sortowania (klawisz sterujący).
Programowanie operacji
W procedurach sortowania są potrzebne następujące pliki nagłówkowe:
#include <string.h>
#include <stdio.h>
#include <io.h>
#include <direct.h>
#include <stdlib.h>
#include <time.h>
#include <vcclr.h>
#include <assert.h>
Znaki (litery) muszą być typu int.
Generować i zapisywać znak za pomocą instrukcji:
int znak='A'+(rand()*('Z'-'A'))/RAND_MAX;
sprintf(buf,"%c\n",znak);
fputs(buf,pf0); //zapisywanie bufora
Sortowanie przez scalanie w plikach można realizować w strukturze, która ma nazwę struktury
"trzech plików":
|-<--<--<--<--<---<--<--|
| ->(plik 2)->|
v / (plik 0)-->-->-(plik 1)-->-
^ \ | ->(plik 3)->|
|-<--<--<--<--<---<--<--|
faza scalania faza rozdzielania
Przed sortowaniem dane są przepisywane z pliku 0 (źródłowego) do pliku 1. Po sortowaniu plik 1 występuje jako plik wynikowy.
Proces sortowania zawiera etap (fazę) rozdzielania pliku 1 na dwa pliki 2 i 3 oraz etap (fazę) scalania plików 2 i 3 w plik 1.
Na etapie rozdzielania plik 1 jest dzielony na części rozmiarem rg (od wartości 1), które są zapisywane kolejno do plików 2 i 3. Po scalaniu plików rozmiar posortowanej części jest równy 2*rg, i dlatego w następnym etapie rozdzielania wartość rg zwiększa się o dwa razy.
Proces sortowania będzie zakończony, gdy przed rozdzielaniem wartość rg będzie większa lub równa rozmiarowi pliku 1.
Przytoczona niżej procedura sortuje przez scalanie dane liczbowe.
Procedura scalania danych liczbowych
//--- Implementacja algorytmu sortowania przez scalanie danych liczbowych void SortScalanie(int nn,FILE* pf1,FILE* pf2,FILE* pf3)
{// nn - rozmiar danych wejściowych i wynikowych
// pf1, pf2, pf3 – wskaźniki na struktury FILE już otwartych plików // plik pf1 występuje jako plik źródłowy i wynikowy
int rg=1; //rozmiar grupy liczb w plikach 2 i 3
int rozm1=0,rozm2=0,rozm3=0; //ilości liczb w plikach 1, 2 i 3 char *pch=NULL,*pch2=NULL,*pch3=NULL;
char buf[8],buf2[8],buf3[8];
rozm1=nn;
//----
while (rg<nn) {
//---rozdzielanie---
fseek(pf1,0,SEEK_SET); //ustawienie na początek fseek(pf2,0,SEEK_SET); //ustawienie na początek fseek(pf3,0,SEEK_SET); //ustawienie na początek rozm2=0;
rozm3=0;
bool kier=true; //true ~ kierunek "plik1 --> plik2"; false ~ kierunek "plik1 --> plik3"
for (int poz1=0;poz1<rozm1;poz1++) { //index w pliku 1
pch=fgets(buf,8,pf1);
if (pch!=NULL) {
if (kier) {
fputs(buf,pf2);
rozm2++;
} else {
fputs(buf,pf3);
rozm3++;
} }
else break; //break poz1
if ((poz1%rg)==(rg-1)) kier=!kier;
}
//---scalanie---
fseek(pf1,0,SEEK_SET); //ustawienie na początek fseek(pf2,0,SEEK_SET); //ustawienie na początek fseek(pf3,0,SEEK_SET); //ustawienie na początek rozm1=0;
int maxrozm23=(rozm2>=rozm3)? rozm2: rozm3;
for (int poz=0;poz<maxrozm23;poz+=rg) { //początek grupy w plikach 2 i 3
int i2=0,i3=0;
int liczba2=0,liczba3=0;
bool bPowtor=true; //znacznik powtórzenia bool bOdczyt2=true; //znacznik odczytu z pliku 2 bool bOdczyt3=true; //znacznik odczytu z pliku 3 while (bPowtor)
{
bool bJest2=i2<rg && (poz+i2)<rozm2; //znacznik "jeszcze jest dana"
bool bJest3=i3<rg && (poz+i3)<rozm3; //znacznik "jeszcze jest dana"
if (!bJest2 && !bJest3) break; //break "while (bPowtor)"
if (!bJest2 && bJest3) {//dane tylko w pliku 3
while (bJest3) {
pch3=fgets(buf3,8,pf3);
assert (pch3!=NULL);
fputs(buf3,pf1);
rozm1++;
i3++;
bJest3=i3<rg && (poz+i3)<rozm3; //znacznik "jeszcze jest dana"
}
break; //break "while (bPowtor)"
}
if (bJest2 && !bJest3) {//dane tylko w pliku 2
while (bJest2) {
pch2=fgets(buf2,8,pf2);
assert (pch2!=NULL);
fputs(buf2,pf1);
rozm1++;
i2++;
bJest2=i2<rg && (poz+i2)<rozm2; //znacznik "jeszcze jest dana"
}
break; //break "while (bPowtor)"
} //---
if (bOdczyt2 && bJest2) {//odczyt z pliku 2
pch2=fgets(buf2,8,pf2);
assert(pch2!=NULL);
sscanf(buf2,"%6d",&liczba2);
bOdczyt2=false; //zakaz nowego odczytu }
if (bOdczyt3 && bJest3) {//odczyt z pliku 3
pch3=fgets(buf3,8,pf3);
assert (pch3!=NULL);
sscanf(buf3,"%6d",&liczba3);
bOdczyt3=false; //zakaz nowego odczytu }
//---
if (liczba2<=liczba3) {
fputs(buf2,pf1);//zapisywanie daną z pliku 2 rozm1++;
i2++;
bJest2=i2<rg && (poz+i2)<rozm2; //znacznik "jeszcze jest dana"
if (!bJest2)
{//dane tylko w pliku 3 while (bJest3) {
fputs(buf3,pf1);//zapisywanie daną z pliku 3
rozm1++;
i3++;
bJest3=i3<rg && (poz+i3)<rozm3; //znacznik "jeszcze jest dana"
if (bJest3) {
pch3=fgets(buf3,8,pf3);
assert(pch3!=NULL);
} }
break; //break "while (bPowtor)"
} else
bOdczyt2=true;
} else
{//liczba2>liczba3
fputs(buf3,pf1);//zapisywanie daną z pliku 3 rozm1++;
i3++;
bJest3=i3<rg && (poz+i3)<rozm3; //znacznik "jeszcze jest dana"
if (!bJest3)
{//dane tylko w pliku 2 while (bJest2) {
fputs(buf2,pf1);//zapisywanie daną z pliku 2 rozm1++;
i2++;
bJest2=i2<rg && (poz+i2)<rozm2; //znacznik "jeszcze jest dana"
if (bJest2) {
pch2=fgets(buf2,8,pf2);
assert(pch2!=NULL);
} }
break; //break "while (bPowtor)"
} else
bOdczyt3=true;
}
bPowtor=(i2<rg && (poz+i2)<rozm2) || (i3<rg && (poz+i3)<rozm3);
}//while (bPowtor) }// poz
//--- rg+=rg; // rg=rg*2 }//while (rg<nn) }
Przytoczona niżej procedura sortuje przez scalanie dane znakowe.
Procedura scalania danych znakowych
//--- Implementacja algorytmu sortowania przez scalanie danych znakowych void SortScalanie(int nn,FILE* pf1,FILE* pf2,FILE* pf3)
{// rozmiar nn dla danych wejściowych i wynikowych
// pf1, pf2, pf3 – wskaźniki na struktury FILE już otwartych plików // plik pf1 występuje jako plik źródłowy i wynikowy
int rg=1; //rozmiar grupy znaków w plikach 2 i 3
int rozm1=0,rozm2=0,rozm3=0; //ilości znaków w plikach 1, 2 i 3 char *pch=NULL,*pch2=NULL,*pch3=NULL;
char buf[8],buf2[8],buf3[8];
rozm1=nn;
//----
while (rg<nn) {
//---rozdzielanie---
fseek(pf1,0,SEEK_SET); //ustawienie na początek fseek(pf2,0,SEEK_SET); //ustawienie na początek fseek(pf3,0,SEEK_SET); //ustawienie na początek rozm2=0;
rozm3=0;
bool kier=true; //true ~ kierunek "plik1 --> plik2"; false ~ kierunek "plik1 --> plik3"
for (int poz1=0;poz1<rozm1;poz1++) { //indeks w pliku 1
pch=fgets(buf,8,pf1);
if (pch!=NULL) {
if (kier) {
fputs(buf,pf2);
rozm2++;
} else {
fputs(buf,pf3);
rozm3++;
} }
else break; //break poz1
if ((poz1%rg)==(rg-1)) kier=!kier;
}
//---scalanie---
fseek(pf1,0,SEEK_SET); //ustawienie na początek fseek(pf2,0,SEEK_SET); //ustawienie na początek fseek(pf3,0,SEEK_SET); //ustawienie na początek rozm1=0;
int maxrozm23=(rozm2>=rozm3)? rozm2: rozm3;
for (int poz=0;poz<maxrozm23;poz+=rg) { //początek grupy w plikach 2 i 3
int i2=0,i3=0;
int znak2=0,znak3=0;
bool bPowtor=true; //znacznik powtórzenia bool bOdczyt2=true; //znacznik odczytu z pliku 2 bool bOdczyt3=true; //znacznik odczytu z pliku 3 while (bPowtor)
{
bool bJest2=i2<rg && (poz+i2)<rozm2; //znacznik "jeszcze jest dana"
bool bJest3=i3<rg && (poz+i3)<rozm3; //znacznik "jeszcze jest dana"
if (!bJest2 && !bJest3) break; //break "while (bPowtor)"
if (!bJest2 && bJest3) {//dane tylko w pliku 3
while (bJest3) {
pch3=fgets(buf3,8,pf3);
assert (pch3!=NULL);
fputs(buf3,pf1);
rozm1++;
i3++;
bJest3=i3<rg && (poz+i3)<rozm3; //znacznik "jeszcze jest dana"
}
break; //break "while (bPowtor)"
}
if (bJest2 && !bJest3) {//dane tylko w pliku 2
while (bJest2) {
pch2=fgets(buf2,8,pf2);
assert (pch2!=NULL);
fputs(buf2,pf1);
rozm1++;
i2++;
bJest2=i2<rg && (poz+i2)<rozm2; //znacznik "jeszcze jest dana"
}
break; //break "while (bPowtor)"
} //---
if (bOdczyt2 && bJest2) {//odczyt z pliku 2
pch2=fgets(buf2,8,pf2);
assert(pch2!=NULL);
sscanf(buf2,"%c",&znak2);
bOdczyt2=false; //zakaz nowego odczytu }
if (bOdczyt3 && bJest3) {//odczyt z pliku 3
pch3=fgets(buf3,8,pf3);
assert (pch3!=NULL);
sscanf(buf3,"%c",&znak3);
bOdczyt3=false; //zakaz nowego odczytu }
//---
if (znak2<=znak3) {
fputs(buf2,pf1);//zapisywanie daną z pliku 2 rozm1++;
i2++;
bJest2=i2<rg && (poz+i2)<rozm2; //znacznik "jeszcze jest dana"
if (!bJest2)
{//dane tylko w pliku 3 while (bJest3) {
fputs(buf3,pf1);//zapisywanie daną z pliku 3
rozm1++;
i3++;
bJest3=i3<rg && (poz+i3)<rozm3; //znacznik "jeszcze jest dana"
if (bJest3) {
pch3=fgets(buf3,8,pf3);
assert(pch3!=NULL);
} }
break; //break "while (bPowtor)"
} else
bOdczyt2=true;
} else
{//znak2>znak3
fputs(buf3,pf1);//zapisywanie daną z pliku 3 rozm1++;
i3++;
bJest3=i3<rg && (poz+i3)<rozm3; //znacznik "jeszcze jest dana"
if (!bJest3)
{//dane tylko w pliku 2 while (bJest2) {
fputs(buf2,pf1);//zapisywanie daną z pliku 2 rozm1++;
i2++;
bJest2=i2<rg && (poz+i2)<rozm2; //znacznik "jeszcze jest dana"
if (bJest2) {
pch2=fgets(buf2,8,pf2);
assert(pch2!=NULL);
} }
break; //break "while (bPowtor)"
} else
bOdczyt3=true;
}
bPowtor=(i2<rg && (poz+i2)<rozm2) || (i3<rg && (poz+i3)<rozm3);
}//while (bPowtor) }// poz
//--- rg+=rg; // rg=rg*2 }//while (rg<nn) }