Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабы_по_проге_Берлин / Книги / учебное пособие ОАиП.pdf
Скачиваний:
49
Добавлен:
11.02.2015
Размер:
947 Кб
Скачать

getch();

// задержка

}

//функция выделения k MAX элементов из списка параметров

//найденные элементы возвратить в main

int * fun(...)

{int i,j,k,n=0,*ii,**jj; void *p;

printf("\n сколько MAX переменных надо выделить из списка = ");

scanf("%d",&k); // ввести ограничение на k (не более чем параметров) ii=(int *)calloc(k+1,sizeof(int)); // k max значений из списка (k+1 эл-т

 

// всегда ==0 - признак конца для main)

jj=(int **)calloc(k,sizeof(int *)); // адреса k max значений в стеке

while(n<=k-1)

// пока не найдено k max элементов

{ p=(...);

// элипсис, p устанавливается на начало списка

 

// параметров переменной длинны

do

{i=0;

while(i<n && jj[i]) if (jj[i++]==(int *)p)

{((int *)p)++; break;

//поиск первого еще не занесенного

//адрес уже есть

//выбор следующего элемента из стека

}

 

} while(jj[i]);

 

ii[n]=*(int *)p;

// предварительное max значение для сравнения

jj[n]=((int *)p)++;

// его адрес в стеке

while(j=*((int *)p))

// пока считанный j!= 0 (признак конца списка)

{ for(i=0;i<n && jj[i]!=(int *)p && jj[i++];); // поиск адреса эл-та в jj if (j>ii[n] && jj[i]!=(int *)p) // эл-т max и его адрес не найден

{ ii[n]=*((int *)p);

// новое max значение для сравнения

jj[n]=((int *)p);

// его адрес в стеке

}

 

((int *)p)++;

// указатель на следующий элемент стека

}

 

n++;

 

}

 

free(jj);

 

return ii;

 

}

Сортировка

Сортировка применяется во многих программах оперирующих информацией. Цель сортировки – упорядочить информацию и облегчить поиск требуемых данных. Существует много методов сортировки данных. Причём для разных типов данных иногда целесообразно применять разные методы сортировки.

// выбор верхней границы массива // просмотр массива ”снизу” ”вверх” // условие замены выполнено
// замена j-1 и j элементов

Практически каждый алгоритм сортировки можно разбить на три части:

-сравнение двух элементов, определяющее упорядоченность этой пары;

-перестановку, меняющую местами неупорядоченную пару элементов;

-сортирующий алгоритм, определяющий выбор элементов для сравнения

иотслеживающий общую упорядоченность массива данных.

Сортировка данных в оперативной памяти называется внутренней, а сортировка данных в файлах называется внешней. Ниже будут рассматриваться методы сортировки данных в оперативной памяти.

Пузырьковая сортировка.

Название метода отражает его суть. ”Легкие”элементы массива ”всплывают” вверх(в начало), а ”тяжелые” опускаются вниз(в конец). Пузырьковая сортировка проходит по массиву снизу вверх. Каждый элемент массива сравнивается с элементом, который находится непосредственно над ним. И если при их сравнении оказывается, что они удовлетворяют условию их перестановки, то она выполняется. Процесс сравнений и перестановок продолжается до тех пор, пока ”легкий” элемент не “всплывет” вверх. В конце каждого прохода по массиву, верхняя граница сдвигается на один элемент вниз(вправо). Сортировка продолжается анализируя все меньшие массивы. В примере выполняется сортировка элементов массива размерностью k.

void sort(int *ms, int k) { int i,j,m;

for(i=0;i<k-1;++i) for(j=k-1;j>i;--j) {if(ms[j-1]>ms[j]) { m=ms[j-1];

ms[j-1]=ms[j]; ms[j]=m;

}

}

}

Внутренний цикл for выполняет проход по подмассиву в направлении обратном внешнему циклу. Если изменить направление этих циклов, то не наименьший будет “всплывать”, а наибольший “тонуть”.

Шейкер сортировка

