ПЕРОВА САБАЕВА
.pdf5.4. Быстрая сортировка
Быстрая сортировка, хоть и была разработана более 40 лет назад, является наиболее широко применяемым и одним их самых эффективных алгоритмов сортировки. Метод основан на принципе «разделяй-и-властвуй».
Общая схема быстрой сортировки такова: из массива выбирается некоторый опорный элемент a[i], запускается процедура разделения массива, которая перемещает все ключи, меньшие, либо равные a[i], влево от него, а все ключи, большие, либо равные a[i] – вправо (рис. 5.5). Теперь массив состоит из двух подмножеств, причем левое подмножество меньше, либо равно правого:
Рис. 5.5. Разделение массива на два подмассива
Для каждого подмассива будем иметь: если в подмассиве более двух элементов, рекурсивно запускается для него та же процедура. В конце получится полностью отсортированная последовательность.
Рассмотрим алгоритм быстрой сортировки подробнее.
1.На входе задаем массив a[0] ... a[N] и опорный элемент p, по которому будет производиться разделение.
2.Введем два указателя: i и j (рис. 5.6). В начале алгоритма они указывают, соответственно, на левый и правый концы последовательности.
3.Будем двигать указатель i с шагом в 1 элемент по направлению к концу массива, пока не будет найден элемент a[i] >= p.
4.Аналогичным образом начнем двигать указатель j от конца массива к началу, пока не будет найден a[j] <= p.
5.Если i <= j, меняем a[i] и a[j] местами и продолжаем двигать i, j по тем же правилам.
6.Повторяем шаг 3, пока i <= j.
Рассмотрим работу процедуры быстрой сортировки для массива a[0]...a[6]
иопорного элемента p = a[3] (рис. 5.6).
43
Рис. 5.6. Иллюстрация алгоритма быстрой сортировки
Теперь массив разделен на две части: все элементы левой меньше либо равны p, все элементы правой – больше, либо равны p. Разделение завершено.
Листинг 5.4. Задать исходный массив х[N]. Количество элементов массива N и значения элементов массива ввести с клавиатуры. Применяя алгоритм быстрой сортировки, отсортировать исходный массив в порядке возрастания его элементов. Вывести на экран дисплея исходный и отсортированный массивы.
//L5_4.cpp
#include <iostream> using namespace std;
void qs(int* s_arr, int first, int last); // Прототип функции qs() int main()
{
setlocale(LC_CTYPE,"russian"); int i, n, *x;
do
{
cout<<"Введите число элементов массива "; cin>>n;
}while (n<=1); x=new int[n]; for(i=0; i<n; i++)
{
cout<<"Введите x("<<i+1<<")=";
44
cin>>x[i];
}
cout<<"Исходный массив\n"; for(i=0; i<n; i++)
cout<<x[i]<<" "; cout<<endl; qs(x,0,n-1);
cout<<"Полученный массив\n"; for(i=0;i<n;i++)
cout<<x[i]<<" "; cout<<endl;
return 0;
}
void qs(int* s_arr, int first, int last)
{
int i = first, j = last, x = s_arr[(first + last) / 2];
do {
while (s_arr[i] < x) i++; while (s_arr[j] > x) j--;
if(i <= j) {
if (i < j) swap(s_arr[i], s_arr[j]); i++;
j--;
}
} while (i <= j);
if (i < last) qs(s_arr, i, last);
if (first < j) qs(s_arr, first, j);
}
На рис. 5.7 приведен результат выполнения программы листинга 5.4.
45
Рис. 5.7. Результат работы программы листинга 5.4
УПРАЖНЕНИЯ
1.Упорядочить массив из n числовых элементов методом пузырька по возрастанию.
2.Упорядочить массив из n числовых элементов методом пузырька по убыванию.
3.Используя алгоритм быстрой сортировки, упорядочить массив из n числовых элементов по убыванию.
4.Используя алгоритм сортировки вставкой, упорядочить массив из n числовых элементов по убыванию.
5.Используя алгоритм сортировки выбором, упорядочить массив из n числовых элементов по убыванию.
6.Используя алгоритм сортировки выбором, упорядочить массив из n числовых элементов по возрастанию.
7.Упорядочить четные элементы массива из n числовых элементов методом пузырька по возрастанию.
8.Упорядочить нечетные элементы массива из n числовых элементов методом пузырька по убыванию.
9.Упорядочить массив из n символов методом пузырька в алфавитном по-
рядке.
10.Упорядочить массив из n символов методом быстрой сортировки в алфавитном порядке.
11.Упорядочить массив из n символов методом сортировки вставкой в алфавитном порядке.
12.Упорядочить массив из n числовых элементов методом пузырька по возрастанию числа их делителей.
46
13.Используя алгоритм быстрой сортировки, упорядочить массив из n числовых элементов по убыванию числа их делителей.
14.Используя алгоритм быстрой сортировки, упорядочить массив из n числовых элементов по возрастанию числа их делителей.
15.Задан список студентов с указанием их среднего балла за текущую сессию. Упорядочить список студентов по убыванию балла, а в случае равенства баллов, упорядочить список студентов в алфавитном порядке.
16.Задан список студентов с указанием числа их прогулов за текущий семестр. Упорядочить список студентов по убыванию числа прогулов, а в случае равенства прогулов, упорядочить его в алфавитном порядке.
17.Задан список сотрудников с указанием отдела, в котором они работают. Упорядочить список сотрудников по убыванию номера отдела, а в случае равенства номеров отделов, упорядочить его в алфавитном порядке.
18.Упорядочить массив из n элементов следующим образом: положительные элементы по возрастанию, а отрицательные – по убыванию.
19.Заданы два упорядоченных массива из n и m элементов. Построить массив размерностью n+m с той же упорядоченностью.
20.Заданы два упорядоченных массива из n и m элементов. Построить массив размерностью n+m с противоположной упорядоченностью.
21.Упорядочить массив из n элементов следующим образом: сначала положительные элементы по убыванию, а затем отрицательные элементы по возрастанию.
22.Задан список финалистов лыжного соревнования с указанием фамилии и результата в минутах. Упорядочить список по возрастанию результатов, а в случае равенства результатов, указать фамилии спортсменов в алфавитном порядке.
23.В налоговой инспекции составлен список налогоплательщиков с указанием фамилии и суммы уплаченного налога. Упорядочить список налогоплательщиков по убыванию заплаченной суммы, а в случае равенства сумм указать фамилии налогоплательщиков в алфавитном порядке.
24.В налоговой инспекции составлен список налогоплательщиков с указанием фамилии и суммы задолженности по налогам. Упорядочить список налогоплательщиков по возрастанию суммы, а в случае равенства сумм указать фамилии налогоплательщиков в алфавитном порядке.
25.Задан список сотрудников некоторой фирмы с указанием фамилии и суммы, заработанной за месяц. Упорядочить список сотрудников по убыванию заработанной суммы, а в случае равенства сумм упорядочить фамилии сотрудников в алфавитном порядке.
47
ГЛАВА 6. РАБОТА С ФАЙЛАМИ. ПОСТРОЕНИЕ МАССИВОВ БЕЗ ПОВТОРЕНИЙ
6.1. Работа с файлами
Файл – это поименованная часть памяти диска, которая содержит некоторый набор записей [32]. В С++ средства для доступа к файлам объявлены в заголовочном файле fstream, который необходимо включить в программный код при работе с файлами. Для обозначения источника либо приемника данных применяется термин «поток». Потоки для работы с файлами создаются как объекты следующих классов:
ofstream – для вывода (записи) данных в файл;
ifstream – для ввода (чтения) данных из файла;
fstream – для чтения и записи данных (двунаправленный обмен).
Имя файла задается либо при создании объекта, либо при использовании метода open(). В качестве примера рассмотрим пример с двойной сортировкой (см. листинг 5.2), но информацию нужно получать из файла.
Листинг 6.1. В текстовом файле «input.txt» записана следующая информация: число студентов, а затем идут парой фамилия и номер группы (рис. 6.1). Необходимо преобразовать этот список так, чтобы он оказался отсортированным по группам и внутри каждой группы в алфавитном порядке. Полученный список вывести на экран дисплея и записать в файл.
//L6_1.cpp |
|
|
#include <string.h> |
|
|
#include <fstream> |
|
|
#include <iostream> |
|
|
using namespace std; |
|
|
int main( ) |
|
|
{ |
|
|
setlocale(LC_CTYPE,"russian"); |
|
|
int n,i,*grup,f,k=0,gtmp; |
|
|
char**name,*ntmp,fam[30]; |
|
|
fstream ff("input.txt"); |
//Соэдание объекта ff и открытие файла |
|
ff>>n; |
|
|
name=new char*[n]; |
//Выделение памяти для указателей, |
|
|
//связанных с фамилией студентов |
. |
grup=new int[n]; |
//Выделение памяти под номера групп |
|
for(i=0;i<n;i++) |
|
|
{ |
|
|
ff>>fam>>grup[i]; |
|
|
|
48 |
|
name[i]=strdup(fam); |
//Заполняется фамилия i-го студента |
} |
|
ff.close(); |
//Закрытие файла |
. . . |
//См. листинг 5.2 |
ff.open("input.txt",ios::app); //Открытие файла для пополнения ff<<"\nПолученный список\n";
for(i=0;i<n;i++)
{
ff.width(6); ff<<grup[i]<<" "; ff<<name[i]<<'\n';
}
ff.close(); //Закрытие файла return 0;
}
Содержимое файла “input.txt”
Рис. 6.1. Информация, находящаяся в файле «input.txt»
На рис. 6.2 приведен результат выполнения программы листинга 6.1.
Рис. 6.2. Результат работы программы листинга 6.1
49
6.2. Построение массивов без повторений
Предположим, что в файле «input.txt» записана информация, содержащая количество студентов в списке, фамилию студента, название предмета и оценку по этому предмету. Фамилии студентов и названия предметов могут повторяться (рис. 6.3). Необходимо сформировать список студентов и вычислить общее количество пропусков занятий для каждого из них, а также общее число пропусков занятий по каждому предмету. Таким образом, для каждого студента и каждого предмета нужно суммировать число пропусков занятий.
Содержимое файла “input.txt”
Рис. 6.3. Информация, находящаяся в файле «input.txt»
Листинг 6.2. Сформировать список из неповторяющихся фамилий и список из неповторяющихся предметов. При вводе проверять, если среди раннее введенных фамилий (рис. 6.3) вводимые фамилии и предметы. Если их нет, то вводится новая запись, а если они уже есть, то добавляется число прогулов в уже существующую запись.
//L6_2.cpp
#include <string.h> #include <fstream> #include <iostream> using namespace std; int main( )
{
setlocale(LC_CTYPE,"russian");
int n,i,j,*nname,*nsubject,mn=0,ms=0,f,aut;
50
char**name,**subject,fam[30],sb[30];
fstream ff("input.txt"); |
|
ff>>n; |
//Читаем число записей |
name=new char*[n]; |
//Выделяем память под указатели |
|
//на фамилии. |
subject=new char*[n]; |
//Выделяем память под указатели |
|
//на названия предметов. |
nname=new int[n]; |
//Выделяем память под количество |
|
//пропусков длякаждого студента. |
nsubject=new int[n]; |
//Выделяем память под количество |
|
//под каждый предмет. |
for(i=0;i<n;i++) |
|
{ |
|
ff>>fam; |
//Ввод фамилии студента |
ff>>sb; |
//Ввод предмета |
ff>>aut; |
//Ввод числа прогулов студента по этому |
|
//предмету. |
for(j=0;j<mn;j++)
if(strcmp(name[j],fam)==0)
break;
if(j>=mn)
{
name[mn]=strdup(fam);
nname[mn++]=aut;
}
else
nname[j]+=aut;
for(j=0;j<ms;j++)
if(strcmp(subject[j],sb)==0)
break;
if(j>=ms)
{
subject[ms]=strdup(sb);
nsubject[ms++]=aut;
}
else
nsubject[j]+=aut;
}
ff.close();
cout<<"\nПолученные списки\nСТУДЕНТЫ\n\n"; for(i=0;i<mn;i++)
{
cout.width(10);
cout<<name[i];
51
cout.width(5);
cout<<nname[i]<<'\n';
}
cout<<"\nПРЕДМЕТЫ\n\n"; for(i=0;i<ms;i++)
{
cout.width(10);
cout<<subject[i];
cout.width(5);
cout<<nsubject[i]<<'\n';
}
cout<<'\n';
ff.open("input.txt",ios::app); ff<<"\nПолученные списки\nСТУДЕНТЫ\n\n"; for(i=0;i<mn;i++)
{
ff.width(10);
ff<<name[i];
ff.width(5);
ff<<nname[i]<<'\n';
}
ff<<"\nПРЕДМЕТЫ\n\n"; for(i=0;i<ms;i++)
{
ff.width(10);
ff<<subject[i];
ff.width(5);
ff<<nsubject[i]<<'\n';
}
ff<<'\n';
ff.close(); return 0;
}
Результат работы программы листинга 6.2 приведен на рис. 6.4.
52