Структуры данных
(на базе C++)
МЕТОДИЧЕСКИЕ МАТЕРИАЛЫ
Выпуск 4
Разработаны и адаптированы
Кишинёв - 2017
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Redactor coordonator
Ion Spinei - conferenţiar unuversitar, doc
Tehnoredactare computerizată
Ion Stîngu
2
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
ОГЛАВЛЕНИЕ
3
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
4
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Определение:
5
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
6
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
protected:
void error(char* message)
{
fprintf(stderr, ”%s”, message);
printf("Press any key to fin...\n");
getch();
exit(1);
}
};
7
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
char name[16];
int year;
double salary;
public:
usual_elem()
{
name[0]='\0';
year=0;
salary=0.0;
}
8
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Упражнения.
1. Перегрузите операцию вставки в классе usual_elem.
2. Перегрузите операцию извлечения в классе usual_elem.
3. Перегрузите непосредственно (без использования функции сравнения cmp()) операции
сравнения в классе usual_elem.
Создадим текстовый файл с именем, например, ”stud.txt”, из которого в дальнейшем будем
считывать информацию для загрузки различных структур данных. Содержимое файла
”stud.txt” будет выглядеть следующим образом:
Green 1987 350.00
Red 1980 450.00
Blue 1981 500.00
Gray 1968 900.00
Orange 1984 550.00
White 1980 600.00
Cyan 1975 800.00
Yellow 1988 300.00
Magenta 1983 600.00
Black 1981 500.00
public:
SD()
{
}
9
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
SD(char* file_name)
{
if(!(pf=fopen(file_name, "rt")))
{
char *mes = new char[5+strlen(file_name)+12+1];
error(strcat(strcat(strcpy(mes,"File "),file_name),
" not found!\n"));
}
}
~SD()
{
if(pf)
fclose(pf);
}
long get_ncomp()
{
return ncomp;
}
void reset_ncomp()
{
ncomp=0;
}
protected:
10
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
2. ТАБЛИЦЫ
Пример 1.
Таблица квадратов натуральных чисел
Ключ Данные
(значение (значение
аргумента) функции)
0 0
1 1
2 4
3 9
4 16
5 25
6 36
11
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
7 0111 07 7
8 1000 10 8
9 1001 11 9
10 1010 12 A
11 1011 13 B
12 1100 14 C
13 1101 15 D
14 1110 16 E
15 1111 17 F
Ключом в данной таблице является значение числа в системе счисления с основанием 10, а
данные несут информацию о значении этого числа в системах счисления с основаниями 2, 8
и 16.
Пример 3:
Таблица символических имен
Ключ Данные
Symbol name Type Value
!!DATE Text ”09/15/15”
??FILENAME Text ”sumvectr”
??TIME Text ”11:28:21”
A10 Near COD:004E
B10 Near COD:00AD
BINSTR Near COD:01A0
C10 Near COD:0105
N Word DATE:0067
NOMBIN Word DATE:02CF
S10 Near COD:0181
Z Byte DATE:0061
ZMAX Byte DATE:005F
ZT Word DATE01F9
12
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
13
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
где i – порядковый номер записи, а pi – вероятность того, что искомая табличная запись
имеет порядковый номер i.
Если искомая запись с равной вероятностью может находиться в любой позиции таблицы,
1
тогда pi , и средняя длина поиска будет равна:
n
n
i 1 n 1 n n
D1 (2.2)
i 1 n n 2 2
public:
table<el>(int NMAX=200)
{
14
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
t=new el[NMAX];
n=0;
}
15
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
int search(el e)
{
int position = -1;
for(int i=0; (position==-1) && i<n ; i++)
if(SD::ncomp++, e==this->t[i])
position=i;
return position;
}
int get_n()
{
return n;
}
};
table<usual_elem> gr("stud.txt");
gr.show("Group:\n","");
char ch='n';
char surname[21];
while(ch!='y')
{
printf("Enter a name to search: ");
scanf(”%s”, surname);
16
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
17
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Done ? (y/n)
Enter a name to search: Purple
No table! The number of comparisons: 10
Done ? (y/n)
В следующем примере функции main() определяется средняя длина поиска для конкретной
простой неупорядоченной таблицы, созданной на основе файла ”stud.txt”.
void main()
{
clrscr();
table<usual_elem> gr("Stud.txt");
gr.show("Group:\n","");
usual_elem sample;
long NCOMP=0;
18
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Как видно из примера, практическая средняя длина поиска 5.5 совпадает с теоретической
(n+1)/2=11/2=5.5.
Упражнения.
1. Перегрузите операцию вставки в классе table.
2. Перегрузите операцию извлечения в классе table.
3. Модифицируйте конструктор с параметрами класса table, так чтобы он определял
количество табличных записей в зависимости от размера файла с исходными данными для
табличных записей.
19
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
public:
tree_like()
{
less=greater=-1;
}
tree_like(char* init_name, int init_year, double init_salary):
usual_elem(init_name, init_year, init_salary)
{
less=greater=-1;
}
int get_less()
{
return less;
}
20
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
int get_greater()
21
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
return greater;
}
22
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
for(int i=1; i<n; i++)
{
int forward=1;
int j=0;
while(forward)
if(t[i]<t[j])
if(t[j].get_less()==-1)
t[j].set_less(i), forward=0;
else
j=t[j].get_less();
else
if(t[i]>t[j])
if(t[j].get_greater()==-1)
t[j].set_greater(i), forward=0;
else
j=t[j].get_greater();
}
}
23
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
int search(el e)
{
int position = -1;
int forward=1;
int i=0;
int cmp_result;
while(forward)
if(SD::ncomp++, (cmp_result=e.cmp(t[i]))==0)
position=i, forward=0;
else
{
if(cmp_result<0)
i=t[i].get_less();
else
i=t[i].get_greater();
if(i==-1)
forward=0;
}
return position;
}
};
24
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
clrscr();
tree_table<tree_like> tree_gr("stud.txt");
tree_gr.show("Group:\n", "");
tree_gr.tree_show("Group:\n", "");
char ch='n';
char surname[21];
while(ch!='y')
{
printf("Enter a name to search: ");
scanf("%s", surname);
tree_like e(surname, 2000, 0.0);
tree_gr.reset_ncomp();
int pos=tree_gr.search(e);
if(pos<0)
{
printf("No table! ");
printf("The number of comparisons: %d\n", tree_gr.get_ncomp());
}
else
{
printf("There are in the position %d. ", pos+1);
printf("The number of comparisons: %d\n", tree_gr.get_ncomp());
}
printf("Done ? (y/n) ");
ch = getch();
printf("\n");
}
}
Group:
1. Green 1987 350.00
2. Red 1980 450.00
3. Blue 1981 500.00
4. Gray 1968 900.00
5. Orange 1984 550.00
6. White 1980 600.00
7. Cyan 1975 800.00
8. Yellow 1988 300.00
9. Magenta 1983 600.00
25
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Group:
1. Green 1987 350.00 [ 2, 1]
2. Red 1980 450.00 [ 4, 5]
3. Blue 1981 500.00 [ 9, 3]
4. Gray 1968 900.00 [ 6, -1]
5. Orange 1984 550.00 [ 8, -1]
6. White 1980 600.00 [ -1, 7]
7. Cyan 1975 800.00 [ -1, -1]
8. Yellow 1988 300.00 [ -1, -1]
9. Magenta 1983 600.00 [ -1, -1]
10. Black 1981 500.00 [ -1, -1]
End of Table. Press any key ...
Enter a name to search: White
There are in the position 6. The number of comparisons: 3
Done ? (y/n)
Enter a name to search: Green
There are in the position 1. The number of comparisons: 1
Done ? (y/n)
Enter a name to search: Black
There are in the position 10. The number of comparisons: 3
Done ? (y/n)
Enter a name to search: Purple
No table! The number of comparisons: 3
Done ? (y/n)
tree_table<tree_like> gr("stud.txt");
gr.tree_show("Group:\n","");
tree_like sample;
long NCOMP=0;
26
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
while(!feof(pf))
if(sample.fscanf_el(pf)>0)
{
gr.reset_ncomp();
if(gr.search(sample)>=0)
NCOMP+=gr.get_ncomp();
}
fclose(pf);
printf("N=%d, NCOMP=%d, ALS=%.2lf", gr.get_n(), NCOMP,
(double)NCOMP/gr.get_n());
printf(", MAX=%.2lf, MIN=%.2lf\n", (gr.get_n()+1)/2.0,
log((double)gr.get_n())/log(2.0)+2.0);
getch();
}
27
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
28
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
error(message);
}
t[i+1]=tmp, n++;
}
fclose(SD::pf) , SD::pf=NULL;
}
// Binary search
int search(el e)
{
int a=0, b=n-1;
int result;
while(a<b)
{
int i=(a+b)/2;
if(SD::ncomp++, (result=e.cmp(t[i]))>0)
a=i+1;
else
if(result<0)
b=i;
else
a=b=i;
}
return (SD::ncomp++, e==t[a])? a : -1;
}
// Fibonaccian search
int fibsearch(el e)
{
int result;
int j=1;
while(fib(j)<n+1)
j++;
int f1=fib(j-2);
int mid=n-f1+1;
int f2=fib(j-3);
int foward=1;
29
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
if(f1==1)
foward=0;
else
{
mid+=f2;
f1-=f2;
f2-=f1;
}
else
if(f2==0)
foward=0;
else
{
mid-=f2;
int t=f1-f2;
f1=f2;
f2=t;
}
protected:
int fib(int n)
{
int res;
if(n==0 || n==1)
res=n;
else
if(n>=2)
res=fib(n-1)+fib(n-2);
return res;
}
};
sorted_table<usual_elem> sorted_gr("stud.txt");
sorted_gr.show("Group:\n", "");
30
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
char ch='n';
char surname[21];
while(ch!='y')
{
printf("Enter a name to search: ");
scanf("%s", surname);
usual_elem e(surname, 2000, 0.0);
sorted_gr.reset_ncomp();
int pos=sorted_gr.search(e);
if(pos<0)
{
printf("No table! ");
printf("The number of comparisons: %d\n", sorted_gr.get_ncomp());
}
else
{
printf("There are in the position %d. ", pos+1);
printf("The number of comparisons: %d\n", sorted_gr.get_ncomp());
}
printf("Done ? (y/n) ");
ch = getch();
printf("\n");
}
}
31
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
на
int pos=sorted_gr.fibsearch(e);
Вариант результата:
Group:
1. Black 1981 500.00
2. Blue 1981 500.00
3. Cyan 1975 800.00
4. Gray 1968 900.00
5. Green 1987 350.00
6. Magenta 1983 600.00
7. Orange 1984 550.00
8. Red 1980 450.00
9. White 1980 600.00
10. Yellow 1988 300.00
End of Table. Press any key ...
Enter a name to search: Black
There are in the position 1. The number of comparisons: 3
Done ? (y/n)
Enter a name to search: Blue
There are in the position 2. The number of comparisons: 4
Done ? (y/n)
Enter a name to search: Cyan
There are in the position 3. The number of comparisons: 2
Done ? (y/n)
Enter a name to search: Gray
There are in the position 4. The number of comparisons: 4
Done ? (y/n)
Enter a name to search: Green
There are in the position 5. The number of comparisons: 3
Done ? (y/n)
Enter a name to search: Magenta
32
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
что для достаточно больших n почти совпадает с теоретическим нижним пределом для
методов поиска, основанных только на сравнении ключей. Теоретически нижний предел
равняется log2(n+1). Двоичный поиск намного эффективнее последовательного просмотра.
Так, для n = 1000, D1 = 500, а D2 = 11.
Для определения средней длины двоичного поиска в упорядоченной таблице, созданной на
основе файла "stud.txt", модифицируем функцию main():
void main()
{
clrscr();
sorted_table<usual_elem> gr("stud.txt");
gr.show("Group:\n","");
usual_elem sample;
long NCOMP=0;
33
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
if(gr.search(sample)>=0)
NCOMP+=gr.get_ncomp();
}
fclose(pf);
printf("N=%d, NCOMP=%d, ALS=%.2lf", gr.get_n(), NCOMP,
(double)NCOMP/gr.get_n());
printf(", ALS_TEOR=%.2lf\n", log((double)gr.get_n())/log(2.0)+2.0);
getch();
}
на
if(gr.fibsearch(sample)>=0)
34
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
небольшое количество записей ищутся очень часто, средняя длина поиска может оказаться
значительно меньше средней длины при двоичном поиске. Это иногда используют при
создании таблиц в трансляторах, например таблица ключевых слов входного языка.
Упорядочение таблиц требует дополнительных временных затрат. Поэтому упорядоченные
таблицы используются как постоянные таблицы транслятора. Иногда упорядочиваются и
временные таблицы, хотя их упорядочение создает некоторые сложности. Проблема состоит
в том, что временные таблицы создаются в процессе трансляции и в большинстве случаев
тут же используются и для поиска. Будучи частично заполненными, такие таблицы требуют
проверки: не была ли включена очередная табличная запись на каком-то из предыдущих
этапов работы транслятора. Поэтому упорядочение временных таблиц необходимо
выполнять одновременно с их заполнением.
Для сокращения временных затрат процессора на упорядочение временных таблиц, иногда
используют секционирование, при котором таблица разбивается на разделы,
соответствующие различным интервалам значений ключей. Разделы упорядочены, а внутри
разделов записи не упорядочиваются. Для поиска записей используется комбинированный
метод. Например, раздел отыскивается двоичным поиском, а внутри раздела используется
последовательный просмотр.
Упражнения.
1. Перегрузите операцию вставки в классе sorted_table.
2. Перегрузите операцию извлечения в классе sorted_table.
3. Замените в классе sorted_table рекурсивный вариант функции fib() на итеративный.
4. Измените в классе sorted_table код функции поиска по методу Fibonacci fibsearch()
так, чтобы она не использовала функцию fib().
35
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
36
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Общие понятия
37
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
При поиске алгоритм всегда детерминирован, если таблица содержит табличную запись с
ключом K, или в векторе есть, по крайней мере, одна свободна позиция. Если ни одно из этих
условий не выполняется, возможно зацикливание, против которого надо применять
специальные меры. Например, ввести счетчик проверенных позиций, если это число
становится больше n, необходимо останавливать работу алгоритма.
Создадим на базе класса usual_elem класс hashing_elem, который будет дополнен функцией
распределения.
//
// C l a s s "h a s h i n g _ e l e m"
//
class hashing_elem : public usual_elem
{
public:
hashing_elem()
{
}
Упражнения.
1. Перегрузите операцию вставки в классе hashing_elem.
38
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
public:
hashing_table<el>(char* file_name, int NMAX=200): table<el>(NMAX)
{
n=NMAX, m=0;
el tmp;
int repeated;
SD::pf=fopen(file_name, "rt");
m=0;
while(!feof(SD::pf))
if(tmp.fscanf_el(SD::pf)>0)
{
int i=tmp.hf(n);
repeated=-1;
while((repeated==-1) && !t[i].free())
{
if(tmp==t[i])
repeated=i;
else
i=(i+1)%n;
}
if(repeated!=-1)
{
char message[60];
char repeated_str[10];
message[0]='\0';
strcat(message,
"Key coincides with the key in the position: ");
strcat(message, itoa(repeated+1, repeated_str, 10));
strcat(message, "!\n");
error(message);
39
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
}
t[i]=tmp;
m++;
}
fclose(SD::pf), SD::pf=NULL;
}
int search(el e)
{
int position=-1;
int i=e.hf(n);
while((position==-1) && !t[i].free())
if(SD::ncomp++, e==t[i])
position=i;
else
i=(i+1)%n;
return position;
}
int get_m()
{
return m;
}
};
char ch='n';
char surname[21];
while(ch!='y')
{
cout << "Enter a name to search: ";
cin >> surname;
hashing_elem e(surname, 2000, 0.0);
hashing_gr.reset_ncomp();
int pos=hashing_gr.search(e);
40
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
if(pos<0)
cout << "No table! " << "The number of comparisons: "
<< hashing_gr.get_ncomp() << "\n";
else
cout << "There are in the position " << (pos+1)
<< ". The number of comparisons: "
<< hashing_gr.get_ncomp() << "\n";
cout << "Done ? (y/n) ";
ch = getch();
cout << endl;
}
}
41
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Done ? (y/n)
00│
01│ Blue, 1981, 500
02│ Red, 1980, 450
”Green”
03│ Cyan, 1975, 800
”Red”
04│ Black, 1981, 500
”Blue”
05│
”Gray”
06│ Green, 1987, 350
”Orange”
07│ Gray, 1968, 900
”White”
08│ White, 1980, 600
”Cyan”
09│ Yellow, 1988, 300
”Yellow”
10│
”Magenta”
11│
”Black”
12│ Magenta,1983, 600
13│
14│ Orange, 1984, 550
Из приведенной таблицы видно, что позиции 0, 5, 10, 11, 13 остались свободными. По ходу
формирования таблицы, в позициях 1, 2, 6, 7 возникали коллизии. Стоит заметить, что
коллизия, возникшая в позиции 7 при занесении записи с ключом White, является вторичной.
Теоретические исследования и практические эксперименты для поиска в методе
распределения с открытым перемешиванием, показали, что при случайном и равномерном
распределении табличных записей по позициям вектора в интервале [0, n-1] при помощи
функции расстановки, средняя длина поиска не зависит от длины таблицы, а зависит только
m
от коэффициента заполненности , где m – длина таблицы, а n – длина вектора в
n
который эта таблица отображается.
Это очень важное свойство, особенно для больших таблиц. Детерминированные таблицы,
как упорядоченные, так и неупорядоченные, не обладают таким свойством. В
детерминированных таблицах средняя длина поиска растет с ростом длины таблицы.
2
Приближенная формула D( ) , для средней длины поиска при открытом
2 2
перемешивании дает достаточное совпадение с экспериментальными данными для σ≤0,85.
Формула получена в предположении случайного и равномерного распределения табличных
записей по позициям вектора отображения.
Следующая таблица демонстрирует зависимость средней длины поиска от коэффициента
заполненности σ.
42
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
hashing_elem sample;
long NCOMP=0;
43
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
44
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Primary Secondary
Table Table
00│ │ 00|Gray, 1968,900│
01│Blue, 1981,500│02 01│Cyan, 1975,800│
02│Red, 1980,450│01 02│Black, 1981,500|
”Green”
03│ │ 03│ │
”Red”
04│ │ 04│ │
”Blue”
05│ │ 05│ │
”Gray”
06│Green, 1987,350│00 06│ │
”Orange”
07│White, 1980,600│ 07│ │
”White”
08│ │ 08│ │
”Cyan”
09│Yellow,1988,300│ 09│ │
”Yellow”
10│ │ 10│ │
”Magenta”
11│ │ 11│ │
”Black”
12│Magenta,1983,600│ 12│ │
13│ │ 13│ │
14│Orange,1984,550│ 14│ │
m 1
Dm, n 1 , n – длина вектора отображения, m – длина таблицы.
2n
Для демонстрации работы с таблицами распределения с внешними цепочками, в первую
очередь, объявляем класс hashing_linked_elem как производный от класса usual_elem и
дополненный полем next, для создания связных цепочек.
//
// C l a s s "h a s h i n g _ l i n k e d _ e l e m"
//
class hashing_linked_elem: public usual_elem
{
protected:
int next;
public:
hashing_linked_elem()
{
next = -1;
}
45
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
int get_next()
{
return next;
}
Упражнения.
1. Перегрузите операцию вставки в классе hashing_linked_elem.
2. Перегрузите операцию извлечения в классе hashing_linked_elem.
46
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
public:
extern_hashing_table<el>(char* file_name, int init_n=0): SD(file_name)
{
n=init_n;
if(n<=0)
n=countn();
t=new el[n];
v=new el[n];
m=0;
el tmp;
int repeated, position;
while(!feof(SD::pf))
if(tmp.fscanf_el(SD::pf)>0)
{
int i=tmp.hf(n);
if(t[i].free())
{
t[i]=tmp;
m++;
}
else
{
repeated=-1;
if( tmp==t[i] )
{
repeated=i;
t[i].show("", " !!!\n");
}
47
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
else
{
if(t[i].get_next()==-1)
{
int j=0;
while(!v[j].free())
j++;
t[i].set_next(j);
v[j]=tmp;
m++;
}
else
{
i=t[i].get_next();
position=-1;
while((repeated==-1) && position==-1)
{
if( tmp==v[i] )
{
repeated=i;
v[i].show("", " !!!\n");
}
else
if(v[i].get_next()==-1)
{
position=i+1;
while(!v[position].free())
position++;
v[i].set_next(position);
v[position]=tmp;
m++;
}
else
i=v[i].get_next();
}
}
}
if ( repeated!=-1 )
{
char message[60];
char repeated_str[10];
message[0]='\0';
48
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
49
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
if(!ending)
ending="\n";
printf("%s", opening);
for(int i=0; i<n; i++)
{
if(i>0 && i% nlinepp==0)
{
printf("%s", "Press any key to continue ...\n");
getch();
clrscr();
printf("%s", opening);
}
printf("%4d. ", (i+1)); t[i].hashing_linked_show();
}
printf("%s", ending);
printf("End of Table. Press any key ...\n");
getch();
}
50
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
int search(el e)
{
int position=-1;
int i=e.hf(n);
if(!t[i].free())
if(SD::ncomp++, e==t[i])
position=i;
else
if((i=t[i].get_next())!=-1)
do
{
if(SD::ncomp++, e==v[i])
position=i;
else
i=v[i].get_next();
}
while((position==-1) && (i!=-1));
return position;
}
int get_n()
{
return n;
}
int get_m()
{
return m;
}
protected:
int countn()
{
return 200;
}
};
51
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
clrscr();
char ch='n';
char surname[21];
while(ch!='y')
{
printf("Enter a name to search: ");
scanf("%s", surname);
hashing_linked_elem e(surname, 2000, 0.0);
ex_hashing_gr.reset_ncomp();
int pos=ex_hashing_gr.search(e);
if(pos<0)
{
printf("No table! ");
printf("The number of comparisons: %d\n", ex_hashing_gr.get_ncomp());
}
else
{
printf("There are in the position %d. ", pos+1);
printf("The number of comparisons: %d\n", ex_hashing_gr.get_ncomp());
}
printf("Done ? (y/n) ");
ch = getch();
printf("\n"); }
}
52
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
12.
13. Magenta 1983 600.00 [ -1]
14.
15. Orange 1984 550.00 [ -1]
End of Table. Press any key ...
Secondary table:
1. Gray 1968 900.00 [ -1]
2. Cyan 1975 800.00 [ -1]
3. Black 1981 500.00 [ -1]
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
End of Table. Press any key ...
Enter a name to search: White
There are in the position 8. The number of comparisons: 1
Done ? (y/n)
Enter a name to search: Green
There are in the position 7. The number of comparisons: 1
Done ? (y/n)
Enter a name to search: Black
There are in the position 3. The number of comparisons: 2
Done ? (y/n)
Enter a name to search: Purple
No table! The number of comparisons: 0
Done ? (y/n)
53
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
hashing_linked_elem sample;
long NCOMP=0;
54
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
while(!feof(pf))
if(sample.fscanf_el(pf)>0)
{
ex_hashing_gr.reset_ncomp();
if(ex_hashing_gr.search(sample)>=0)
NCOMP+=ex_hashing_gr.get_ncomp();
}
fclose(pf);
printf("m=%d, n=%d, NCOMP=%d, ALS=%.2lf", ex_hashing_gr.get_m(),
ex_hashing_gr.get_n(), NCOMP, (double)NCOMP/ex_hashing_gr.get_m());
printf(", D(m/n)=%.2lf\n",
1.+(ex_hashing_gr.get_m()-1.)/(2.*ex_hashing_gr.get_n()));
getch();
}
55
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
9.
10.
11.
12.
13.
14.
15.
End of Table. Press any key ...
m=10, n=15, NCOMP=13, ALS=1.30, D(m/n)=1.30
Упражнения.
1. Перегрузите операцию вставки в классе extern_hashing_table.
2. Перегрузите операцию извлечения в классе extern_hashing_table.
56
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
00│Black, 1981,500│
01│Blue, 1981,500│00
02│Red, 1980,450│03
”Green”
03│Cyan, 1975,800│
”Red”
04│Gray, 1968,900│
”Blue”
05│ │
”Gray”
06│Green, 1987,350│04
”Orange”
07│White, 1980,600│
”White”
08│ │
”Cyan”
09│Yellow,1988,300│
”Yellow”
10│ │
”Magenta”
11│ │
”Black”
12│Magenta,1983,600│
13│ │
14│Orange,1984,550│
57
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
отображения могут быть заполнены (т.е. m=n), а средняя длина поиска при случайном и
однородном распределении не превысит 1.5.
Для демонстрации работы с таблицами организованными по методу распределения с
внутренними цепочками переполнения, создадим на базе абстрактного класса SD шаблонный
класс extern_hashing_table, который позволит нам создавать таблицы по методу
распределения с внутренними цепочками переполнения.
//
// C l a s s "i n t e r n _ h a s h i n g _ t a b l e"
// m/n
template <class el> class intern_hashing_table: public SD
{
protected:
int n;
int m;
el *t;
el *v;
public:
intern_hashing_table<el>(char* file_name, int init_n=0): SD(file_name)
{
n=init_n;
if(n<=0)
n=countn();
t=new el[n];
v=new el[n];
m=0;
el tmp;
int i, j;
int repeated, position;
while(!feof(SD::pf))
if(tmp.fscanf_el(SD::pf)>0)
{
i=tmp.hf(n);
if(t[i].free())
{
t[i]=tmp;
m++;
}
else
{
repeated=-1;
if( tmp==t[i] )
58
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
repeated=i;
t[i].show("", " !!!\n");
}
else
{
if(t[i].get_next()==-1)
{
j=0;
while(!v[j].free())
j++;
t[i].set_next(j);
v[j]=tmp;
m++;
}
else
{
i=t[i].get_next();
position=-1;
while((repeated==-1) && position==-1)
{
if( tmp==v[i] )
{
repeated=i;
v[i].show("", " !!!\n");
}
else
if(v[i].get_next()==-1)
{
position=i+1;
while(!v[position].free())
position++;
v[i].set_next(position);
v[position]=tmp;
m++;
}
else
i=v[i].get_next();
}
}
}
if ( repeated!=-1 )
59
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
char message[60];
char repeated_str[10];
message[0]='\0';
//strcat(message, "Key coincides with the key in the position: ");
//strcat(message, itoa(repeated+1, repeated_str, 10));
//strcat(message, "!\n");
strcat(message, "Key coincides !!!\n");
error(message);
}
}
}
fclose(SD::pf), SD::pf=NULL;
el empty;
int k=0;
for(j=0; j<n; j++)
if(!v[j].free())
{
i=v[j].hf(n);
int j1=j;
do
{
while(!t[k].free())
k++;
t[i].set_next(k);
i=k;
t[i]=v[j1];
t[i].set_next(-1);
int jtmp=j1;
j1=v[j1].get_next();
v[jtmp]=empty;
}
while (j1!=-1);
}
delete v;
}
60
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
clrscr();
if(!opening)
opening="";
if(!ending)
ending="\n";
printf("%s", opening);
for(int i=0; i<n; i++)
{
if(i>0 && i% nlinepp==0)
{
printf("Press any key to continue ...\n");
getch();
clrscr();
printf("%s", opening);
}
printf("%4d. ", (i+1)); t[i].show();
}
printf("%s", ending);
printf("End of Table. Press any key ...\n");
getch();
}
61
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
}
printf("%s", ending);
printf("End of Table. Press any key ...\n");
getch();
}
int search(el e)
{
int position=-1;
int i=e.hf(n);
if(!t[i].free())
do
{
if(SD::ncomp++, e==t[i])
position=i;
else
i=t[i].get_next();
}
while((position==-1) && (i!=-1));
return position;
}
int get_n()
{
return n;
}
int get_m()
{
return m;
}
protected:
int countn()
{
return 200;
}
};
62
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
clrscr();
char ch='n';
char surname[21];
while(ch!='y')
{
printf("Enter a name to search: ");
scanf("%s", surname);
hashing_linked_elem e(surname, 2000, 0.0);
in_hashing_gr.reset_ncomp();
int pos=in_hashing_gr.search(e);
if(pos<0)
{
printf("No table! ");
printf("The number of comparisons: %d\n", in_hashing_gr.get_ncomp());
}
else
{
printf("There are in the position %d. ", pos+1);
printf("The number of comparisons: %d\n", in_hashing_gr.get_ncomp());
}
printf("Done ? (y/n) ");
ch = getch();
printf("\n");
}
}
63
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
12.
13. Magenta 1983 600.00 [ -1]
14.
15. Orange 1984 550.00 [ -1]
End of Table. Press any key ...
Enter a name to search: White
There are in the position 8. The number of comparisons: 1
Done ? (y/n)
Enter a name to search: Green
There are in the position 7. The number of comparisons: 1
Done ? (y/n)
Enter a name to search: Black
There are in the position 5. The number of comparisons: 2
Done ? (y/n)
Enter a name to search: Purple
No table! The number of comparisons: 1
Done ? (y/n)
64
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
hashing_linked_elem sample;
long NCOMP=0;
getch();
}
65
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Функции распределения
Время вычисления функции расстановки f(k) входит в среднее время поиска, это необходимо
учитывать при выборе алгоритма реализации функции расстановки.
Хорошая функция расстановки должна обеспечивать равномерное распределение табличных
записей по позициям вектора отображения, т.к. неравномерное распределение увеличивает
среднее время поиска. Однако если вычисление значений функции расстановки будет
требовать выполнения слишком большого количества операций, это может свести на нет всю
экономию, полученную за счет равномерности. Т.е. алгоритм вычисления функции
расстановки не должен быть слишком сложным. Рассмотрим несколько способов реализации
функции расстановки:
66
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
67
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
3. СОРТИРОВКА
68
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Из этой формулы следует, что величины n-1, n, 2n, n+3 имеют один и тот же порядок O(n). А
величина n2 имеет более высокий порядок.
Алгоритм сортировки n элементов, основанный на сравнении ключей имеет минимальную
сложность O(n) или выше.
Покажем это посредством математической индукции:
Для k = 2 – одно сравнение. Предположим, что для k = n-1 требуются n-2 сравнения.
Добавим еще один элемент, тогда необходимо выполнит еще, по крайней мере, одно
сравнение, получаем n-2+1 = n-1 сравнений. Таким образом, минимальная сложность имеет
порядок O(n).
Теоретически доказано [см. 1], что средняя сложность любого алгоритма сортировки,
который оперирует сравнением ключей, не может быть меньше, чем O(nlog2n).
У тривиальных алгоритмов сортировки, основанных на сравнении ключей, как
максимальная, так и средняя сложности имеют порядок O(n2).
69
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
70
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
public:
vector<el>(int NMAX=200)
{
n=NMAX;
t=new el[n];
}
virtual void show(const char* opening, const char* ending, int nlinepp=20)
{
clrscr();
if(!opening)
opening="";
printf("%s", opening);
if(!ending)
ending="\n";
for(int i=0; i<n; i++)
{
if(i>0 && i%nlinepp==0)
71
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
printf("Press any key to continue...\n");
getch();
clrscr();
printf("%s", opening);
}
printf("%4d. ", (i+1));
t[i].show("", "\n");
}
printf("%s", ending);
printf("End of vector. Press any key ...\n");
getch();
}
int search(el e)
{
int position = -1;
for(int i=0; (position==-1) && i<n ; i++)
if(SD::ncomp++, e==this->t[i])
position=i;
return position;
}
int get_n()
{
return n;
}
long get_ncomp()
{
return SD::ncomp;
}
void reset_ncomp()
{
SD::ncomp=0;
}
protected:
72
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
el tempor=t[i];
t[i]=t[j];
t[j]=tempor;
}
};
Упражнения.
1. Перегрузите операцию вставки в классе vector.
2. Перегрузите операцию извлечения в классе vector.
73
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
void bubble_sort()
{
BOOLEAN inversion;
do
{
inversion = FALSE;
for(int i=0; i<n-1; i++)
if(ncomp++, t[i]>t[i+1])
{
swap(i,i+1);
inversion = TRUE;
}
}
while (inversion);
}
74
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
75
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
protected:
void quicksort_intern(int i, int j);
int divide(int i, int j);
};
76
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
imain-1 imain+1
0 imain n-1
справа от главного (получают индексы >imain). Что касается элементов с ключами равными
ключу главного, то часть из них может быть размещена слева от главного, а часть – справа.
Имеем типично рекурсивный случай:
параметризация: обрабатывается подвектор t[i]÷t[j]; изначально i=0, j=n-1;
тривиальный случай: i=j (нечего сортировать);
переход от сложного случая к более простому, который возможен благодаря функции
divide().
При наличии такой функции divide(), быстрая сортировка запишется в рекурсивной форме
следующим образом:
template <class el>
void vector_quicksort<el>::quicksort_intern(int i, int j)
{
if (j>i)
{
int imain=divide(i,j);
quicksort_intern(i,imain-1);
quicksort_intern(imain+1,j);
}
}
Просматриваем подвектор слева направо и справа налево до тех пор, пока слева не будет
найден элемент с ключом большим, чем ключ главного элемента, а справа не будет найден
элемент с ключом меньшим, чем ключ главного элемента. После этого меняем местами эти
два элемента, ликвидируя тем самым соответствующую инверсию. Далее продолжаем такой
77
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Выбор гланого элемента должен осуществляться так, что бы вероятность случая, когда после
деления левый и правый отрезки существенно различаются по длине, была бы как можно
меньше.
Первая стратегия: при каждом делении главный элемент выбирается случайным образом
среди позиций i, i+1, …, j. Недостаток этого метода – дополнительные расходы времени на
вызов и работу функции-генератора случайных чисел.
Вторая стратегия: в качестве главного элемента выбирается элемент со срединным
значением ключа, среди небольшой выборки из элементов подвектора, подлежащего
делению. Проще всего взять набор из трех элементов с индексами соответственно i, j и
(i+j)/2.
Оба этих метода уменьшают вероятность катастрофического случая O(n2), однако такая
ситуация не исключается. Быстрая сортировка всегда может деградировать. Парадокс
состоит в том, что, являясь одним из лучших алгоритмов внутренней сортировки, быстрая
сортировка не может быть использована при решении задач, в которых верхнее ограничение
сложности сортировки равное knlog2n является непременным.
Алгоритм деления
Существует множество вариантов деления. Все они преследуют, по крайней мере, две цели:
ускорить внутренние циклы;
предусмотреть “случайный” характер вектора. Т.е. исключить случайное внесение
порядка среди элементов подвекторов (отрезков), получаемых в результате деления,
заботясь о производительности алгоритма в целом. Необходимо отказываться от соблазна
попутной сортировки в процессе деления.
Р. Седжвик (Sedgewick R. E.) предложил следующий метод деления:
a) устанавливаем главный элемент в позицию i (меняя его местами, в случае
необходимости, с элементом t[i]).
i i+1 j
78
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
b) делим подвектор t[i+1], t[i+2],… t[j], при помощи значения ключа главного
элемента t[i], оставляя t[i] на своем месте. Получается разделение с промежуточной
позицией, например, imain:
imain-1 imain+1
i imain j
c) меняем местами элемент t[i] с элементом t[imain] и выдаем значение imain как
результат, возвращаемый функцией divide().
imain-1 imain+1
i imain j
if(imain > i)
swap(i, imain);
imain = i+1, jmain = j;
while(imain < jmain)
{
79
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
проверяет каждый элемент вектора t[0], t[i],… t[n-1] не более двух раз, а остальные
операции выполняются за фиксированное время.
В функции main() создаем вектор и сортируем его методом quicksort:
void main()
{
clrscr();
vector_quicksort<usual_elem> gr("Stud.txt");
gr.show("Unsorted group:\n","");
gr.quicksort();
gr.show("Group sorted by name:\n","");
printf("n=%d, ncomp=%d, n*log2(n)=%.2lf, n*n=%.0lf\n",
gr.get_n(),gr.get_ncomp(),
gr.get_n()*log((double)gr.get_n())/log(2.0),
(double)gr.get_n()*gr.get_n());
getch();
}
80
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Для сортировки по году рождения, создадим на базе класса usual_elem класс year_elem, в
котором переопределим функцию cmp().
//
// C l a s s "y e a r _ e l e m"
//
class year_elem : public usual_elem
{
public:
year_elem()
{
}
81
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
vector_quicksort<year_elem> gr("Stud.txt");
gr.show("Unsorted group:\n","");
gr.quicksort();
gr.show("Group sorted by year:\n","");
printf("n=%d, ncomp=%d, n*log2(n)=%.2lf, n*n=%.0lf\n",
gr.get_n(),gr.get_ncomp(),
gr.get_n()*log((double)gr.get_n())/log(2.0),
(double)gr.get_n()*gr.get_n());
getch();
}
82
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
83
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
result=-1;
else
if(this->salary > ((salary_elem&)e2).salary)
result=1;
else
result=0;
return result;
}
};
vector_quicksort<salary_elem> gr("Stud.txt");
gr.show("Unsorted group:\n","");
gr.quicksort();
gr.show("Group sorted by salary:\n","");
printf("n=%d, ncomp=%d, n*log2(n)=%.2lf, n*n=%.0lf\n",
gr.get_n(),gr.get_ncomp(),
gr.get_n()*log((double)gr.get_n())/log(2.0),
(double)gr.get_n()*gr.get_n());
getch();
}
84
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
85
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
int imain=divide(i,j);
if(imain-i > j-imain)
{// We start with the left-hand interval
quicksort_intern(i,imain-1);
quicksort_intern(imain+1,j);
}
else
{// We start with the right-hand interval
quicksort_intern(imain+1,j);
quicksort_intern(i,imain-1);
}
}
}
В силу того, что введенная модификация не изменит полученный ранее вывод, не будем его
повторять.
Пространственная сложность в будущем (когда будем непосредственно использовать стек)
будет приведена к величине P(n) O(log 2 n). Оценим временную сложность T(n). Т.к.
деление имеет сложность O(n), имеем:
T (n) O(n) T (imain 0) T (n 1 imain) . Т.е. все зависит от imain, а именно как вектор
будет поделен функцией divide().
Идеальный случае, который может буть достигнут применением принципа равновесия,
n
состоит в разделении вектора на две приблизительно расные части, так, чтобы imain .
2
n n n
T (n) O(n) 2T O(n) 2 O 2T
2 2 4
Тогда
n n n
O(n) 2 O 2 O 2T ... O(n) O(n) ... O(n) O(n log 2 n),
2 4 8
т.к. T(0)=0. Тким образом, T(n)=O(nlog2n), коэффициент перед nlog2n тот же, что и
коэффициент перед n в сложности деления.
Таким образом, метод дает O(nlog2n), что является нижним пределом сложности алгоритмов
сортировки, основанных на сравнении ключей.
Если же, в результате деления, главные элементы систематически будут устанавливаться в
позиции возле первого или возле последнего элемента соответствующих подвекторов (т.е.
постоянно imain=i, или imain=j), тогда каждый раз остается необходимость сортировать
подвектор количество элементов которого на единицу меньше, чем в предыдущем
подвекторе. В результате сложность будет
T (n) O(n) O(1) T (n 1) O(n) O(n 1) ... O(1) O(n 2 ) .
86
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
В этом случае, быстрая сортировка имеет сложность теоретически равную сложности самых
плохих алгоритмов сортировки, например, сортировки методом пузырька, а практическая
сложность вероятно будет и больше, в силу временных затрат на реализацию рекурсии,
управляемой стеком. Для быстрой сортировки, теоретически показано, что средняя
сложность, при равной вероятности всех перестановок, равна O(nlog2n) с примерно 2nlog2n
сравнениями ключей. Так же показано, что вероятность самого неблагоприятного случая со
сложностью O(n2) достаточно мала.
Вероятность самого неблагоприятного случая не исключена, когда данные уже упорядочены
или частично упорядочены (возможно и в обратном порядке).
Парадокс быстрой сортировки, в сравнении с сортировкой простыми вставками или, даже,
пузырьковой, заключается в том, что быстрая сортировка теряет свое качество на частично
упорядоченных векторах. Это является неудобным, т.к. необходимость сортировки “почти
упорядоченных” данных достаточно часто возникает на практике.
Для подтверждения изложенного, создадим текстовый файл с именем, например,
”stud20.txt” и со следующим содержанием:
Green 1987 350.00
Green 1987 350.00
Green 1987 350.00
Green 1987 350.00
Green 1987 350.00
Green 1987 350.00
Green 1987 350.00
Green 1987 350.00
Green 1987 350.00
Green 1987 350.00
Green 1987 350.00
Green 1987 350.00
Green 1987 350.00
Green 1987 350.00
Green 1987 350.00
Green 1987 350.00
Green 1987 350.00
Green 1987 350.00
Green 1987 350.00
Green 1987 350.00
87
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
88
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Как видно, в данном случае, количество сравнений ближе к n2, чем к nlog2n.
89
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
protected:
int threshold;
void quicksort_intern(int i, int j);
void insertsort(int i, int j);
};
90
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
91
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Câmpul de sortare
Prag
name year salary
0 39 42 43
1 39 42 43
92
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
2 37 37 41
3 35 37 38
4 32 37 33
5 29 34 28
6 29 34 28
7 29 34 28
8 29 34 28
9 29 34 28
10 30 28 25
11 30 28 25
Анализ результатов, представленных в данной таблице, остается в качестве упражнения.
Упражнение.
Переделайте конструктор класса sorted_table из 2.4 так, что бы он сначала создавал
простую неупорядоченную таблицу, а затем сортировал бы ее оптимизированным
алгоритмом быстрой сортировки.
93
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Простая вставка
Главная идея сортировки простыми вставками (engl. Insert sort) проста: выбираем некоторый
элемент, сортируем остальные, “вставляем” выбранный элемент на подходящее место среди
уже отсортированных.
void recursivinsertsort(int i, int j)
{
if(j>i)
{
recursivinsertsort(i, j-1);
for(int l=j; (l>i)&&(ncomp++, t[l]<t[l-1]; l--))
swap(l-1, l);
}
}
94
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Метод Шелла
95
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
void Shellsort();
};
96
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
int h;
int i, j, k;
el tmp;
// Defining the initial step
h=1;
while(h<n/9)
h=3*h+1;
// Here the step is equal max(1, hm-2)
do
{
// Sort by series by distance h
for(k=0; k<h; k++)
{ // Insertsort the series number k
for(i=h+k; i<n; i+=h)
{ // The inclusion of t[i] in his place among the precedents
tmp=t[i];
j=i-h;
while((j>=0)&&(SD::ncomp++, t[j]>tmp))
{
t[j+h]=t[j];
j-=h;
}
t[j+h]=tmp;
}
}
// Decrease increment
h=h/3;
} while(h>0);
}
Замечания:
1. Вместо последовательного перевычисления величин шагов h, можно вычислить их
предварительно и запомнить в дополнительном векторе:
2. Можно объединить циклы по k и по i, заменив обмены на полуобмены;
3. Сортировка по методу Шелла не является стабильной, и эта проблема легко не решается.
97
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
vector_Shellsort<usual_elem> gr("Stud.txt");
gr.show("Unsorted group:\n","");
gr.Shellsort();
gr.show("Group sorted by name:\n","");
printf("n=%d, ncomp=%d, n*log2(n)=%.2lf, n*n=%.0lf\n",
gr.get_n(),gr.get_ncomp(),
gr.get_n()*log((double)gr.get_n())/log(2.0),
(double)gr.get_n()*gr.get_n());
getch();
}
98
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
99
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
100
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Простой выбор
Идея метода сортировки простым выбором (engl. Selection sort) очень проста: находится
максимальный элемент в сортируемом векторе и меняется местами с последним элементом
вектора; далее ищется максимальный среди элементов без последнего и меняется местами с
предпоследним и т.д. На каждом просмотре рассматриваются только элементы, которые
остались неупорядоченными, максимальный среди которых и будет присоединен к уже
упорядоченным.
В нерекурсивной форме простой выбор состоит из n-1 этапов. На этапе k ищется элемент с
максимальным ключом среди элементов, которые еще до конца не упорядочены, и
устанавливается в позицию n-k.
Пример:
void selectsort()
{
int imax, i, j;
for(i=n-1; i>0; i--)
{
imax=i;
for(j=0; j<i; j++)
if(ncomp++, t[j]>t[imax])
imax=j;
swap(i,imax);
// Here sub vector from t[j] to t[n-1] it is sorted (loop invariance)
}
}
Сложность этого алгоритма имеет порядок O(n2) во всех случаях. Количество выполнений
n(n 1)
внутреннего цикла равно .
2
101
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Максимизация дерева
6 9
9 8 7 8
7 3 5 6 6 3 5 6
6 5 1 6 5 1
4 4
Полным двоичным деревом называется такое двоичное дерево, у которого на каждом уровне
присутствуют все узлы, за исключением, быть может, самых правых узлов последнего
уровня. Полное двоичное дерево может быть представлено в виде вектора.
Узлу с индексом i соответствуют узлы с индексом 2*i+1 (корень его левого поддерева, если
2*i+1<=n-1) и 2*i+2 (корень его правого поддерева, если 2*i+2<=n-1).
Важно понять, что никакое двоичное дерево отдельно не создается, используя формулы
2*i+1 и 2*i+2, работаем с вектором как с двоичным деревом.
102
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
void heapsort();
protected:
void reorganization(int i, int j);
void planting();
void maxtreesort();
};
103
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
При посадке реорганизация применяется к таким индексам i, поддеревья которых, если они
существуют, являются максимизирующими деревьями. Начинаем с элемента t[(n-1)/2],
т.к. у элементов с большим индексом нет поддеревьев.
template <class el> void vector_heapsort<el>::planting()
{
for(int i=(n-1)/2; i>=0; i--)
reorganization(i, n-1);
}
4. …
104
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
for (int i=(n-1);i>=1;i--)
{
swap (0, i);
reorganization(0, i-1);
}
}
n 1
Эта процедура имеет сложность T (n) O(h0,i ) , где h0,i – глубина поддерева t[0]÷t[i], т.е.
i 1
vector_heapsort<usual_elem> gr("Stud.txt");
gr.show("Unsorted group:\n","");
gr.heapsort();
gr.show("Group sorted by name:\n","");
printf("n=%d, ncomp=%d, n*log2(n)=%.2lf, n*n=%.0lf\n",
gr.get_n(),gr.get_ncomp(),
gr.get_n()*log((double)gr.get_n())/log(2.0),
(double)gr.get_n()*gr.get_n());
getch();
}
105
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Упражнение.
Перепишите конструктор класса sorted_table из 2.4 так, что бы он сначала создавал
простую неупорядоченную таблицу, а затем сортировал бы ее древовидной сортировкой.
Заменим в предыдущей функции main() класс usual_elem на класс year_elem, тогда
получим следующий результат:
Unsorted group:
1. Green 1987 350.00
2. Red 1980 450.00
3. Blue 1981 500.00
4. Gray 1968 900.00
5. Orange 1984 550.00
6. White 1980 600.00
7. Cyan 1975 800.00
8. Yellow 1988 300.00
9. Magenta 1983 600.00
10. Black 1981 500.00
End of vector. Press any key ...
Group sorted by year:
1. Gray 1968 900.00
2. Cyan 1975 800.00
3. Red 1980 450.00
4. White 1980 600.00
5. Black 1981 500.00
6. Blue 1981 500.00
7. Magenta 1983 600.00
8. Orange 1984 550.00
9. Green 1987 350.00
10. Yellow 1988 300.00
106
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
107
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Метод
Bublesort 0,16 20 2400
Extractsort 0,12 7,3 680
Insertsort 0,12 6,7 610
Shellsort 0,07 2 37 600 1800 4200
Heapsort 0,2 3,5 50 660 1830 3960
Quicksort 0,07 2 28 365 1000 2140
108
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
109
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Двоичное дерево, состоящее только из корня (точнее из корня и двух пустых поддеревьев)
110
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
B C
B C
D E F
111
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
right
B C
left right
left right
A F
D
root
112
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
level
1 A
2 B C
3 D E F
Двоичное дерево из n узлов может иметь максимум n уровней. В самом деле, в случае когда
все узлы имеют только по одному непустому поддереву (не имеет значение левому или
правому), за исключением единственного узла у которого не будет ни одного поддерева (это
будет узел последнего уровня), все узлы будут распределены по отдельным уровням, и,
следовательно, общее количество уровней будет n. Больше уровней не может быть, т. к.
недостаточно узлов.
level
1 A
2 B C
3 D E F
4 G H
113
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
114
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
A ×
B C
Пример полного двоичного дерева: отсутствуют два правых узла последнего уровня.
B C
D E
B C
D E F
115
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
public:
bintree<el>()
{
pdata=NULL;
pleft=pright=NULL;
}
bintree<el> *pcurrent_nod;
el *pnewel;
while(!feof(SD::pf))
if((pnewel = new el())->fscanf_el(SD::pf)>0)
{
pcurrent_nod=this;
while(pcurrent_nod->pdata!=NULL)
{
if(*pnewel < *(pcurrent_nod->pdata))
{
if(pcurrent_nod->pleft==NULL)
pcurrent_nod->pleft=new bintree<el>();
pcurrent_nod=pcurrent_nod->pleft;
116
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
}
else
{
if(pcurrent_nod->pright==NULL)
pcurrent_nod->pright=new bintree<el>();
pcurrent_nod=pcurrent_nod->pright;
}
}
pcurrent_nod->pdata=pnewel;
}
fclose(pf);
}
if(pdata)
pdata->show("", "\n");
if(pleft)
pleft->show_preorder("", "");
if(pright)
pright->show_preorder("", "");
printf("%s", ending);
}
if(pleft)
pleft->show_inorder("", "");
if(pdata)
pdata->show("", "\n");
if(pright)
117
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
pright->show_inorder("", "");
printf("%s", ending);
}
if(pleft)
pleft->show_postorder("", "");
if(pright)
pright->show_postorder("", "");
if(pdata)
pdata->show("", "\n");
printf("%s", ending);
}
118
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
if(cmp_result<0)
if(pcurrent_nod->pleft)
pcurrent_nod = pcurrent_nod->pleft;
else
forward=0;
else
if(pcurrent_nod->pright)
pcurrent_nod = pcurrent_nod->pright;
else
forward=0;
}
return found ? pcurrent_nod->pdata : NULL;
}
};
В функции main() создаем двоичное дерево поиска, загружая его из файла "Stud.txt" и
выводим узлы поочередно в прямом порядке, в симметричном порядке и концевом порядке:
void main()
{
clrscr();
bintree<usual_elem> btgr("Stud.txt");
btgr.show_preorder("Group in preorder\n","\n");
btgr.show_inorder("Group in inorder\n","\n");
btgr.show_postorder("Group in postorder\n","\n");
getch();
}
Green
Blue Red
119
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Group in inorder
Black 1981 500.00
Blue 1981 500.00
Cyan 1975 800.00
Gray 1968 900.00
Green 1987 350.00
Magenta 1983 600.00
Orange 1984 550.00
Red 1980 450.00
White 1980 600.00
Yellow 1988 300.00
Group in postorder
Black 1981 500.00
Cyan 1975 800.00
Gray 1968 900.00
Blue 1981 500.00
Magenta 1983 600.00
Orange 1984 550.00
Yellow 1988 300.00
White 1980 600.00
Red 1980 450.00
Green 1987 350.00
120
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
функция search() класса bintree адрес искомого объекта в случае успешного поиска, и
возвращает NULL – в случае когда поиск оказался неуспешным. Представленная далее
функция main(), демонстрирует поиск в двоичном дереве, созданном на основе файла
"Stud.txt":
void main()
{
clrscr();
bintree<usual_elem> btgr("Stud.txt");
btgr.show("Group:\n", "");
char ch='n';
char surname[21];
while(ch!='y')
{
printf("Enter a name to search: ");
scanf("%s", surname);
usual_elem e(surname, 2000, 0.0);
btgr.reset_ncomp();
usual_elem* p=btgr.search(e);
if(p==NULL)
printf("No bintree! The number of comparisons: %d\n", btgr.get_ncomp());
else
{
printf("There are in the bintree: ");
p->show("","\n");
printf("The number of comparisons: %d\n", btgr.get_ncomp());
}
printf("Done ? (y/n) ");
ch = getch();
printf("\n");
}
121
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Средняя длина поиска в данном двоичном дереве, может быть подсчитана следующим
образом:
void main()
{
clrscr();
bintree<usual_elem> btgr("Stud.txt");
btgr.show("Group:\n", "");
usual_elem sample;
long NCOMP=0;
long nelem = 0;
122
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
}
fclose(pf);
printf("n=%d, NCOMP=%d", nelem, NCOMP);
printf(", ALS=%.2f", (double)NCOMP/nelem);
printf(", MAX=%.2f", (nelem+1)/2.0);
printf(", MIN=%.2f\n", log((double)nelem)/log(2.0)+2.0);
В случае, когда двоичное дерево не является двоичным деревом поиска, поиск может быть
реализован с использованием любого из рассмотренных способов обхода: прямого,
обратного или концевого. Добавим в класс bintree следующую функцию поиска, которая
использует прямой обход:
el* preorder_search(el &e)
{
el* presult=NULL;
if(pdata)
{
if(SD::ncomp++, e.cmp(*pdata)==0)
presult=pdata;
else
{
if(pleft)
presult=pleft->preorder_search(e);
if(!presult && pright)
presult=pright->preorder_search(e);
123
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
}
}
return presult;
}
bintree<usual_elem> btgr("Stud.txt");
btgr.show("Group:\n", "");
char ch='n';
char surname[21];
while(ch!='y')
{
printf("Enter a name to search: ");
scanf("%s", surname);
usual_elem e(surname, 2000, 0.0);
btgr.reset_ncomp();
usual_elem* p=btgr.preorder_search(e);
if(p==NULL)
printf("No bintree! The number of comparisons: %d\n", btgr.get_ncomp());
else
{
printf("There are in the bintree: ");
p->show("","\n");
printf("The number of comparisons: %d\n", btgr.get_ncomp());
}
printf("Done ? (y/n) ");
ch = getch();
printf("\n");
}
124
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
bintree<usual_elem> btgr("Stud.txt");
btgr.show("Group:\n", "");
usual_elem sample;
long NCOMP=0;
long nelem = 0;
125
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
}
fclose(pf);
printf("n=%d, NCOMP=%d", nelem, NCOMP);
printf(", ALS=%.2f", (double)NCOMP/nelem);
printf(", MAX=%.2f", (nelem+1)/2.0);
printf(", MIN=%.2f\n", log((double)nelem)/log(2.0)+2.0);
На сей раз, средняя длина поиска совпала со средней длиной поиска в соответствующей
простой неупорядоченной таблице.
Упражнения.
1. Добавьте в класс bintree функцию поиска inorder_search() которая бы искала нужный
узел, используя обход в обратном порядке. Продемонстрируйте использование этой
функции. Определите среднюю длину поиска для конкретного двоичного дерева.
2. Добавьте в класс bintree функцию поиска postorder_search()которая бы искала
нужный узел, используя обход в концевом порядке. Продемонстрируйте использование этой
функции. Определите среднюю длину поиска для конкретного двоичного дерева.
3. Перегрузите оператор вставки в классе bintree.
4. Перегрузите оператор извлечения в классе bintree.
5. Добавьте в класс bintree функцию которая определяет высоту (количество уровней)
двоичного дерева.
6. Реализуйте работу с двоичными деревьями созданием двух родственных шаблонных
классов: первый bintree_root, который бы представлял собственно двоичное дерево, и
126
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
второй bintree_nod, который бы представлял один узел. Класс bintree_root может быть
объявлен как класс, дружественный классу bintree_nod.
127
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
4.3. Списки
Список (engl. list, finite sequence) это ДСД, представляющая набор элементов,
имеющих одну и ту же структуру, состоящую из двух разделов:
первый раздел содержит информацию относящуюся к соответствующему
элементу. Обычно это указатель (или ссылка) на внешнюю структуру
(она называется атомом и считается неделимой с точки зрения операций
над списком), или указатель на другой список;
второй раздел обеспечивает связь между элементами списка. Содержимое
этого раздела зависит от типа списка.
В простых односвязных списках (engl. chained list, linked list) второй раздел состоит из
одного указателя на следующий элемент списка. У последнего элемента этот указатель имеет
значение NULL.
В случае односвязного циклического списка (engl. circular list, ring list), указатель из второго
раздела последнего элемента содержит адрес первого элемента списка.
У двусвязных списков второй раздел содержит два указателя, первый из которых указывает
на следующий элемент списка (имеет значение NULL у последнего элемента), а второй
указывает на предыдущий элемент списка (имеет значение NULL у первого элемента).
D1 D2 Dn
… NULL
NULL
У двусвязных циклических списков, второй раздел так же содержит два указателя. В отличии
от списков предыдущего типа, первый из этих двух указателей у последнего элемента
содержит адрес первого элемента списка, а второй указатель у первого элемента содержит
адрес последнего элемента списка.
D1 D2 Dn
128
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
public:
list<el>()
{
pdata=NULL;
pnext=NULL;
}
list<el> *pcurrent_nod;
el *pnewel;
pcurrent_nod=this;
while(!feof(SD::pf))
if((pnewel = new el())->fscanf_el(SD::pf)>0)
{
if(pcurrent_nod->pdata!=NULL)
129
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
pcurrent_nod->pnext=new list<el>();
pcurrent_nod=pcurrent_nod->pnext;
}
pcurrent_nod->pdata=pnewel;
}
fclose(SD::pf);
}
list *pcurrent_nod=this;
if(pcurrent_nod->pdata)
{
int i=1;
printf(”%4d. ”, i);
pcurrent_nod->pdata->show("", "\n");
while(pcurrent_nod=pcurrent_nod->pnext)
{
if(i>0 && i%nlinepp==0)
{
printf("Press any key to continue...\n");
getch();
clrscr();
printf(”%s”, opening);
}
i++;
printf(”%4d. ”, i);
pcurrent_nod->pdata->show("", "\n");
}
}
printf(”%s”, ending);
printf("End of List. Press any key ...\n");
getch();
}
int search(el e)
{
130
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
list *pcurrent_nod=this;
if(pcurrent_nod->pdata)
{
int i=0;
if(SD::ncomp++, *(pcurrent_nod->pdata)==e)
position=i;
while((position==-1) && (pcurrent_nod=pcurrent_nod->pnext))
{
i++;
if(SD::ncomp++, *(pcurrent_nod->pdata)==e)
position=i;
}
}
return position;
}
};
void main()
{
clrscr();
list<usual_elem> gr("Stud.txt");
gr.show("Group:\n","");
char ch='n';
char surname[21];
while(ch!='y')
{
printf("Enter a name to search: ");
scanf(”%s”, surname);
usual_elem e(surname, 2000, 0.0);
int pos=gr.search(e);
if(pos<0)
printf("No list!\n");
else
131
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Group:
1. Green 1987 350.00
2. Red 1980 450.00
3. Blue 1981 500.00
4. Gray 1968 900.00
5. Orange 1984 550.00
6. White 1980 600.00
7. Cyan 1975 800.00
8. Yellow 1988 300.00
9. Magenta 1983 600.00
10. Black 1981 500.00
End of List. Press any key ...
Enter a name to search: Gray
There are in the position 4
Done ? (y/n)
Enter a name to search: Black
There are in the position 10
Done ? (y/n)
Enter a name to search: Green
There are in the position 1
Done ? (y/n)
Enter a name to search: Magenta
There are in the position 9
Done ? (y/n)
Enter a name to search: Purple
No list!
Done ? (y/n)
Упражнения.
1. Перегрузите оператор вставки в классе list.
2. Перегрузите оператор извлечения в классе list.
3. Создайте класс circular_list и продемонстрируйте работу с однонаправленными
циклическими списками.
132
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
public:
bidirectional_list<el>()
{
pdata=NULL;
pnext=ppred=NULL;
}
bidirectional_list<el> *pcurrent_nod;
el *pnewel;
pcurrent_nod=this;
while(!feof(SD::pf))
if((pnewel = new el())->fscanf_el(SD::pf)>0)
{
if(pcurrent_nod->pdata!=NULL)
{
pcurrent_nod->pnext=new bidirectional_list<el>();
133
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
pcurrent_nod->pnext->ppred=pcurrent_nod;
pcurrent_nod=pcurrent_nod->pnext;
}
pcurrent_nod->pdata=pnewel;
}
fclose(SD::pf);
}
bidirectional_list<el> *pcurrent_nod=this;
if(pcurrent_nod->pdata)
{
int i=1;
printf("%4d. ", i);
pcurrent_nod->pdata->show("", "\n");
while(pcurrent_nod=pcurrent_nod->pnext)
{
if(i>0 && i%nlinepp==0)
{
printf("Press any key to continue...\n");
getch();
clrscr();
printf("%s", opening);
}
i++;
printf("%4d. ", i);
pcurrent_nod->pdata->show("", "\n");
}
}
printf("%s", ending);
printf("End of List. Press any key ...\n");
getch();
}
134
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
clrscr();
printf("%s", opening);
bidirectional_list<el> *pcurrent_nod=this;
if(pcurrent_nod->pdata)
{
while(pcurrent_nod->pnext)
pcurrent_nod=pcurrent_nod->pnext;
int i=1;
printf("%4d. ", i);
pcurrent_nod->pdata->show("", "\n");
while(pcurrent_nod=pcurrent_nod->ppred)
{
if(i>0 && i%nlinepp==0)
{
printf("Press any key to continue...\n");
getch();
clrscr();
printf("%s", opening);
}
i++;
printf("%4d. ", i);
pcurrent_nod->pdata->show("", "\n");
}
}
printf("%s", ending);
printf("End of List. Press any key ...\n");
getch();
}
int search(el e)
{
int position = -1;
bidirectional_list<el> *pcurrent_nod=this;
if(pcurrent_nod->pdata)
{
int i=0;
if(*(pcurrent_nod->pdata)==e)
position=i;
while((position==-1) && (pcurrent_nod=pcurrent_nod->pnext))
{
135
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
i++;
if(*(pcurrent_nod->pdata)==e)
position=i;
}
}
return position;
}
};
bidirectional_list<usual_elem> gr("Stud.txt");
gr.show("Group:\n","\n");
char ch='n';
char surname[21];
while(ch!='y')
{
printf("Enter a name to search: ");
scanf("%s", surname);
usual_elem e(surname, 2000, 0.0);
int pos=gr.search(e);
if(pos<0)
printf("No list!\n");
else
printf("There are in the position %d\n", (pos+1));
printf("Done ? (y/n) ");
ch = getch();
printf("\n");
}
}
136
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Упражнения.
1. Перегрузите оператор вставки в классе bidirectional_list.
2. Перегрузите оператор извлечения в классе bidirectional_list.
3. Объявите класс bidirectional_list как класс производный от шаблонного класса list.
137
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Далее следует пример реализации простых однонаправленных списков при помощи двух
родственных классов. Основной класс main_list будет представлять список в целом, а
вспомогательный класс node_list будет представлять один элемент списка. Для облегчения
реализации класса main_list, последний будет объявлен как дружественный класс классу
node_list.
Прежде всего анонсируем класс main_list, чтобы на него можно было ссылаться в классе
node_list.
template <class el> class main_list;
public:
node_list<el>()
{
pnext=NULL;
pdata=NULL;
}
Наконец создадим главный класс списка main_list, как конкретный шаблонный класс,
производный от абстрактного класса SD. Класс main_list может быть конкретизирован
138
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
public:
main_list<el>()
{
pfirst=new node_list<el>();
}
node_list<el> *pcurrent_nod;
el *pnewel;
pcurrent_nod=this->pfirst;
while(!feof(SD::pf))
if((pnewel = new el())->fscanf_el(SD::pf)>0)
{
if(pcurrent_nod->pdata!=NULL)
{
pcurrent_nod->pnext=new node_list<el>();
pcurrent_nod=pcurrent_nod->pnext;
}
pcurrent_nod->pdata=pnewel;
}
fclose(SD::pf);
}
virtual void show(const char* opening, const char* ending, int nlinepp=20)
{
clrscr();
printf("%s", opening);
139
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
node_list<el> *pcurrent_nod=this->pfirst;
if(pcurrent_nod->pdata)
{
int i=1;
printf("%4d. ", i);
pcurrent_nod->pdata->show("", "\n");
while(pcurrent_nod=pcurrent_nod->pnext)
{
if(i>0 && i%nlinepp==0)
{
printf("Press any key to continue...\n");
getch();
clrscr();
printf("%s", opening);
}
i++;
printf("%4d. ", i);
pcurrent_nod->pdata->show("", "\n");
}
}
printf("%s", ending);
printf("End of List. Press any key ...\n");
getch();
}
int search(el e)
{
int position = -1;
node_list<el> *pcurrent_nod=this->pfirst;
if(pcurrent_nod->pdata)
{
int i=0;
if(SD::ncomp++, *(pcurrent_nod->pdata)==e)
position=i;
while((position==-1) && (pcurrent_nod=pcurrent_nod->pnext))
{
i++;
if(SD::ncomp++, *(pcurrent_nod->pdata)==e)
position=i;
}
}
140
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
return position;
}
};
main_list<usual_elem> gr("Stud.txt");
gr.show("Group:\n","");
char ch='n';
char surname[21];
while(ch!='y')
{
printf("Enter a name to search: ");
scanf("%s", surname);
usual_elem e(surname, 2000, 0.0);
int pos=gr.search(e);
if(pos<0)
printf("No list!\n");
else
printf("There are in the position %d\n", (pos+1));
printf("Done ? (y/n) ");
ch = getch();
printf("\n");
}
}
141
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Упражнения.
1. Перегрузите оператор вставки в классах main_list и node_list.
2. Перегрузите оператор извлечения в классах main_list и node_list.
3. Реализуйте работу с однонаправленными циклическими списками при помощи двух
родственных шаблонных классов: первый main_circular_list, который будет представлять
однонаправленный циклический список в целом, и второй node_circular_list, который
будет представлять один элемент списка. Класс main_circular_list может быть объявлен
как класс дружественный классу node_circular_list.
4. Реализуйте работу с двунаправленными списками при помощи двух родственных
шаблонных классов: первый main_bidirectional_list, который будет представлять
двунаправленный список в целом, и второй nod_bidirectional_list, который будет
представлять один элемент списка. Класс main_bidirectional_list может быть объявлен
как класс дружественный классу nod_bidirectional_list.
5. Реализуйте работу с двунаправленными циклическими списками при помощи двух
родственных шаблонных классов: первый main_bidirectional_circular_list, который
будет представлять двунаправленный циклический список в целом, и второй
nod_bidirectional_circular_list, который будет представлять один элемент списка.
Класс main_bidirectional_circular_list может быть объявлен как класс дружественный
классу nod_bidirectional_circular_list.
142
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
4.4. Стеки
Обшие понятия
Стек (engl. stack, LIFO list, pushdown stack, pushdown list) это динамическая
структура данных, состоящая из конечного и упорядоченного набора
элементов одной и той же структуры, со свойством, что как добавление
новых элементов и доступ к существующим (преимущественно удаление)
осуществляется с одного и того же конца (называемого вершиной стека) по
принципу “последним вошел – первым вышел” (engl. LIFO – Last In, First
Out).
Буфер представляет вектор фиксированной длины (размер или глубина стека). Тип
элементов вектора зависит от типа элементов стека или является указателем с базовым типом
– тип элементов стека, как это показано схематически на следующем рисунке.
size n top 0
0 1 2 3 4 n-2 n-1
buffer …
143
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Поле size содержит размер стека. Оно инициализируется при создании стека и больше не
меняет своего значения.
Вектор buffer представляет пространство для записи элементов в стек. Память под него
выделяется во время создания стека.
Поле top указывает следующую позицию за вершиной стека (первая позиция доступная для
записи в стек). Оно инициализируется при создании стека и в дальнейшем будет обновляться
при каждой записи в стек (push) и при каждом извлечении из стека (pop).
Например, после трех последовательных записей (push(A), push(B), push(C)) стек будет
выглядеть следующим образом:
size n top 3
0 1 2 3 4 n-2 n-1
buffer A B C …
Если далее последует операция извлечения (pop), ее результатом будет C, а стек будет
выглядеть следующим образом:
size n top 2
0 1 2 3 4 n-2 n-1
buffer A B …
144
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
public:
stackFB<el>(int init_size=100)
{
size=init_size;
buffer = new el[size];
top=0;
}
el newel;
while(!feof(SD::pf))
if(newel.fscanf_el(SD::pf)>0)
push(newel);
fclose(SD::pf);
}
~stackFB<el>()
{
delete buffer;
}
el pop()
{
145
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
if(top)
return buffer[--top];
else
error("Stack is empty!\n");
}
virtual void show(const char* opening, const char* ending, int nlinepp=20)
{
clrscr();
printf(”%s”, opening);
if(!isempty())
{
int i=1;
printf(”%4d. ”, i);
int current=top-1;
buffer[current].show("", "\n");
while(--current>=0)
{
if(i>0 && i%nlinepp==0)
{
printf("Press any key to continue...\n");
getch();
clrscr();
printf(”%s”, opening);
}
i++;
printf(”%4d. ”, i);
buffer[current].show("", "\n");
}
}
printf(”%s”, ending);
printf(”End of Stack. Press any key ...\n");
getch();
}
};
В функции main() создадим стек в виде буфера фиксированного размера в 100 элементов
типа usual_elem, загрузив его из файла "Stud.txt". Затем выведем содержимое стека, после
чего опустошим по шагам, последовательными извлечениями. Далее запишем в стек два
элемента и убедимся, что они будут извлечены в обратном порядке:
void main()
146
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
clrscr();
printf("\nExtracting by one:\n");
char ch;
while(!gr.isempty())
{
printf("Press any key...\n");
ch = getch();
usual_elem extracted_el;
extracted_el = gr.pop();
extracted_el.show("","\n");
}
printf("Stack is empty! Press any key...\n");
ch = getch();
printf(”\n”);
gr.pop().show("","\n");
gr.pop().show("","\n");
printf("Press any key...\n");
ch = getch();
printf(”\n”);
}
147
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Extracting by one:
Press any key...
Black 1981 500.00
Press any key...
Magenta 1983 600.00
Press any key...
Yellow 1988 300.00
Press any key...
Cyan 1975 800.00
Press any key...
White 1980 600.00
Press any key...
Orange 1984 550.00
Press any key...
Gray 1968 900.00
Press any key...
Blue 1981 500.00
Press any key...
Red 1980 450.00
Press any key...
Green 1987 350.00
Stack is empty! Press any key...
Упражнения.
1. Перегрузите оператор вставки в классе stackFB.
2. Перегрузите оператор извлечения в классе stackFB.
148
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
pdata NULL
pnext NULL
После трех последовательных записей (push(A), push(B), push(C)) стек будет выглядеть
следующим образом:
C B A
pdata
pnext NULL
Если далее последует операция извлечения (pop), ее результатом будет C, а стек будет
выглядеть так:
B A
pdata
pnext NULL
149
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
public:
stackL<el>()
{
pdata=NULL;
pnext=NULL;
}
el *pnewel;
while(!feof(SD::pf))
if((pnewel=new el())->fscanf_el(SD::pf)>0)
push(*pnewel);
fclose(SD::pf);
}
~stackL<el>()
{
150
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
}
else
error("Stack is full!");
}
el &pop()
{
if(!isempty())
{
el *pret=this->pdata;
if(this->pnext)
{
stackL<el> *ptemp=this->pnext;
this->pnext=ptemp->pnext;
this->pdata=ptemp->pdata;
delete ptemp;
}
else
this->pdata=NULL;
return *pret;
}
else
error("Stack is empty!");
}
virtual void show(const char* opening, const char* ending, int nlinepp=20)
{
clrscr();
printf("%s", opening);
if(!isempty())
{
int i=1;
printf("%4d. ", i);
stackL<el> *pcurrent=this;
pcurrent->pdata->show("", "\n");
while((pcurrent=pcurrent->pnext)!=NULL)
{
if(i>0 && i%nlinepp==0)
{
151
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
printf("%s", ending);
printf("End of Stack. Press any key ...\n");
getch();
}
};
В предыдущей версии функции main(), вместо стека в форме буфера создадим стек в форме
списка:
stackL<usual_elem> gr("Stud.txt");
152
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
public:
stackFB<el>(int init_size=100)
{
size=init_size;
buffer = new el[size];
top=0;
}
~stackFB<el>()
{
delete buffer;
}
153
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
error("Stack is full!\n");
}
el pop()
{
if(top)
return buffer[--top];
else
error("Stack is empty!\n");
}
virtual void show(const char* opening, const char* ending, int nlinepp=20)
{
};
//
// C l a s s "s t a c k l i s t"
//
template <class el> class stackL: public SD
{
protected:
el *pdata;
stackL<el> *pnext;
public:
stackL<el>()
{
pdata=NULL;
pnext=NULL;
}
~stackL<el>()
{
154
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
el &pop()
{
if(!isempty())
{
el *pret=this->pdata;
if(this->pnext)
{
stackL<el> *ptemp=this->pnext;
this->pnext=ptemp->pnext;
this->pdata=ptemp->pdata;
delete ptemp;
}
else
this->pdata=NULL;
return *pret;
}
else
error("Stack is empty!");
}
virtual void show(const char* opening, const char* ending, int nlinepp=20)
{
155
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
};
public:
bintree_stack<el>()
{
pdata=NULL;
pleft=pright=NULL;
}
bintree_stack *pcurrent_nod;
el *pnewel;
while(!feof(SD::pf))
if((pnewel = new el())->fscanf_el(SD::pf)>0)
{
156
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
pcurrent_nod=this;
while(pcurrent_nod->pdata!=NULL)
{
if(*pnewel < *(pcurrent_nod->pdata))
{
if(pcurrent_nod->pleft==NULL)
pcurrent_nod->pleft=new bintree_stack();
pcurrent_nod=pcurrent_nod->pleft;
}
else
{
if(pcurrent_nod->pright==NULL)
pcurrent_nod->pright=new bintree_stack();
pcurrent_nod=pcurrent_nod->pright;
}
}
pcurrent_nod->pdata=pnewel;
}
fclose(SD::pf);
}
printf(”%s”, opening);
while(!st.isempty())
{
bintree_stack<el>* pcur=st.pop();
if(pcur->pright)
st.push(pcur->pright);
if(pcur->pleft)
st.push(pcur->pleft);
if(pcur->pdata)
pcur->pdata->show("","\n");
}
printf(”%s”, ending);
}
157
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
st.push(stel);
printf(”%s”, opening);
while(!st.isempty())
{
stack_elem<el> current=st.pop();
if(current.t=='n')
(current.p)->pdata->show("","\n");
else
{
if((current.p)->pright)
{
stel.p=(current.p)->pright;
stel.t='r';
st.push(stel);
}
if((current.p)->pdata)
{
stel.p=current.p;
stel.t='n';
st.push(stel);
}
if((current.p)->pleft)
{
stel.p=(current.p)->pleft;
stel.t='r';
st.push(stel);
}
}
}
printf(”%s”, ending);
}
158
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
st.push(stel);
printf(”%s”, opening);
while(!st.isempty())
{
stack_elem<el> current=st.pop();
if(current.t=='n')
(current.p)->pdata->show("","\n");
else
{
if((current.p)->pdata)
{
stel.p=current.p;
stel.t='n';
st.push(stel);
}
if((current.p)->pright)
{
stel.p=(current.p)->pright;
stel.t='r';
st.push(stel);
}
if((current.p)->pleft)
{
stel.p=(current.p)->pleft;
stel.t='r';
st.push(stel);
}
}
}
printf("%s", ending);
}
159
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
printf(”%s”, opening);
while(!st.isempty())
{
bintree_stack<el>* pcur=st.pop();
if(pcur->pright)
st.push(pcur->pright);
if(pcur->pleft)
st.push(pcur->pleft);
if(pcur->pdata)
pcur->pdata->show("","\n");
}
printf(”%s”, ending);
}
st.push(*pstel);
printf(”%s”, opening);
while(!st.isempty())
{
stack_elem<el> current=st.pop();
if(current.t=='n')
(current.p)->pdata->show("","\n");
else
{
if((current.p)->pright)
{
160
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
st.push(*pstel);
printf(”%s”, opening);
while(!st.isempty())
{
stack_elem<el> current=st.pop();
if(current.t=='n')
(current.p)->pdata->show("","\n");
else
161
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
if((current.p)->pdata)
{
pstel = new stack_elem<el>;
pstel->p=current.p;
pstel->t='n';
st.push(*pstel);
}
if((current.p)->pright)
{
pstel = new stack_elem<el>;
pstel->p=(current.p)->pright;
pstel->t='r';
st.push(*pstel);
}
if((current.p)->pleft)
{
pstel = new stack_elem<el>;
pstel->p=(current.p)->pleft;
pstel->t='r';
st.push(*pstel);
}
}
}
printf(”%s”, ending);
}
virtual void show(const char* opening, const char* ending, int nlinepp=20)
{
show_preorderFB(opening, ending);
}
};
В функции main() создаем двоичное дерево, загрузив его из файла "Stud.txt", затем
выводим последовательно информацию об его узлах соответственно обходу в прямом,
162
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
симметричном и концевом порядках по два раза. Один раз с использованием стека в форме
буфера фиксированной длины и второй раз с использованием стека в форме простого
однонаправленного списка.
void main()
{
clrscr();
bintree_stack<usual_elem> btgr("Stud.txt");
getch();
}
163
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
164
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Упражнение.
1. Продемонстрируйте использование стеков для обхода двоичных деревьев, реализовав стек
в виде списка с помощью двух родственных шаблонных классов: main_stackL и
node_stackL.
165
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
int i;
int j;
166
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
protected:
void quicksort_stack(int i, int j);
int divide(int i, int j);
};
while(!stack_interv.isempty())
{
interval tinterv=stack_interv.pop();
i=tinterv.i;
167
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
j=tinterv.j;
if(j>i)
{
int imain=divide(i,j);
stack_interv.push(*(new interval(i, imain-1)));
stack_interv.push(*(new interval(imain+1, j)));
}
else
printf("Not processed!\n"), getch();
}
}
if(imain > i)
swap(i, imain);
imain = i+1, jmain = j;
while(imain < jmain)
{
while((imain < jmain)&&(SD::ncomp++, t[imain] <= t[i]))
imain++;
while((jmain > imain)&&(SD::ncomp++, t[jmain] >= t[i]))
jmain--;
if(imain < jmain)
swap(imain, jmain);
168
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
}
if(ncomp++, t[imain] > t[i])
imain--;
if(imain > i)
swap(i, imain);
return imain;
}
vector_quicksort_stack<usual_elem> gr("Stud.txt");
gr.show("Unsorted group:\n","");
gr.reset_ncomp();
gr.quicksort();
gr.show("Group sorted by name:\n","");
printf("n=%d, ncomp=%d, n*log2(n)=%.2lf, n*n=%.0lf\n",
gr.get_n(),gr.get_ncomp(),
gr.get_n()*log((double)gr.get_n())/log(2.0),
(double)gr.get_n()*gr.get_n());
getch();
169
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
From Stack: [ 5, 7]
From Stack: [ 7, 7]
Not processed!
From Stack: [ 5, 5]
Not processed!
From Stack: [ 0, 3]
From Stack: [ 3, 3]
Not processed!
From Stack: [ 0, 1]
From Stack: [ 2, 1]
Not processed!
From Stack: [ 0, 0]
Not processed!
Group sorted by name:
1. Black 1981 500.00
2. Blue 1981 500.00
3. Cyan 1975 800.00
4. Gray 1968 900.00
5. Green 1987 350.00
6. Magenta 1983 600.00
7. Orange 1984 550.00
8. Red 1980 450.00
9. White 1980 600.00
10. Yellow 1988 300.00
End of vector. Press any key ...
n=10, ncomp=39, n*log2(n)=33.22, n*n=100
vector_quicksort_stack<year_elem> gr("Stud.txt");
gr.show("Unsorted group:\n","");
gr.reset_ncomp();
gr.quicksort();
gr.show("Group sorted by year:\n","");
printf("n=%d, ncomp=%d, n*log2(n)=%.2lf, n*n=%.0lf\n",
gr.get_n(),gr.get_ncomp(),
gr.get_n()*log((double)gr.get_n())/log(2.0),
(double)gr.get_n()*gr.get_n());
getch();
}
170
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
171
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
vector_quicksort_stack<salary_elem> gr("Stud.txt");
gr.show("Unsorted group:\n","");
gr.reset_ncomp();
gr.quicksort();
gr.show("Group sorted by salary:\n","");
printf("n=%d, ncomp=%d, n*log2(n)=%.2lf, n*n=%.0lf\n",
gr.get_n(),gr.get_ncomp(),
gr.get_n()*log((double)gr.get_n())/log(2.0),
(double)gr.get_n()*gr.get_n());
getch();
}
rezultatul va fi:
Unsorted group:
1. Green 1987 350.00
2. Red 1980 450.00
3. Blue 1981 500.00
4. Gray 1968 900.00
5. Orange 1984 550.00
6. White 1980 600.00
7. Cyan 1975 800.00
8. Yellow 1988 300.00
9. Magenta 1983 600.00
10. Black 1981 500.00
End of vector. Press any key ...
From Stack: [ 0, 9]
From Stack: [ 5, 9]
From Stack: [ 7, 9]
From Stack: [ 9, 9]
Not processed!
From Stack: [ 7, 7]
Not processed!
From Stack: [ 5, 5]
Not processed!
From Stack: [ 0, 3]
From Stack: [ 2, 3]
From Stack: [ 4, 3]
172
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Not processed!
From Stack: [ 2, 2]
Not processed!
From Stack: [ 0, 0]
Not processed!
Group sorted by salary:
1. Yellow 1988 300.00
2. Green 1987 350.00
3. Red 1980 450.00
4. Blue 1981 500.00
5. Black 1981 500.00
6. Orange 1984 550.00
7. White 1980 600.00
8. Magenta 1983 600.00
9. Cyan 1975 800.00
10. Gray 1968 900.00
End of vector. Press any key ...
n=10, ncomp=43, n*log2(n)=33.22, n*n=100
Упражнение.
1. Создайте шаблонный класс vector_quicksort_stack как производный от шаблонного
класса vector_quicksort из 3.4.
173
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
protected:
int threshold;
void optim_quicksort_stack(int i, int j);
void insertsort(int i, int j);
};
while(!stack_interv.isempty())
{
interval tinterv=stack_interv.pop();
i=tinterv.i;
j=tinterv.j;
if(j-i+1>threshold)
{
int imain=divide(i,j);
if(imain-i > j-imain)
{
stack_interv.push(*(new interval(i, imain-1)));
stack_interv.push(*(new interval(imain+1, j)));
}
else
{
stack_interv.push(*(new interval(imain+1, j)));
stack_interv.push(*(new interval(i, imain-1)));
}
174
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
}
else
insertsort(i, j);
}
}
175
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
результат будет:
Unsorted group:
1. Green 1987 350.00
2. Red 1980 450.00
3. Blue 1981 500.00
4. Gray 1968 900.00
5. Orange 1984 550.00
6. White 1980 600.00
7. Cyan 1975 800.00
8. Yellow 1988 300.00
176
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
void main()
{
clrscr();
результат будет:
Unsorted group:
1. Green 1987 350.00
2. Red 1980 450.00
3. Blue 1981 500.00
4. Gray 1968 900.00
5. Orange 1984 550.00
6. White 1980 600.00
7. Cyan 1975 800.00
177
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Упражнение.
1. Создайте шаблонный класс vector_optim_quicksort_stack, как производный от
шаблонного класса vector_optim_quicksort из 3.4.
178
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
4.5. Очереди
Общие понятия
Очередь (engl. queue, FIFO list, pushup stack, pushup list) это динамическая
структура данных, состоящая из конечного упорядоченного набора
элементов одного и того же типа, организованная таким образом, что
добавление новых элементов осуществляется только в конец очереди, а
доступ к ее элементам (преимущественно извлечение) осуществляется
только с начала очереди, согласно принципу “первым вошел – первым
вышел ” (engl. FIFO – First In, First Out ).
179
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Буфер представляет собой вектор фиксированной длины (величина или глубина очереди).
Тип элементов вектора зависит от типа элементов очереди, или может быть указателем с
базовым типом элементов очереди. На следующем рисунке схематически представлена
пустая очередь реализованная в виде циклического буфера.
size n nextin 0
0 1 2 3 4 n-2 n-1
buffer …
nextout 0 count 0
size n nextin 3
0 1 2 3 4 n-2 n-1
buffer A B C …
nextout 0 count 3
180
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Если далее последует одно извлечение из очереди (get), то результатом будет A, а очередь
будет выглядеть так:
size n nextin 3
0 1 2 3 4 n-2 n-1
buffer B C …
nextout 1 count 2
queueCB<el>(int init_size=100)
{
size=init_size;
buffer = new el[size];
nextin=nextout=count=0;
}
181
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
nextin=nextout=count=0;
el newel;
while(!feof(SD::pf))
if(newel.fscanf_el(SD::pf)>0)
put(newel);
fclose(SD::pf);
}
~queueCB()
{
delete buffer;
}
el get()
{
if(count-- > 0)
{
int outpos = nextout;
nextout=++nextout%size;
return buffer[outpos];
}
else
error("Queue is empty!");
}
virtual void show(const char* opening, const char* ending, int nlinepp=20)
182
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
clrscr();
printf("%s”, opening);
if(count>0)
{
int i=1;
printf("%4d. ”, i);
int current=nextout;
buffer[current].show("", "\n");
while((++current%size)!=nextin)
{
if(i>0 && i%nlinepp==0)
{
printf("Press any key to continue...\n");
getch();
clrscr();
printf("%s”, opening);
}
i++;
printf("%4d. ”, i);
buffer[current].show("", "\n");
}
}
printf("%s”, ending);
В функции main() создадим очередь в виде циклического буфера размера в 100 элементов
типа usual_elem, загрузив ее из файла "Stud.txt". Затем выведем содержимое очереди,
после чего очистим ее пошаговым извлечением. Далее запишем в очередь два элемента и
убедимся, что они будут извлекаться в порядке, соответствующем записи:
void main()
{
clrscr();
183
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
printf("\nExtracting by one:\n");
while(!gr.isempty())
{
printf(”\nPress any key...\n");
getch();
usual_elem extel;
extel = gr.get();
extel.show("","");
}
printf("\nQueue is empty! Press any key...\n");
printf(”\n”);
gr.get().show("","\n");
gr.get().show("","\n");
printf(”Press any key...\n");
getch();
}
Extracting by one:
184
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Упражнения.
1. Перегрузите оператор вставки в классе queueCB.
2. Перегрузите оператор извлечения в классе queueCB.
pdata NULL
pnext NULL
После трех последовательных записей (put(A), put(B), put(C)) очередь будет выглядеть
следующим образом:
185
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
A B C
pdata
pnext NULL
Если далее последует одно извлечение (get), то результатом будет A, а очередь будет
выглядеть так:
B C
pdata
pnext NULL
public:
queueL<el>()
{
pdata=NULL;
pnext=NULL;
}
186
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
pdata=NULL;
pnext=NULL;
queueL *pcurrent_nod=this;
el *pnewel;
while(!feof(SD::pf))
if((pnewel = new el())->fscanf_el(SD::pf)>0)
{
if(pcurrent_nod->pdata!=NULL)
{
pcurrent_nod->pnext=new queueL<el>();
pcurrent_nod=pcurrent_nod->pnext;
}
pcurrent_nod->pdata=pnewel;
}
fclose(SD::pf);
}
~queueL()
{
187
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
}
pcurrent_nod->pdata=pnewel;
}
else
error("Queue is full!");
}
el get()
{
if(!isempty())
{
el* pret=pdata;
queueL<el>* pdel=pnext;
if(pdel)
{
pdata=pnext->pdata;
pnext=pnext->pnext;
delete pdel;
}
else
pdata=NULL;
return *pret;
}
else
error("Queue is empty!");
}
virtual void show(const char* opening, const char* ending, int nlinepp=20)
{
clrscr();
printf("%s", opening);
queueL<el> *pcurrent_nod=this;
if(pcurrent_nod->pdata)
{
int i=1;
printf("%4d. ", i);
pcurrent_nod->pdata->show("", "\n");
while(pcurrent_nod=pcurrent_nod->pnext)
{
if(i>0 && i%nlinepp==0)
{
printf("Press any key to continue...\n");
188
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
getch();
clrscr();
printf("%s", opening);
}
i++;
printf("%4d. ", i);
pcurrent_nod->pdata->show("", "\n");
}
}
printf("%s", ending);
189
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
5. МАТРИЦЫ
Пример. Используя нотацию языка Pascal элемент матрицы A может быть обозначен как
A[i1,i2,i3,i4], а в языке C – A[i1][i2][i3][i4].
Количество чисел (индексов) которые входят в упорядоченный набор целых чисел
определяет размерность матрицы. Если этот набор содержит n чисел, тогда матрица
называется n-мерной.
Итак, целые числа i1, i2,…,in, входящие в упорядоченный набор, называются индексами.
Каждый индекс имеет собственную область допустимых значений, определенную тем или
иным образом, и которая может состоять из нескольких непересекающихся между собой
интервалов.
Важным подклассом матриц, которые используются как в компиляторах так и в языках
программирования, является класс прямоугольных матриц. У прямоугольных матриц
область допустимых значений у каждого индекса представляет постоянный и непрерывный
интервал.
Пример из языка Pascal.
Var
A: array[2..4, -3..-1, 0..1] of char;
190
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
191
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Одномерная матрица B с интервалом индекса [l, h], l≤h, нормальным способом отображается
в вектор следующим образом:
B[i] → V[i-l], i=l, l+1, …, h,
где V начальный адрес размещения вектора в ОП, т.е. V является базовым адресом, а i-l
является смещением к элементу с индексом i.
Прямоугольные матрицы размерности большей 1, обычно отображаются в вектора одним из
следующих двух способов:
1. Быстрее изменяется последний индекс (так называемый метод “по строкам”, название
происходит от матриц размерности 2);
2. Быстрее изменяется первый индекс (так называемый метод “по столбцам”, название
происходит от матриц размерности 2).
192
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
V[0] V[1] V[2] V[3] V[4] V[5] V[6] V[7] V[8] V[9] V[10] V[11] V[12] V[13] V[14] V[15] V[16] V[17]
’A’ ’B’ ’C’ ’D’ ’E’ ’F’ ’G’ ’H’ ’I’ ’J’ ’K’ ’L’ ’M’ ’N’ ’O’ ’P’ ’Q’ ’R’
2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4
-3 -3 -2 -2 -1 -1 -3 -3 -2 -2 -1 -1 -3 -3 -2 -2 -1 -1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
193
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
n
V[ ( ij-lj) Dj] вектора V, где Dj числа, которые вычисляются в обратном порядке, по
j 1
194
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
unsigned char c;
public:
character()
{
c='\0';
}
Упражнения.
1. Перегрузите оператор вставки в классе character.
2. Перегрузите оператор извлечения в классе character.
195
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
public:
matrix3l<el>(int l1, int h1, int l2, int h2, int l3, int h3)
{
this->l1=l1;
this->h1=h1;
this->l2=l2;
this->h2=h2;
this->l3=l3;
this->h3=h3;
int nel=(this->h1-this->l1+1)*(this->h2-this->l2+1)*(this->h3-this->l3+1);
V = new el[nel];
nopadd=0, nopmul=0;
}
matrix3l<el>(char* file_name, int l1, int h1, int l2, int h2,
int l3, int h3):
SD(file_name)
{
this->l1=l1;
this->h1=h1;
this->l2=l2;
this->h2=h2;
196
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
this->l3=l3;
this->h3=h3;
int nel=(this->h1-this->l1+1)*(this->h2-this->l2+1)*(this->h3-this->l3+1);
V = new el[nel];
nopadd=0, nopmul=0;
}
nopadd+=9, nopmul+=5;
D3=1;
D2=(h3-l3+1)*D3;
D1=(h2-l2+1)*D2;
return V[(i1-l1)*D1+(i2-l2)*D2+(i3-l3)*D3];
}
virtual void show(const char* opening, const char* ending , int nlinepp=20)
{
clrscr();
printf("%s", opening);
int i1, i2, i3;
for(int i1=l1; i1<=h1; i1++)
{
printf("i1=%i\n", i1);
for(i2=l2; i2<=h2; i2++)
{
for(i3=l3; i3<=h3; i3++)
elem(i1, i2, i3).show("", " ");
printf("\n");
}
}
printf("%s", ending);
printf("End of matrix. Press any key ...\n");
197
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
getch();
}
int search(el e)
{
int position = -1;
int nel=(h1-l1+1)*(h2-l2+1)*(h3-l3+1);
for(int i=0; (position==-1) && i<nel ; i++)
if(e==this->V[i])
position=i;
return position;
}
198
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
return found;
}
void resetnop()
{
nopadd=0, nopmul=0;
}
A.showvect("Matrix-vector A:\n","\n");
A.show("Matrix A\n","\n");
printf("\nN op. +/- %i, N op. x/: %i\n", A.getnopadd(), A.getnopmul());
199
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
char ch='n';
char c;
int i1, i2, i3;
while(ch!='y')
{
printf("Enter a char to search: ");
c=getch();
character mychar(c);
int pos=A.search(c);
if(pos<0)
printf("The character %c no matrix!\n", c);
else
{
A.search(c, i1, i2, i3);
printf("The character %c are in the position %i \nwith indices
[%i,%i,%i]\n",
c, pos, i1, i2, i3);
}
200
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
5. F
6. G
7. H
8. I
9. J
10. K
11. L
12. M
13. N
14. O
15. P
16. Q
17. R
201
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Упражнения.
1. Перегрузите с классе matrix3l оператор [].
2. Перегрузите оператор вставки в классе matrix3l.
3. Перегрузите оператор извлечения в классе matrix3l.
202
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
V[0] V[1] V[2] V[3] V[4] V[5] V[6] V[7] V[8] V[9] V[10] V[11] V[12] V[13] V[14] V[15] V[16] V[17]
’A’ ’B’ ’C’ ’D’ ’E’ ’F’ ’G’ ’H’ ’I’ ’J’ ’K’ ’L’ ’M’ ’N’ ’O’ ’P’ ’Q’ ’R’
2 3 4 2 3 4 2 3 4 2 3 4 2 3 4 2 3 4
-3 -3 -3 -2 -2 -2 -1 -1 -1 -3 -3 -3 -2 -2 -2 -1 -1 -1
0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1
i3=0 i3=1
i2 -3 -2 -1 i2 -3
-2 -1
i1 i1
2 ’A’ ’D’ ’G’ 2 ’J’ ’M’ ’P’
3 ’B’ ’E’ ’H’ 3 ’K’ ’N’ ’Q’
4 ’C’ ’F’ ’I’ 4 ’L’ ’O’ ’R’
рекуррентной формуле:
203
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
D1=1;
Dj=(hj-1-lj-1+1)×Dj-1, j=2,3,…,n.
Возвращаясь к нашему примеру, возьмем опять i1=4, i2=-2, i3=1.
Вспомним, что n=3,
l1=2, h1=4,
l2=-3, h2=-1,
l3=0, h3=1,
тогда
D1=1,
D2=(4-2+1)×1=3×1=3,
D3=(-1-(-3)+1)×3=3×3=9,
и
A[i1, i2,…, in] → V[(4-2)×1+(-2-(-3))×3+(1-0)×9]= V[2×1+1×3+1×9]=V[2+3+9]=V[14]=’O’.
Очевидно, что количество операций типа ’+’ и количество операций типа ’×’ выполненных
для доступа к элементу A[i1, i2,…, in] такие же как и в случае размещения “по строкам”.
Для демонстрации использования прямоугольных матриц размерности 3, размещаемых “по
столбцам”, создадим шаблонный класс matrix3c:
//
// C l a s s "m a t r i x 3 c"
//
template <class el> class matrix3c: public SD
{
protected:
public:
matrix3c<el>(int l1, int h1, int l2, int h2, int l3, int h3)
{
this->l1=l1;
this->h1=h1;
204
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
this->l2=l2;
this->h2=h2;
this->l3=l3;
this->h3=h3;
int nel=(this->h1-this->l1+1)*(this->h2-this->l2+1)*(this->h3-this->l3+1);
V = new el[nel];
nopadd=0, nopmul=0;
}
matrix3c<el>(char* file_name, int l1, int h1, int l2, int h2,
int l3, int h3):
SD(file_name)
{
this->l1=l1;
this->h1=h1;
this->l2=l2;
this->h2=h2;
this->l3=l3;
this->h3=h3;
int nel=(this->h1-this->l1+1)*(this->h2-this->l2+1)*(this->h3-this->l3+1);
V = new el[nel];
nopadd=0, nopmul=0;
}
nopadd+=9, nopmul+=5;
D1=1;
D2=(h1-l1+1)*D1;
D3=(h2-l2+1)*D2;
return V[(i1-l1)*D1+(i2-l2)*D2+(i3-l3)*D3];
205
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
virtual void show(const char* opening, const char* ending, int nlinepp=20)
{
clrscr();
printf("%s", opening);
int i1, i2, i3;
for(int i3=l3; i3<=h3; i3++)
{
printf("i3=%i\n", i3);
for(i1=l1; i1<=h1; i1++)
{
for(i2=l2; i2<=h2; i2++)
elem(i1, i2, i3).show("", " ");
printf("\n");
}
}
printf("%s", ending);
printf("End of matrix. Press any key ...\n");
getch();
}
206
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
int search(el e)
{
int position = -1;
int nel=(h1-l1+1)*(h2-l2+1)*(h3-l3+1);
for(int i=0; (position==-1) && i<nel ; i++)
if(e==this->V[i])
position=i;
return position;
}
void resetnop()
{
nopadd=0, nopmul=0;
}
207
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
0. A
1. B
2. C
3. D
4. E
5. F
6. G
7. H
8. I
9. J
10. K
11. L
12. M
13. N
14. O
15. P
16. Q
17. R
208
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Упражнения.
1. Перегрузите в классе matrix3c оператор [].
2. Перегрузите оператор вставки в классе matrix3c.
3. Перегрузите оператор извлечения в классе matrix3c.
209
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
(i
j 1
j l j ) Dj ij Dj l j Dj
j 1 j 1
Однако, как значения lj, так и числа Dj, зависят только от объявления матрицы и никак не
зависят от индексов элемента, к которому осуществляется обращение. Поэтому, для
n
оптимизации, числа Dj и величина l D
j 1
j j могут храниться в памяти компьютера, что
210
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
...
211
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
... ...
n
...
... Elem.A l1
A h1 Vector
definitor
... ... ...
...
... l D j j
...
B ... Elem.B
...
... ...
...
C
... Elem.C
...
...
public:
matrix3ldv<el>(int l1, int h1, int l2, int h2, int l3, int h3):
matrix3l<el>(l1, h1, l2, h2, l3, h3)
{
d = new int[12];
d[0]=3; // dimension
d[1]=l1;
d[2]=h1;
212
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
d[3]=l2;
d[4]=h2;
d[5]=l3;
d[6]=h3;
d[7]=(h1-l1+1)*(h2-l2+1)*(h3-l3+1); // number of elements
d[10]=1; // D3
d[9]=(h3-l3+1)*d[10]; // D2
d[8]=(h2-l2+1)*d[9]; // D1
d[11]=l1*d[8]+l2*d[9]+l3*d[10]; // Sum(ljxDj)
}
213
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
1. B
2. C
3. D
4. E
5. F
6. G
7. H
8. I
9. J
10. K
11. L
12. M
13. N
14. O
15. P
16. Q
17. R
214
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Как легко можно заметить, общее количество операций, выполненных при доступе к
элементам матрицы для вывода ее логической структуры, сократилось со 162 до 54 для ’+’ и
с 90 до 54 для ’×’.
Упражнения.
1. Перегрузите в классе matrix3ldv оператор [].
2. Сравните время доступа к элементам матрицы при непосредственном методе и при
использовании определяющего вектора.
3. Создайте на базе шаблонного класса matrix3c, шаблонный класс matrix3cdv,
наделенный определяющим вектором.
215
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
0
A 1
2
3
4
-3 -3 -3
-2 -2 -2
-1 -1 -1
0 0 0
’A’ ’B’ ’C’ ’D’ ’E’ ’F’ ’G’ ’H’ ’I’ ’J’ ’K’ ’L’ ’M’ ’N’ ’O’ ’P’ ’Q’ ’R’
2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4
-3 -3 -2 -2 -1 -1 -3 -3 -2 -2 -1 -1 -3 -3 -2 -2 -1 -1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
216
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
public:
matrix3lIl<el>(int l1, int h1, int l2, int h2, int l3, int h3):
matrix3l<el>(l1, h1, l2, h2, l3, h3)
{
int i1, i2 , d, step;
d=-l3;
step=h3-l3+1;
matrix3lIl<el>(char* file_name, int l1, int h1, int l2, int h2,
int l3, int h3):
matrix3l<el>(file_name, l1, h1, l2, h2, l3, h3)
217
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
int i1, i2 , d, step;
d=-l3;
step=h3-l3+1;
В функции main() предыдущего примера изменим только создание матрицы. На сей раз
создадим прямоугольную матрицу размерности 3, снабженную иерархией векторов Айлифа:
matrix3lIl<character> A("char.txt", 2, 4, -3, -1, 0, 1);
218
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
16. Q
17. R
219
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
I j
K L
i1=4
m N
O p
Q R
0
A 1
-3 -3
-2 -2
-1 -1
0 0
’A’ ’B’ ’C’ ’D’ ’E’ ’F’ ’G’ ’H’ ’I’ ’J’ ’K’ ’L’ ’M’ ’N’ ’O’ ’P’ ’Q’ ’R’
2 3 4 2 3 4 2 3 4 2 3 4 2 3 4 2 3 4
-3 -3 -3 -2 -2 -2 -1 -1 -1 -3 -3 -3 -2 -2 -2 -1 -1 -1
0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1
220
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
public:
matrix3cIl<el>(int l1, int h1, int l2, int h2, int l3, int h3):
matrix3c<el>(l1, h1, l2, h2, l3, h3)
{
int i3, i2 , d, step;
d=-l1;
step=h1-l1+1;
221
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
matrix3cIl<el>(char* file_name, int l1, int h1, int l2, int h2,
int l3, int h3):
matrix3c<el>(file_name, l1, h1, l2, h2, l3, h3)
{
int i3, i2 , d, step;
d=-l1;
step=h1-l1+1;
222
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
7. H
8. I
9. J
10. K
11. L
12. M
13. N
14. O
15. P
16. Q
17. R
223
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
a D G
g E H
m F I
i3=1
J d P
K j Q
L p R
Анализ результатов и выводы такие же как и для случая размещения элементов “по
строкам”.
Упражнения.
1. Перегрузите в классе matrix3cIl оператор [].
2. Разработайте класс, который бы позволял использовать одну и ту же иерархию векторов
Айлифа для нескольких матриц, размещаемых “по столбцам” и имеющих одну и ту же
структуру.
224
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
6. ЗАДАНИЯ
225
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
– II – Работа с таблицами
Простые неупорядоченные таблицы
На базе абстрактного класса SD (см. 1.2) создайте конкретный шаблонный класс table для
работы с простыми неупорядоченными таблицами.
Создайте простую неупорядоченную таблицу, загрузив исходные данные из текстового
файла. Продемонстрируйте последовательный поиск табличных записей по ключу.
Определите среднюю длину поиска для данной таблицы и сравните ее с теоретической
оценкой сложности алгоритма последовательного просмотра, выраженной средней длиной
поиска.
226
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
– III – Сортировки
Класс для тестирования алгоритмов сортировки
Создайте на базе абстрактного класса SD конкретный шаблонный класс vector который
будет использован для представления векторов с элементами – объектами выбранной
предметной области. В отличии от таблиц, векторы допускают элементы с равными
ключами.
Быстрая сортировка
Создайте на базе класса vector шаблонный класс, снабженный алгоритмом быстрой
сортировки.
Создайте конкретный вектор с использованием имеющегося текстового файла. Выведите
исходный несортированный вектор, отсортируйте вектор по ключу алгоритмом быстрой
сортировки, выведите отсортированный вектор. Выведите число сравнений ключей и число
перестановок элементов, выполненных в ходе сортировки, и сравните их с теоретическими
оценками сложности алгоритма быстрой сортировки. Проделайте то же самое с другими
ключами.
227
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
228
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Двунаправленные списки
Создайте на базе абстрактного класса SD конкретный шаблонный класс для представления
двунаправленных списков.
Создайте на основе имеющегося текстового файла конкретный двунаправленный список и
продемонстрируйте поиск в нем по ключу. Определите среднюю длину поиска для этого
списка и сравните с теоретической оценкой алгоритма поиска в двунаправленном списке по
ключу. Продемонстрируйте методы добавления нового элемента в список, удаления
элемента из списка и др.
229
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
– V – Матрицы
Матрицы с прямым доступом
Объявите на базе абстрактного класса SD конкретный шаблонный класс matrix4l для
представления прямоугольных матриц порядка 4 с элементами, размещаемыми “по строкам.
Покажите на примере использование этого класса, объявив матрицу с типом элементов и с
диапазонами индексов, указанных преподавателем.
Объявите на базе абстрактного класса SD конкретный шаблонный класс matrix3c для
представления прямоугольных матриц порядка 4 с элементами, размещаемыми “по
столбцам. Покажите на примере использование этого класса, объявив матрицу с типом
элементов и с диапазонами индексов, указанных преподавателем.
230
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
231
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
БИБЛИОГРАФИЯ
232
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
using System;
using System.IO;
struct MainApp
{
string s;
char[] separator = new char[] { ' ', '\t' };
using System;
using System.IO;
struct usual_elem
{
public string name;
public int year;
public double salary;
struct MainApp
{
static void Main()
{
string s;
char[] separator = new char[] { ' ', '\t' };
233
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
usual_elem ue;
ue.name = se[0];
ue.year = int.Parse(se[1]);
ue.salary = double.Parse(se[2]);
ue.Show();
}
fstr_in.Close();
using System;
using System.IO;
//
// a b s t r a c t c l a s s "e l e m"
//
abstract class elem
{
public abstract int fscanf_el(StreamReader f);
234
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
//
// c l a s s "u s u a l _ e l e m"
//
class usual_elem : elem
{
public usual_elem()
{
name = "";
year = 0;
salary = 0.0;
}
if (succes)
{
string[] se = s.Split(separator,
StringSplitOptions.RemoveEmptyEntries);
name = se[0];
235
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
year = int.Parse(se[1]);
salary = double.Parse(se[2]);
}
return succes ? 1 : 0;
}
//
236
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
// A b s t r a c t c l a s s "S D"
//
abstract class SD
{
protected static StreamReader pf;
protected static long ncomp;
public SD()
{
}
~SD()
{
if (pf != null)
pf.Close();
}
237
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
ПРИЛОЖЕНИЕ 2. ТАБЛИЦЫ НА C#
//
// C l a s s "t a b l e"
//
//class table<el> : SD
class table : SD
{
protected int n; // Number of table records
protected usual_elem[] t; // Vector of table records
n = 0;
int repeated;
while (!pf.EndOfStream)
{
t[n] = new usual_elem();
if (t[n].fscanf_el(pf) > 0)
{
// t[n].show("--> ", "\n");
if ((repeated = search(t[n])) >= 0)
{
error("Key coincides with the key in the position: " +
(repeated + 1) + "!\n");
}
n++;
}
}
pf.Close();
pf = null;
}
Console.Write(opening);
for (int i = 0; i < n; i++)
{
if ((i > 0) && (i % nlinepp == 0))
{
Console.Write("Press any key to continue... ");
Console.ReadKey();
Console.Clear();
Console.Write(opening);
}
Console.Write("{0,4:D}. ", (i + 1));
if((object)t[i] != null)
t[i].show("", "\n");
238
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
else
Console.WriteLine();
}
Console.Write(ending);
Console.Write("End of Table. Press any key to continue... ");
Console.ReadKey();
Console.WriteLine();
}
public int N
{
get
{
return n;
}
}
}
//
// c l a s s "t r e e l i k e" e l e m e n t s
//
class tree_like : usual_elem
{
protected int less;
protected int greater;
public tree_like()
{
less = greater = -1;
}
239
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
}
}
//
// C l a s s "t r e e _ t a b l e"
//
class tree_table : SD
{
protected int n; // Number of table records
protected tree_like[] t; // Vector of table records
n = 0;
int repeated;
while (!pf.EndOfStream)
{
t[n] = new tree_like();
if (t[n].fscanf_el(pf) > 0)
{
// t[n].show("--> ", "\n");
if ((repeated = secv_search(t[n])) >= 0)
{
error("Key coincides with the key in the position: " +
(repeated + 1) + "!\n");
}
240
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
n++;
}
}
pf.Close();
pf = null;
Console.Write(opening);
for (int i = 0; i < n; i++)
{
if ((i > 0) && (i % nlinepp == 0))
{
Console.Write("Press any key to continue... ");
Console.ReadKey();
Console.Clear();
Console.Write(opening);
}
Console.Write("{0,4:D}. ", (i + 1));
t[i].show("", "\n");
}
Console.Write(ending);
Console.Write("End of Table. Press any key to continue... ");
Console.ReadKey();
Console.WriteLine();
}
241
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Console.Clear();
Console.Write(opening);
}
Console.Write("{0,4:D}. ", (i + 1));
t[i].tree_show("", "\n");
}
Console.Write(ending);
Console.Write("End of Table. Press any key to continue... ");
Console.ReadKey();
Console.WriteLine();
}
while (forward)
{
ncomp++;
if ((cmp_result = e.cmp(t[i])) == 0)
{
position = i;
forward = false;
}
else
{
if (cmp_result < 0)
i = t[i].Less;
else
i = t[i].Greater;
if (i == -1)
forward = false;
}
}
return position;
}
public int N
{
get
{
return n;
}
}
242
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
/*
//
// C l a s s "t r e e _ e l e m"
//
class tree_elem
{
protected int less;
protected int greater;
public tree_elem() {
less = greater = -1;
}
//
// C l a s s "t r e e _ t a b l e"
//
class tree_table : table
{
protected tree_elem[] p;
243
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
j = p[j].Less;
else
if (t[i] > t[j])
if (p[j].Greater == -1) {
p[j].Greater = i;
forward = false;
}
else
j = p[j].Greater;
}
}
while (forward) {
ncomp++;
if ((cmp_result = e.cmp(t[i])) == 0) {
position = i;
forward = false;
}
else {
if (cmp_result < 0)
i = p[i].Less;
else
i = p[i].Greater;
if (i == -1)
forward = false;
}
}
return position;
}
}
*/
//
// C l a s s "s o r t e d t a b l e"
244
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
//
class sorted_table : table
{
public sorted_table(int NMAX)
: base(NMAX)
{
}
n = 0;
pf = new StreamReader(file_name);
if (pf == null)
error("File " + file_name + " not found!\n");
while (!pf.EndOfStream)
if ((tmp = new usual_elem()).fscanf_el(pf) > 0)
{
// tmp.show("--> ", "\n");
for (i = n - 1; (i >= 0) && (tmp < t[i]); i--)
t[i + 1] = t[i];
if ((n > 0) && (i >= 0) && (tmp == t[i]))
error("Key coincides with the key in the position: " + (i +
1) + "!\n");
if(n == i + 1)
t[n] = new usual_elem();
t[i + 1] = tmp;
n++;
}
pf.Close();
pf = null;
}
// Binary search
public int search(usual_elem e)
{
int a = 0, b = n - 1;
int result;
while (a < b)
{
int i = (a + b) / 2;
ncomp++;
if ((result = e.cmp(t[i])) > 0)
a = i + 1;
else
if (result < 0)
b = i;
else
a = b = i;
}
ncomp++;
return (e == t[a]) ? a : -1;
}
/*
// Fibonaccian search
public int fibsearch(usual_elem e)
{
int result;
int j = 1;
245
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
ncomp++;
while ( ( (result = e.cmp(t[mid - 1])) != 0 ) && forward
) {
// while ( forward && ( (result = e.cmp(t[mid - 1])) != 0 ) )
{
if ((mid <= 0) || (result > 1))
if (f1 == 1)
forward = false;
else {
mid += f2;
f1 -= f2;
f2 -= f1;
}
else
if (f2 == 0)
forward = false;
else {
mid -= f2;
int tmp = f1 - f2;
f1 = f2;
f2 = tmp;
}
// if(forward)
ncomp++;
}
return forward ? (mid - 1) : -1;
}
//
// C l a s s "h a s h i n g _ e l e m"
//
class hashing_elem : usual_elem
{
public hashing_elem()
{
}
246
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
//
// C l a s s "h a s h i n g t a b l e"
//
class hashing_table : table
{
protected int m;
hashing_elem tmp;
int repeated;
pf = new StreamReader(file_name);
if (pf == null)
error("File " + file_name + " not found!\n");
while (!pf.EndOfStream)
if ((tmp = new hashing_elem()).fscanf_el(pf) > 0)
{
// tmp.show("--> ", "\n");
// Console.ReadKey();
int i = tmp.hf(n);
repeated = -1;
while ((repeated == -1) && ((object)t[i] != null))
{
if (tmp == t[i])
repeated = i;
else
i = (i + 1) % n;
}
if (repeated != -1)
error("Key coincides with the key in the position: " +
(repeated + 1) + "!\n");
t[i] = tmp;
m++;
}
pf.Close();
pf = null;
}
247
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
public int M
{
get
{
return m;
}
}
}
/*
// --- Table Searching ---
struct MainApp {
static void Main() {
char ch='n';
while(ch!='y') {
Console.Write("Enter a name to search: ");
string surname = Console.ReadLine();
usual_elem e = new usual_elem(surname, 2000, 0.0);
// e.show("Table record: ", "\n");
gr.reset_ncomp();
int pos=gr.search(e);
if(pos < 0) {
Console.Write("No table! ");
Console.WriteLine("The number of comparisons: {0:D}",
gr.get_ncomp());
}
else {
Console.Write("There are in the position: {0:D}. ", pos + 1);
Console.WriteLine("The number of comparisons: {0:D}",
gr.get_ncomp());
}
Console.Write("Done ? (y/n) ");
ConsoleKeyInfo info = Console.ReadKey();
Console.WriteLine();
ch = info.KeyChar;
}
}
}
*/
/*
// --- Table ALS ---
struct MainApp {
static void Main() {
while (!pf.EndOfStream)
if(sample.fscanf_el(pf) > 0) {
gr.reset_ncomp();
if (gr.search(sample) >= 0)
NCOMP += gr.get_ncomp();
248
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
}
pf.Close();
Console.WriteLine("N={0:D}, NCOMP={1:D}, ALS={2:F2}", gr.get_n(), NCOMP,
(double)NCOMP/gr.get_n());
char ch='n';
while(ch!='y') {
Console.Write("Enter a name to search: ");
string surname = Console.ReadLine();
tree_like e = new tree_like(surname, 2000, 0.0);
// e.show("Table record: ", "\n");
gr.Ncomp = 0;
int pos=gr.search(e);
if(pos < 0) {
Console.Write("No table! ");
Console.WriteLine("The number of comparisons: {0:D}", gr.Ncomp);
}
else {
Console.Write("There are in the position: {0:D}. ", pos + 1);
Console.WriteLine("The number of comparisons: {0:D}", gr.Ncomp);
}
Console.Write("Done ? (y/n) ");
ConsoleKeyInfo info = Console.ReadKey();
Console.WriteLine();
ch = info.KeyChar;
}
}
}
*/
/*
// --- tree_table ALS ---
struct MainApp {
static void Main() {
while (!pf.EndOfStream)
if(sample.fscanf_el(pf) > 0) {
gr.Ncomp = 0;
if (gr.search(sample) >= 0)
NCOMP += gr.Ncomp;
}
pf.Close();
249
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
/*
// --- Sorted table Searching ---
struct MainApp {
static void Main() {
char ch='n';
while(ch!='y') {
Console.Write("Enter a name to search: ");
string surname = Console.ReadLine();
usual_elem e = new usual_elem(surname, 2000, 0.0);
// e.show("Table record: ", "\n");
sorted_gr.Ncomp = 0;
int pos = sorted_gr.search(e);
// int pos = sorted_gr.fibsearch(e);
if(pos < 0) {
Console.Write("No table! ");
Console.WriteLine("The number of comparisons: {0:D}",
sorted_gr.Ncomp);
}
else {
Console.Write("There are in the position: {0:D}. ", pos + 1);
Console.WriteLine("The number of comparisons: {0:D}",
sorted_gr.Ncomp);
}
Console.Write("Done ? (y/n) ");
ConsoleKeyInfo info = Console.ReadKey();
Console.WriteLine();
ch = info.KeyChar;
}
}
}
*/
/*
// --- Sorted table ALS ---
struct MainApp {
static void Main() {
while (!pf.EndOfStream)
if(sample.fscanf_el(pf) > 0) {
sorted_gr.Ncomp = 0;
if (sorted_gr.search(sample) >= 0)
// if (sorted_gr.fibsearch(sample) >= 0)
250
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
NCOMP += sorted_gr.Ncomp;
}
pf.Close();
Console.Write("N={0:D}, NCOMP={1:D}, ALS={2:F2}", sorted_gr.N, NCOMP,
(double)NCOMP / sorted_gr.N);
Console.WriteLine(", ALS_TEOR={0:F2}", Math.Log((double)sorted_gr.N) /
Math.Log(2.0) + 2.0);
char ch='n';
while(ch!='y') {
Console.Write("Enter a name to search: ");
string surname = Console.ReadLine();
hashing_elem e = new hashing_elem(surname, 2000, 0.0);
// e.show("Table record: ", "\n");
gr.Ncomp = 0;
int pos = gr.search(e);
if(pos < 0) {
Console.Write("No table! ");
Console.WriteLine("The number of comparisons: {0:D}",
gr.get_ncomp());
}
else {
Console.Write("There are in the position: {0:D}. ", pos + 1);
Console.WriteLine("The number of comparisons: {0:D}",
gr.get_ncomp());
}
Console.Write("Done ? (y/n) ");
ConsoleKeyInfo info = Console.ReadKey();
Console.WriteLine();
ch = info.KeyChar;
}
}
}
*/
/*
// --- Hashing table ALS ---
struct MainApp
{
static void Main()
{
while (!pf.EndOfStream)
if (sample.fscanf_el(pf) > 0)
251
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
gr.Ncomp = 0;
if (gr.search(sample) >= 0)
NCOMP += gr.Ncomp;
}
pf.Close();
252
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
ПРИЛОЖЕНИЕ 3. СОРТИРОВКА НА C#
//
// C l a s s "v e c t o r"
//
//class vector<el> : SD
class vector : SD
{
protected int n; // Number of elements
protected usual_elem[] t; // Vector of elements
n = 0;
while (!pf.EndOfStream)
{
t[n] = new usual_elem();
if (t[n].fscanf_el(pf) > 0)
n++;
}
pf.Close();
pf = null;
}
Console.Write(opening);
for (int i = 0; i < n; i++)
{
if ((i > 0) && (i % nlinepp == 0))
{
Console.Write("Press any key to continue... ");
Console.ReadKey();
Console.Clear();
Console.Write(opening);
}
Console.Write("{0,4:D}. ", (i + 1));
t[i].show("", "\n");
}
Console.Write(ending);
Console.Write("End of Vector. Press any key to continue... ");
Console.ReadKey();
Console.WriteLine();
}
253
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
public int N
{
get
{
return n;
}
}
//
// C l a s s " v e c t o r q u i c k s o r t"
//
class vector_quicksort : vector
{
public vector_quicksort(string file_name, int NMAX) :
base(file_name, NMAX)
{
}
254
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
imed = (i + j) / 2;
ncomp++;
if (t[i] < t[imed])
{
ncomp++;
if (t[imed] < t[j])
imain = imed;
else
{
ncomp++;
if (t[i] < t[j])
imain = j;
else
imain = i;
}
}
else
{
ncomp++;
if (t[imed] > t[j])
imain = imed;
else
{
ncomp++;
if (t[i] > t[j])
imain = j;
else
imain = i;
}
}
if (imain > i)
swap(i, imain);
imain = i + 1;
jmain = j;
while (imain < jmain)
{
bool forward = true;
while (forward)
{
255
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
ncomp++;
if (t[imain] > t[i])
imain--;
if (imain > i)
swap(i, imain);
return imain;
}
}
//
// C l a s s " v e c t o r o p t i m q u i c k s o r t "
//
class vector_optim_quicksort : vector_quicksort
{
protected int threshold;
256
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
if (j >= n || j == -1)
j = n - 1;
if (i < 0 || i > j)
i = 0;
quicksort_intern(i, j);
}
}
}
}
//
// C l a s s "v e c t o r _ h e a p s o r t "
//
class vector_heapsort: vector
{
public vector_heapsort(string file_name, int NMAX):
base(file_name, NMAX)
{
}
257
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
planting();
maxtreesort();
}
if(next != pred)
swap(pred, next); // We change elements with places
// t[pred] and t[next]
}
} while(pred!=next);
}
/*
// --- Quicksort ---
struct MainApp
{
static void Main()
{
258
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
/*
// --- Heapsort ---
struct MainApp
{
static void Main()
{
259
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
//
// C l a s s "b i n t r e e"
//
//class bintree<el> : SD
class bintree : SD
{
protected bintree pleft;
protected bintree pright;
protected usual_elem pdata;
public bintree()
{
pdata = null;
pleft = pright = null;
}
bintree pcurrent_nod;
usual_elem pnewel;
while (!pf.EndOfStream)
{
pnewel = new usual_elem();
if (pnewel.fscanf_el(pf) > 0)
{
//pnewel.show(" --- ","\n");
//Console.ReadKey();
pcurrent_nod = this;
while ((object)pcurrent_nod.pdata != null)
{
if (pnewel < pcurrent_nod.pdata)
{
if ((object)pcurrent_nod.pleft == null)
pcurrent_nod.pleft = new bintree();
pcurrent_nod = pcurrent_nod.pleft;
}
else
{
if ((object)pcurrent_nod.pright == null)
pcurrent_nod.pright = new bintree();
pcurrent_nod = pcurrent_nod.pright;
}
}
pcurrent_nod.pdata = pnewel;
}
}
pf.Close();
pf = null;
}
260
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
if ((object)pdata != null)
pdata.show("", "\n");
if ((object)pleft != null)
pleft.show_preorder("", "");
if ((object)pright != null)
pright.show_preorder("", "");
Console.Write(ending);
}
if ((object)pleft != null)
pleft.show_inorder("", "");
if ((object)pdata != null)
pdata.show("", "\n");
if ((object)pright != null)
pright.show_inorder("", "");
Console.Write(ending);
}
if ((object)pleft != null)
pleft.show_postorder("", "");
if ((object)pright != null)
pright.show_postorder("", "");
if ((object)pdata != null)
pdata.show("", "\n");
Console.Write(ending);
}
if ((object)pcurrent_nod.pdata != null)
forward = true;
else
261
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
forward = false;
while(forward)
{
ncomp++;
if ((cmp_result = e.cmp(pcurrent_nod.pdata)) == 0)
{
found = true;
forward = false;
}
else
{
if (cmp_result < 0)
if ((object)pcurrent_nod.pleft != null)
pcurrent_nod = pcurrent_nod.pleft;
else
forward = false;
else
if ((object)pcurrent_nod.pright != null)
pcurrent_nod = pcurrent_nod.pright;
else
forward = false;
}
}
/*
struct MainApp
{
static void Main()
{
btgr.show_preorder("Group in preorder\n","\n");
btgr.show_inorder("Group in inorder\n","\n");
btgr.show_postorder("Group in postorder\n","\n");
262
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
btgr.show("Group:\n","", 0);
char ch='n';
while(ch!='y')
{
Console.Write("Enter a name to search: ");
string surname = Console.ReadLine();
usual_elem e = new usual_elem(surname, 2000, 0.0);
btgr.Ncomp = 0;
usual_elem p = btgr.search(e);
if((object)p == null) {
Console.Write("No bintree! ");
Console.WriteLine("The number of comparisons: {0:D}",
btgr.Ncomp);
}
else {
Console.Write("There are in the bintree: ");
p.show("", "\n");
Console.WriteLine("The number of comparisons: {0:D}",
btgr.Ncomp);
}
Console.Write("Done ? (y/n) ");
ConsoleKeyInfo info = Console.ReadKey();
Console.WriteLine();
ch = info.KeyChar;
}
}
}
*/
/*
struct MainApp
{
static void Main()
{
bintree btgr = new bintree("Stud.txt");
btgr.show("Group:\n","", 0);
263
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
}
pf.Close();
Console.Write("n={0:D}, NCOMP={1:D}, ALS={2:F2}", nelem, NCOMP,
(double)NCOMP / nelem);
Console.WriteLine(", MAX={0:F2}, MIN={1:F2}", (nelem + 1) / 2.0,
Math.Log((double)nelem) / Math.Log(2.0) + 2.0);
char ch = 'n';
while (ch != 'y')
{
Console.Write("Enter a name to search: ");
string surname = Console.ReadLine();
usual_elem e = new usual_elem(surname, 2000, 0.0);
btgr.Ncomp = 0;
usual_elem p = btgr.preorder_search(e);
if ((object)p == null)
{
Console.Write("No bintree! ");
Console.WriteLine("The number of comparisons: {0:D}",
btgr.Ncomp);
}
else
{
Console.Write("There are in the bintree: ");
p.show("", "\n");
Console.WriteLine("The number of comparisons: {0:D}",
btgr.Ncomp);
}
Console.Write("Done ? (y/n) ");
ConsoleKeyInfo info = Console.ReadKey();
Console.WriteLine();
ch = info.KeyChar;
}
}
}
*/
/*
struct MainApp
{
static void Main()
{
bintree btgr = new bintree("Stud.txt");
btgr.show_preorder("Group:\n", "");
264
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
if (sample.fscanf_el(pf) > 0)
{
btgr.Ncomp = 0;
if ((object)(btgr.preorder_search(sample)) != null)
{
NCOMP += btgr.Ncomp;
nelem++;
}
}
pf.Close();
Console.Write("n={0:D}, NCOMP={1:D}, ALS={2:F2}", nelem, NCOMP,
(double)NCOMP / nelem);
Console.WriteLine(", MAX={0:F2}, MIN={1:F2}", (nelem + 1) / 2.0,
Math.Log((double)nelem) / Math.Log(2.0) + 2.0);
265
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
ПРИЛОЖЕНИЕ 5. СПИСКИ НА C#
//
// C l a s s "l i s t"
//
class list : SD
{
protected list pnext;
protected usual_elem pdata;
public list()
{
pdata = null;
pnext = null;
}
list pcurrent_nod;
usual_elem pnewel;
pcurrent_nod = this;
while (!pf.EndOfStream)
{
pnewel = new usual_elem();
if (pnewel.fscanf_el(pf) > 0)
{
//pnewel.show(" --- ","\n");
//Console.ReadKey();
if ((object)pcurrent_nod.pdata != null)
{
pcurrent_nod.pnext = new list();
pcurrent_nod = pcurrent_nod.pnext;
}
pcurrent_nod.pdata = pnewel;
}
}
pf.Close();
pf = null;
}
Console.Write(opening);
list pcurrent_nod = this;
if ((object)pcurrent_nod.pdata != null)
{
int i = 1;
Console.Write("{0,4:D}. ", i);
pcurrent_nod.pdata.show("", "\n");
while ((object)(pcurrent_nod = pcurrent_nod.pnext) != null)
{
if ((i > 0) && (i % nlinepp == 0))
266
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
Console.Write("Press any key to continue... ");
Console.ReadKey();
Console.Clear();
Console.Write(opening);
}
i++;
Console.Write("{0,4:D}. ", i);
pcurrent_nod.pdata.show("", "\n");
}
}
Console.Write(ending);
Console.Write("End of List. Press any key to continue... ");
Console.ReadKey();
Console.WriteLine();
}
if ((object)pcurrent_nod.pdata != null)
{
int i = 0;
ncomp++;
if (pcurrent_nod.pdata == e)
position = i;
while (position == -1 && (object)pcurrent_nod.pnext != null )
{
i++;
pcurrent_nod = pcurrent_nod.pnext;
ncomp++;
if (pcurrent_nod.pdata == e)
position = i;
}
}
return position;
}
}
//
// C l a s s "b i d i r e c t i o n a l l i s t"
//
class bidirectional_list : SD
{
protected bidirectional_list pnext;
protected bidirectional_list ppred;
protected usual_elem pdata;
public bidirectional_list()
{
pdata = null;
pnext = ppred = null;
}
bidirectional_list pcurrent_nod;
267
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
usual_elem pnewel;
pcurrent_nod = this;
while (!pf.EndOfStream)
{
pnewel = new usual_elem();
if (pnewel.fscanf_el(pf) > 0)
{
//pnewel.show(" --- ","\n");
//Console.ReadKey();
if ((object)pcurrent_nod.pdata != null)
{
pcurrent_nod.pnext = new bidirectional_list();
pcurrent_nod.pnext.ppred = pcurrent_nod;
pcurrent_nod = pcurrent_nod.pnext;
}
pcurrent_nod.pdata = pnewel;
}
}
pf.Close();
pf = null;
}
Console.Write(opening);
bidirectional_list pcurrent_nod = this;
if ((object)pcurrent_nod.pdata != null)
{
int i = 1;
Console.Write("{0,4:D}. ", i);
pcurrent_nod.pdata.show("", "\n");
while ((object)(pcurrent_nod = pcurrent_nod.pnext) != null)
{
if ((i > 0) && (i % nlinepp == 0))
{
Console.Write("Press any key to continue... ");
Console.ReadKey();
Console.Clear();
Console.Write(opening);
}
i++;
Console.Write("{0,4:D}. ", i);
pcurrent_nod.pdata.show("", "\n");
}
}
Console.Write(ending);
Console.Write("End of List. Press any key to continue... ");
Console.ReadKey();
Console.WriteLine();
}
Console.Write(opening);
bidirectional_list pcurrent_nod = this;
if ((object)pcurrent_nod.pdata != null)
{
while ((object)pcurrent_nod.pnext != null)
pcurrent_nod = pcurrent_nod.pnext;
268
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
int i = 1;
Console.Write("{0,4:D}. ", i);
pcurrent_nod.pdata.show("", "\n");
while ((object)(pcurrent_nod = pcurrent_nod.ppred) != null)
{
if ((i > 0) && (i % nlinepp == 0))
{
Console.Write("Press any key to continue... ");
Console.ReadKey();
Console.Clear();
Console.Write(opening);
}
i++;
Console.Write("{0,4:D}. ", i);
pcurrent_nod.pdata.show("", "\n");
}
}
Console.Write(ending);
Console.Write("End of List. Press any key to continue... ");
Console.ReadKey();
Console.WriteLine();
}
if ((object)pcurrent_nod.pdata != null)
{
int i = 0;
ncomp++;
if (pcurrent_nod.pdata == e)
position = i;
while (position == -1 && (object)pcurrent_nod.pnext != null )
{
i++;
pcurrent_nod = pcurrent_nod.pnext;
ncomp++;
if (pcurrent_nod.pdata == e)
position = i;
}
}
return position;
}
}
//
// C l a s s "n o d e _ l i s t"
//
class node_list
{
protected node_list pnext;
protected usual_elem pdata;
public node_list()
{
pnext = null;
pdata = null;
}
269
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
//
// C l a s s "m a i n _ l i s t"
//
class main_list : SD
{
protected node_list pfirst;
public main_list()
{
pfirst = null;
}
node_list pcurrent_nod;
usual_elem pnewel;
pcurrent_nod = pfirst;
while (!pf.EndOfStream)
{
pnewel = new usual_elem();
if (pnewel.fscanf_el(pf) > 0)
{
//pnewel.show(" --- ","\n");
//Console.ReadKey();
if ((object)pcurrent_nod.Pdata != null)
{
pcurrent_nod.Pnext = new node_list();
pcurrent_nod = pcurrent_nod.Pnext;
}
270
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
pcurrent_nod.Pdata = pnewel;
}
}
pf.Close();
pf = null;
}
Console.Write(opening);
node_list pcurrent_nod = this.pfirst;
if ((object)pcurrent_nod.Pdata != null)
{
int i = 1;
Console.Write("{0,4:D}. ", i);
pcurrent_nod.Pdata.show("", "\n");
while ((object)(pcurrent_nod = pcurrent_nod.Pnext) != null)
{
if ((i > 0) && (i % nlinepp == 0))
{
Console.Write("Press any key to continue... ");
Console.ReadKey();
Console.Clear();
Console.Write(opening);
}
i++;
Console.Write("{0,4:D}. ", i);
pcurrent_nod.Pdata.show("", "\n");
}
}
Console.Write(ending);
Console.Write("End of List. Press any key to continue... ");
Console.ReadKey();
Console.WriteLine();
}
if ((object)pcurrent_nod.Pdata != null)
{
int i = 0;
ncomp++;
if (pcurrent_nod.Pdata == e)
position = i;
while (position == -1 && (object)pcurrent_nod.Pnext != null)
{
i++;
pcurrent_nod = pcurrent_nod.Pnext;
ncomp++;
if (pcurrent_nod.Pdata == e)
position = i;
}
}
return position;
}
}
271
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
/*
// List utilisation
struct MainApp
{
static void Main()
{
char ch = 'n';
while (ch != 'y')
{
Console.Write("Enter a name to search: ");
string surname = Console.ReadLine();
usual_elem e = new usual_elem(surname, 2000, 0.0);
gr.Ncomp = 0;
int pos = gr.search(e);
if (pos < 0)
{
Console.Write("No List! ");
Console.WriteLine("The number of comparisons: {0:D}", gr.Ncomp);
}
else
{
Console.Write("There are in the position {0:D}\n", pos + 1);
Console.WriteLine("The number of comparisons: {0:D}\n",
gr.Ncomp);
}
Console.Write("Done ? (y/n) ");
ConsoleKeyInfo info = Console.ReadKey();
Console.WriteLine();
ch = info.KeyChar;
}
}
}
*/
/*
// Bidirectional list utilisation
struct MainApp
{
static void Main()
{
bidirectional_list gr = new bidirectional_list("Pstud.txt");
char ch = 'n';
while (ch != 'y')
{
Console.Write("Enter a name to search: ");
string surname = Console.ReadLine();
usual_elem e = new usual_elem(surname, 2000, 0.0);
gr.Ncomp = 0;
int pos = gr.search(e);
if (pos < 0)
{
Console.Write("No List! ");
Console.WriteLine("The number of comparisons: {0:D}", gr.Ncomp);
}
else
272
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
Console.Write("There are in the position {0:D}\n", pos + 1);
Console.WriteLine("The number of comparisons: {0:D}\n",
gr.Ncomp);
}
Console.Write("Done ? (y/n) ");
ConsoleKeyInfo info = Console.ReadKey();
Console.WriteLine();
ch = info.KeyChar;
}
}
}
*/
273
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
ПРИЛОЖЕНИЕ 6. СТЕКИ НА C#
//
// C l a s s "s t a c k f i x e d b u f f e r"
//
class stackFB : SD
{
protected usual_elem[] buffer;
protected int size, top;
usual_elem newel;
while (!pf.EndOfStream)
{
newel = new usual_elem();
if (newel.fscanf_el(pf) > 0)
push(newel);
}
pf.Close();
pf = null;
}
274
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Console.Write(opening);
if (!isempty())
{
int i = 1;
Console.Write("{0,4:D}. ", i);
int current = top - 1;
buffer[current].show("", "\n");
while (--current >= 0)
{
if ((i > 0) && (i % nlinepp == 0))
{
Console.Write("Press any key to continue... ");
Console.ReadKey();
Console.Clear();
Console.Write(opening);
}
i++;
Console.Write("{0,4:D}. ", i);
buffer[current].show("", "\n");
}
}
Console.Write(ending);
Console.Write("End of Stack. Press any key to continue... ");
Console.ReadKey();
Console.WriteLine();
}
}
//
// C l a s s "s t a c k l i s t"
//
class stackL : SD
{
protected stackL pnext;
protected usual_elem pdata;
public stackL()
{
pdata = null;
pnext = null;
}
stackL pcurrent_nod;
usual_elem pnewel;
pcurrent_nod = this;
while (!pf.EndOfStream)
{
pnewel = new usual_elem();
if (pnewel.fscanf_el(pf) > 0)
push(pnewel);
}
pf.Close();
pf = null;
275
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
if ((object)this.pnext != null)
{
stackL ptemp = this.pnext;
this.pnext = ptemp.pnext;
this.pdata = ptemp.pdata;
}
else
this.pdata = null;
return pret;
}
else
{
error("Stack is empty!");
return null;
}
}
Console.Write(opening);
stackL pcurrent_nod = this;
if ((object)pcurrent_nod.pdata != null)
{
int i = 1;
Console.Write("{0,4:D}. ", i);
pcurrent_nod.pdata.show("", "\n");
while ((object)(pcurrent_nod = pcurrent_nod.pnext) != null)
{
if ((i > 0) && (i % nlinepp == 0))
{
Console.Write("Press any key to continue... ");
Console.ReadKey();
276
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Console.Clear();
Console.Write(opening);
}
i++;
Console.Write("{0,4:D}. ", i);
pcurrent_nod.pdata.show("", "\n");
}
}
Console.Write(ending);
Console.Write("End of Stack. Press any key to continue... ");
Console.ReadKey();
Console.WriteLine();
}
}
///*
// Stack utilisation
struct MainApp
{
static void Main()
{
Console.WriteLine("\nExtracting by one:");
while(!gr.isempty())
{
Console.WriteLine("Press any key...");
ConsoleKeyInfo info = Console.ReadKey();
Console.WriteLine();
usual_elem extracted_el;
extracted_el = gr.pop();
extracted_el.show("","\n");
}
Console.WriteLine("Stack is empty! Press any key...");
Console.ReadKey();
Console.WriteLine();
Console.WriteLine();
gr.pop().show("","\n");
gr.pop().show("","\n");
277
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
//
// C l a s s "s t a c k _ e l e m"
//
class stack_elem
{
protected SD p;
protected char t;
public stack_elem()
{
p = null;
t = '\0';
}
public SD P
{
set
{
p = value;
}
get
{
return p;
}
}
public char T
{
set
{
t = value;
}
get
{
return t;
}
}
}
//
// C l a s s "s t a c k f i x e d b u f f e r"
//
class stackFB : SD
{
protected stack_elem[] buffer;
protected int size, top;
278
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
//
// C l a s s "s t a c k l i s t"
//
class stackL : SD
{
protected stackL pnext;
protected stack_elem pdata;
public stackL()
{
pdata = null;
pnext = null;
}
279
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
stack_elem pret = this.pdata;
if ((object)this.pnext != null)
{
stackL ptemp = this.pnext;
this.pnext = ptemp.pnext;
this.pdata = ptemp.pdata;
}
else
this.pdata = null;
return pret;
}
else
{
error("Stack is empty!");
return null;
}
}
//
// C l a s s "b i n t r e e s t a c k"
//
class bintree_stack : SD
{
protected bintree_stack pleft;
protected bintree_stack pright;
protected usual_elem pdata;
public bintree_stack()
{
pdata = null;
pleft = pright = null;
}
bintree_stack pcurrent_nod;
usual_elem pnewel;
while (!pf.EndOfStream)
{
pnewel = new usual_elem();
if (pnewel.fscanf_el(pf) > 0)
{
//pnewel.show(" --- ","\n");
//Console.ReadKey();
pcurrent_nod = this;
while ((object)pcurrent_nod.pdata != null)
{
if (pnewel < pcurrent_nod.pdata)
{
280
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
if ((object)pcurrent_nod.pleft == null)
pcurrent_nod.pleft = new bintree_stack();
pcurrent_nod = pcurrent_nod.pleft;
}
else
{
if ((object)pcurrent_nod.pright == null)
pcurrent_nod.pright = new bintree_stack();
pcurrent_nod = pcurrent_nod.pright;
}
}
pcurrent_nod.pdata = pnewel;
}
}
pf.Close();
pf = null;
}
281
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
282
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
if (((bintree_stack)pcur.P).pright != null)
st.push(new stack_elem(((bintree_stack)pcur.P).pright,
'r'));
if ((object)(((bintree_stack)pcur.P).pdata) != null)
st.push(new stack_elem(pcur.P, 'n'));
if (((bintree_stack)pcur.P).pleft != null)
st.push(new stack_elem(((bintree_stack)pcur.P).pleft, 'r'));
}
}
Console.Write(ending);
}
///*
struct MainApp
{
static void Main()
{
283
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
284
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
//
// C l a s s "i n t e r v a l"
//
class interval
{
protected int i, j;
public interval()
{
i = j = 0;
}
public int I
{
set
{
i = value;
}
get
{
return i;
}
}
public int J
{
set
{
j = value;
}
get
{
return j;
}
}
//
// C l a s s "s t a c k f i x e d b u f f e r"
//
class stackFB : SD
{
protected interval[] buffer;
protected int size, top;
285
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
top = 0;
}
/*
//
// C l a s s "s t a c k l i s t"
//
class stackL : SD
{
protected stackL pnext;
protected interval pdata;
public stackL()
{
pdata = null;
pnext = null;
}
286
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
error("Stack is full!");
}
if ((object)this.pnext != null)
{
stackL ptemp = this.pnext;
this.pnext = ptemp.pnext;
this.pdata = ptemp.pdata;
}
else
this.pdata = null;
return pret;
}
else
{
error("Stack is empty!");
return null;
}
}
//
// C l a s s "v e c t o r"
//
class vector : SD
{
protected int n; // Number of elements
protected usual_elem[] t; // Vector of elements
n = 0;
while (!pf.EndOfStream)
{
t[n] = new usual_elem();
if (t[n].fscanf_el(pf) > 0)
n++;
}
pf.Close();
pf = null;
}
287
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
Console.Clear();
Console.Write(opening);
for (int i = 0; i < n; i++)
{
if ((i > 0) && (i % nlinepp == 0))
{
Console.Write("Press any key to continue... ");
Console.ReadKey();
Console.Clear();
Console.Write(opening);
}
Console.Write("{0,4:D}. ", (i + 1));
t[i].show("", "\n");
}
Console.Write(ending);
Console.Write("End of Vector. Press any key to continue... ");
Console.ReadKey();
Console.WriteLine();
}
public int N
{
get
{
return n;
}
}
//
// C l a s s " v e c t o r q u i c k s o r t"
//
class vector_quicksort : vector
{
public vector_quicksort(string file_name, int NMAX) :
base(file_name, NMAX)
{
288
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
while(!stack_interv.isempty())
{
interval tinterv = stack_interv.pop();
i = tinterv.I;
j = tinterv.J;
if(j>i)
{
int imain=divide(i,j);
stack_interv.push(new interval(i, imain - 1));
stack_interv.push(new interval(imain + 1, j));
//stack_interv.push(new interval(imain + 1, j));
//stack_interv.push(new interval(i, imain - 1));
}
else
{
Console.WriteLine("Not processed!");
Console.ReadKey();
}
}
/*
protected void quicksort_stack(int i, int j)
{
stackFB stack_interv = new stackFB((int)(Math.Log((double)n) /
Math.Log(2.0)) + 1);
// stackL stack_interv = new stackL();
// stackFB stack_interv = new stackFB(n);
stack_interv.push(new interval(i, j));
while (!stack_interv.isempty())
{
interval tinterv = stack_interv.pop();
i = tinterv.I;
j = tinterv.J;
289
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
if (j > i)
{
int imain = divide(i, j);
if (imain - i > j - imain)
{// We'll start with the right-hand interval
stack_interv.push(new interval(i, imain - 1));
stack_interv.push(new interval(imain + 1, j));
}
else
{// We'll start with the left-hand interval
stack_interv.push(new interval(imain + 1, j));
stack_interv.push(new interval(i, imain - 1));
}
}
else
{
Console.WriteLine("Not processed!");
Console.ReadKey();
}
}
}
*/
protected int divide(int i, int j)
{
int imain, jmain, imed;
imed = (i + j) / 2;
ncomp++;
if (t[i] < t[imed])
{
ncomp++;
if (t[imed] < t[j])
imain = imed;
else
{
ncomp++;
if (t[i] < t[j])
imain = j;
else
imain = i;
}
}
else
{
ncomp++;
if (t[imed] > t[j])
imain = imed;
else
{
ncomp++;
if (t[i] > t[j])
imain = j;
else
imain = i;
}
}
if (imain > i)
290
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
swap(i, imain);
imain = i + 1;
jmain = j;
while (imain < jmain)
{
bool forward = true;
while (forward)
{
if (imain >= jmain)
forward = false;
else
{
ncomp++;
if (t[imain] > t[i])
forward = false;
else
imain++;
}
}
ncomp++;
if (t[imain] > t[i])
imain--;
if (imain > i)
swap(i, imain);
return imain;
}
}
//
// C l a s s " v e c t o r o p t i m q u i c k s o r t "
//
class vector_optim_quicksort : vector_quicksort
{
protected int threshold;
291
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
while (!stack_interv.isempty())
{
interval tinterv = stack_interv.pop();
i = tinterv.I;
j = tinterv.J;
if (j - i + 1 > threshold)
{
int imain = divide(i, j);
if (imain - i > j - imain)
{// We'll start with the right-hand interval
stack_interv.push(new interval(i, imain - 1));
stack_interv.push(new interval(imain + 1, j));
}
else
{// We'll start with the left-hand interval
stack_interv.push(new interval(imain + 1, j));
stack_interv.push(new interval(i, imain - 1));
}
}
else
{
Console.WriteLine("Processed with insertsort!");
Console.ReadKey();
insertsort(i, j);
}
}
}
292
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
forward = false;
else
{
ncomp++;
if (t[l] >= t[l - 1])
forward = false;
else
{
swap(l - 1, l);
l--;
}
}
}
}
/*
// --- Quicksort + Stack ---
struct MainApp
{
static void Main()
{
vector_quicksort gr = new vector_quicksort("Stud.txt", 200);
//vector_quicksort gr = new vector_quicksort("Stud20.txt", 200);
gr.show("Unsorted group:\n", "", 20);
gr.quicksort();
gr.show("Group sorted by name:\n", "", 20);
//gr.show("Group sorted by year:\n", "", 20);
//gr.show("Group sorted by salary:\n", "", 20);
Console.WriteLine("n={0:D}, ncomp={1:D}, n*log2(n)={2:F2}, n*n={3:F0}",
gr.N, gr.Ncomp,
gr.N * Math.Log((double)gr.N) / Math.Log(2.0),
(double)gr.N * gr.N);
293
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
}
}
*/
294
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
ПРИЛОЖЕНИЕ 6. ОЧЕРЕДИ НА C#
//
// C l a s s "q u e u e c i r c u l a r b u f f e r"
//
class queueCB : SD
{
protected usual_elem[] buffer;
protected int size, nextin, nextout, count;
usual_elem newel;
while (!pf.EndOfStream)
{
newel = new usual_elem();
if (newel.fscanf_el(pf) > 0)
put(newel);
}
pf.Close();
pf = null;
}
295
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
else
{
error("Queue is empty!\n");
return null;
}
}
Console.Write(opening);
if (!isempty())
{
int i = 1;
Console.Write("{0,4:D}. ", i);
int current = nextout;
buffer[current].show("", "\n");
while ((++current % size) != nextin)
{
if ((i > 0) && (i % nlinepp == 0))
{
Console.Write("Press any key to continue... ");
Console.ReadKey();
Console.Clear();
Console.Write(opening);
}
i++;
Console.Write("{0,4:D}. ", i);
buffer[current].show("", "\n");
}
}
Console.Write(ending);
Console.Write("End of Queue. Press any key to continue... ");
Console.ReadKey();
Console.WriteLine();
}
}
//
// C l a s s "q u e u e l i s t"
//
class queueL : SD
{
protected queueL pnext;
protected usual_elem pdata;
public queueL()
{
pdata = null;
pnext = null;
}
queueL pcurrent_nod;
usual_elem pnewel;
pcurrent_nod = this;
while (!pf.EndOfStream)
296
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
{
pnewel = new usual_elem();
if (pnewel.fscanf_el(pf) > 0)
{
if ((object)pcurrent_nod.pdata != null)
{
pcurrent_nod.pnext = new queueL();
pcurrent_nod = pcurrent_nod.pnext;
}
}
pcurrent_nod.pdata = pnewel;
}
pf.Close();
pf = null;
}
return pret;
}
else
{
error("Queue is empty!");
return null;
}
}
297
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Console.Clear();
Console.Write(opening);
queueL pcurrent_nod = this;
if ((object)pcurrent_nod.pdata != null)
{
int i = 1;
Console.Write("{0,4:D}. ", i);
pcurrent_nod.pdata.show("", "\n");
while ((object)(pcurrent_nod = pcurrent_nod.pnext) != null)
{
if ((i > 0) && (i % nlinepp == 0))
{
Console.Write("Press any key to continue... ");
Console.ReadKey();
Console.Clear();
Console.Write(opening);
}
i++;
Console.Write("{0,4:D}. ", i);
pcurrent_nod.pdata.show("", "\n");
}
}
Console.Write(ending);
Console.Write("End of Queue. Press any key to continue... ");
Console.ReadKey();
Console.WriteLine();
}
}
///*
// Stack utilisation
struct MainApp
{
static void Main()
{
Console.WriteLine("\nExtracting by one:");
while(!gr.isempty())
{
Console.WriteLine("Press any key...");
ConsoleKeyInfo info = Console.ReadKey();
Console.WriteLine();
usual_elem extracted_el;
extracted_el = gr.get();
extracted_el.show("","\n");
}
Console.WriteLine("Queue is empty! Press any key...");
Console.ReadKey();
Console.WriteLine();
Console.WriteLine();
gr.get().show("","\n");
gr.get().show("","\n");
298
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
Console.ReadKey();
Console.WriteLine();
}
}
//*/
299
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
ПРИЛОЖЕНИЕ 8. МАТРИЦЫ НА C#
//
// C l a s s "m a t r i x 3 l"
//
class matrix3l: SD
{
protected character[] V; // matrix reprezentation vector
protected int l1, h1;
protected int l2, h2;
protected int l3, h3;
public matrix3l(int l1, int h1, int l2, int h2, int l3, int h3)
{
this.l1=l1;
this.h1=h1;
this.l2=l2;
this.h2=h2;
this.l3=l3;
this.h3=h3;
nopadd=0;
nopmul=0;
}
public matrix3l(string file_name, int l1, int h1, int l2, int h2, int l3,
int h3):
base(file_name)
{
this.l1=l1;
this.h1=h1;
this.l2=l2;
this.h2=h2;
this.l3=l3;
this.h3=h3;
nopadd=0;
nopmul=0;
300
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
nopadd+=9;
nopmul+=5;
D3 = 1;
D2 = (h3 - l3 + 1) * D3;
D1 = (h2 - l2 + 1) * D2;
return V[(i1 - l1) * D1 + (i2 - l2) * D2 + (i3 - l3) * D3];
}
301
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
public int search(character e, out int i1, out int i2, out int i3)
{
i1 = 0;
i2 = 0;
i3 = 0;
int found = 0;
for(int i1t = l1; i1t <= h1 && (found == 0); i1t++)
for(int i2t = l2; i2t <= h2 && (found == 0); i2t++)
for (int i3t = l3; i3t <= h3 && (found == 0); i3t++)
if(e == elem(i1t, i2t, i3t))
{
found = 1;
i1 = i1t;
i2 = i2t;
i3 = i3t;
}
return found;
}
302
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
//
// C l a s s "m a t r i x 3 c"
//
class matrix3c : SD
{
protected character[] V; // matrix reprezentation vector
protected int l1, h1;
protected int l2, h2;
protected int l3, h3;
public matrix3c(int l1, int h1, int l2, int h2, int l3, int h3)
{
this.l1 = l1;
this.h1 = h1;
this.l2 = l2;
this.h2 = h2;
this.l3 = l3;
this.h3 = h3;
nopadd = 0;
nopmul = 0;
}
public matrix3c(string file_name, int l1, int h1, int l2, int h2, int l3,
int h3) :
base(file_name)
{
this.l1 = l1;
this.h1 = h1;
this.l2 = l2;
this.h2 = h2;
this.l3 = l3;
this.h3 = h3;
nopadd = 0;
nopmul = 0;
}
303
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
nopadd += 9;
nopmul += 5;
D1 = 1;
D2 = (h1 - l1 + 1) * D1;
D3 = (h2 - l2 + 1) * D2;
return V[(i1 - l1) * D1 + (i2 - l2) * D2 + (i3 - l3) * D3];
}
304
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
public int search(character e, out int i1, out int i2, out int i3)
{
i1 = 0;
i2 = 0;
i3 = 0;
int found = 0;
for (int i1t = l1; i1t <= h1 && (found == 0); i1t++)
for (int i2t = l2; i2t <= h2 && (found == 0); i2t++)
for (int i3t = l3; i3t <= h3 && (found == 0); i3t++)
if (e == elem(i1t, i2t, i3t))
{
found = 1;
i1 = i1t;
i2 = i2t;
i3 = i3t;
}
return found;
}
//
305
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
// C l a s s "m a t r i x 3 l d v"
//
class matrix3ldv : matrix3l
{
protected int [] d; // poiner to definition vector
public matrix3ldv(int l1, int h1, int l2, int h2, int l3, int h3):
base(l1, h1, l2, h2, l3, h3)
{
d = new int[12];
d[0] = 3; // dimension
d[1] = l1;
d[2] = h1;
d[3] = l2;
d[4] = h2;
d[5] = l3;
d[6] = h3;
d[7] = (h1 - l1 + 1) * (h2 - l2 + 1) * (h3 - l3 + 1); // number of
elements
d[10] = 1; // D3
d[9] = (h3 - l3 + 1) * d[10]; // D2
d[8] = (h2 - l2 + 1) * d[9]; // D1
d[11] = l1 * d[8] + l2 * d[9] + l3 * d[10]; // Sum(ljxDj)
}
//
// C l a s s "m a t r i x 3 l I l"
//
class matrix3lIl : matrix3l
{
protected int v0; // Iliffes vector base
protected int[] v1; // Iliffes vectors ierarhy level 1
protected int[] v2; // Iliffes vectors ierarhy level 1
public matrix3lIl(int l1, int h1, int l2, int h2, int l3, int h3) :
306
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
v0 = -l1;
v1 = new int[n1];
v2 = new int[n1 * n2];
v1[0] = -l2;
for(i = 1; i < n1; i++)
v1[i] = v1[i - 1] + n2;
v2[0] = -l3;
for(i = 1; i < n1 * n2; i++)
v2[i] = v2[i - 1] + n3;
}
public matrix3lIl(string file_name, int l1, int h1, int l2, int h2,
int l3, int h3) :
base(file_name, l1, h1, l2, h2, l3, h3)
{
int n1 = h1 - l1 + 1;
int n2 = h2 - l2 + 1;
int n3 = h3 - l3 + 1;
int i;
v0 = -l1;
v1 = new int[n1];
v2 = new int[n1 * n2];
v1[0] = -l2;
for (i = 1; i < n1; i++)
v1[i] = v1[i - 1] + n2;
v2[0] = -l3;
for (i = 1; i < n1 * n2; i++)
v2[i] = v2[i - 1] + n3;
}
//
// C l a s s "m a t r i x 3 c I l"
//
class matrix3cIl : matrix3c
{
protected int v0; // Iliffes vector base
protected int[] v1; // Iliffes vectors ierarhy level 1
protected int[] v2; // Iliffes vectors ierarhy level 1
public matrix3cIl(int l1, int h1, int l2, int h2, int l3, int h3) :
base(l1, h1, l2, h2, l3, h3)
{
int n3 = h3 - l3 + 1;
307
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
int n2 = h2 - l2 + 1;
int n1 = h1 - l1 + 1;
int i;
v0 = -l3;
v1 = new int[n3];
v2 = new int[n3 * n2];
v1[0] = -l2;
for (i = 1; i < n3; i++)
v1[i] = v1[i - 1] + n2;
v2[0] = -l1;
for (i = 1; i < n3 * n2; i++)
v2[i] = v2[i - 1] + n1;
}
public matrix3cIl(string file_name, int l1, int h1, int l2, int h2,
int l3, int h3) :
base(file_name, l1, h1, l2, h2, l3, h3)
{
int n3 = h3 - l3 + 1;
int n2 = h2 - l2 + 1;
int n1 = h1 - l1 + 1;
int i;
v0 = -l3;
v1 = new int[n3];
v2 = new int[n3 * n2];
v1[0] = -l2;
for (i = 1; i < n3; i++)
v1[i] = v1[i - 1] + n2;
v2[0] = -l1;
for (i = 1; i < n3 * n2; i++)
v2[i] = v2[i - 1] + n1;
}
/*
// --- Pe linii ---
struct MainApp
{
static void Main()
{
// matrix3l A = new matrix3l("char.txt", 2, 4, -3, -1, 0, 1);
// matrix3ldv A = new matrix3ldv("char.txt", 2, 4, -3, -1, 0, 1);
matrix3lIl A = new matrix3lIl("char.txt", 2, 4, -3, -1, 0, 1);
308
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
char c;
int i1, i2, i3;
ConsoleKeyInfo info;
char ch='n';
while(ch!='y')
{
Console.Write("Enter a char to search: ");
info = Console.ReadKey();
Console.WriteLine();
c = info.KeyChar;
character mychar = new character(c);
int pos = A.search(mychar);
if (pos < 0)
{
Console.Write("The character ");
mychar.show("'", "'");
Console.WriteLine(" no matrix!");
}
else
{
A.search(mychar, out i1, out i2, out i3);
Console.Write("The character ");
mychar.show("'", "'");
Console.WriteLine(" are in the position {0:D} \nwith indices
[{1:D},{2:D},{3:D}]\n",
pos, i1, i2, i3);
}
309
Структуры данных (на базе C++): Метод. матер.
С. Перетятку, А. Перетятку
char c;
int i1, i2, i3;
ConsoleKeyInfo info;
char ch = 'n';
while (ch != 'y')
{
Console.Write("Enter a char to search: ");
info = Console.ReadKey();
Console.WriteLine();
c = info.KeyChar;
character mychar = new character(c);
int pos = A.search(mychar);
if (pos < 0)
{
Console.Write("The character ");
mychar.show("'", "'");
Console.WriteLine(" no matrix!");
}
else
{
A.search(mychar, out i1, out i2, out i3);
Console.Write("The character ");
mychar.show("'", "'");
Console.WriteLine(" are in the position {0:D} \nwith indices
[{1:D},{2:D},{3:D}]\n",
pos, i1, i2, i3);
}
310