В этом методе учитывается тот факт, что от последней перестановки до конца массива будут находиться уже упорядоченные данные. Тогда просмотр имеет смысл делать не до конца массива, а до последней перестановки на предыдущем просмотре. Если же просмотр делать попеременно в двух направлениях и фиксировать нижнюю и верхнюю границы неупорядоченной части, то получим шейкер-сортировку. Ниже приведен пример программы, использующей шейкер-сортировку элементов массива размерностью k.

void shaker(int *ms, int k)

{register int i,a,b,c,d; c=1;

b=k-1; //номер элемента на котором остановка

d=k-1; //номер стартового элемента для сортировки справа налево do

{for(i=d;i>=c;--i)

{if (ms[i-1]>ms[i])

{a=ms[i-1];

ms[i-1]=ms[i]; ms[i]=a;

b=i; // крайний слева упорядоченный элемент

}

}

c=b+1; //номер стартового элемента для сортировки слева направо for(i=c;i<=d;++i)

{if (ms[i-1]>ms[i])

{a=ms[i-1];

ms[i-1]=ms[i];

ms[i]=a;

 

b=i;

// крайний слева упорядоченный элемент

}

 

}

 

d=b-1;

 

} while(c<=d);

 

}

Сортировка вставкой

Вметоде вставки на первом шаге выполняется сортировка первых двух элементов массива. Далее алгоритм ставит третий элемент в порядковую позицию, соответствующую его положению относительно первых двух элементов. Затем в этот список вставляется четвертый элемент и т.д. Процесс продолжается до тех пор, пока все элементы не будут отсортированы. Например, если бы строка "dcab" сортировалась методом вставки, то каждый из проходов давал бы результат:

Вэтом методе определяется место в отсортированной части массива, куда должен помещаться элемент. Элементы от данной позиции сдвигаются вверх и на освободившееся место помещается элемент. Трудоемкость алгоритма при линейном поиске n*n/4. Если используется двоичный поиск для определения места элемента, то трудоемкость алгоритма составляет n*log(n). Пример программы, использующей сортировку вставкой элементов массива размерностью k :

void srt2(int *ms, int k) { register int i,j,n;

for(i=1;i<k;++i)

// индекс элемента для упорядочивания

{ j=i-1;

// индекс предыдущего элемента

n=ms[i];

// значение предыдущего элемента

while (j>=0 && n<ms[j])

ms[j--+1]=ms[j];

// сдвиг всех элементов направо

ms[j+1]=n;

// запись в освободившийся или в тот же элемент

}

 

}

 

Сортировка выбором

Выбирается очередной исходный элемент массива. Последовательно проходя весь массив, сравниваем этот элемент со всеми, находящимися после него, и, при нахождении элемента удовлетворяющего условию замены запоминаем его индекс. После просмотра всего массива, переставляем выбранный элемент с исходным. После перебора всех элементов, получим отсортированный массив. Пример программы, реализующей сортировку

выбором, приведен ниже:

 

void sort(int *ms, int k)

 

{ int i,i1,j,m;

 

for(i=0; i<k-1; i++)

// выбор исходного элемента к сравнению

{ i1=i;

//

for(j=i+1; j>i; j--)

// просмотр массива ”снизу” ”вверх”

if(ms[k]>ms[j]) i1=j;

// фиксируем координату элемента в массиве

m=ms[i];

// замена i1 и i элементов

ms[i]=ms[i1];

 

ms[i1]=m;

 

}

 

}

 

Отмеченные методы сортировки не являются эффективными. В программах, где требуется высокая производительность работы сортировок, применяются следующие методы.

Метод Шелла

Метод был предложен автором (Donald Lewis Shell) в 1959г. Основная идея алгоритма состоит в том, что на начальном этапе реализуется сравнивание и, если требуется, перемещение далеко отстоящих друг от друга элементов. Интервал между сравниваемыми элементами (gap) постепенно уменьшается до единицы, что приводит к перестановке соседних элементов на последних стадиях сортировки (если это необходимо).

Реализуем метод Шелла следующим образом. Начальный шаг сортировки примем равным n/2, т.е. 1/2 от общей длины массива, и после каждого прохода будем уменьшать его в два раза. Каждый этап сортировки включает в себя проход всего массива и сравнение отстоящих на gap элементов. Проход с тем же шагом повторяется, если элементы переставлялись. Заметим, что после