PDA

Показать полную графическую версию : [решено] Пара вопросов по Блочной сортировке


Drongo
03-01-2008, 19:33
Товарищи! Тут по заданию решил задачу "Блочная сортировка", вроде решил, но такой вопрос, мне кажется, что я не так её решил, как нужно. Не могли бы вы подсказать, насколько я неправильно решил, хотя код рабочий, но можно как-то улучшить конструкцию, например:
1. Хочу, чтобы массив перебирался и вычислялось число у которого чисел в разрядах наибольшее количество, пример: "7" = 1 разряд в числе, "243" - 3 раряда в числе, "23888" - 5 разрядов, "24" - 2 разряда, и т.д. Это нужно для вычисления проходов в цикле for, Чтобы в первом цикле for можно было подставлять вычисленное число, а не вручную, как сейчас "5", мне кажется нужна функция: которая принимает число и переводит его в строку, но я не знаю эту функцию, подскажете?!
len = strlen(функция ЧислоВСтроку(ar[j]));
2. И ещё почему при размере массива в 20000 функция работает, а с размером уже больше 20 тысяч вылетает в ошибку?! Проверял только до 100000 и выставлял, число в разрядах "6". Что не так?!
Прочитал тему на форуме Последовательность чисел (http://forum.oszone.net/thread-96954.html) Подумал, а нельзя ли как-нибудь использовать исключающее "И" или "или"?! Для сортировки. Как решено в этой теме 5pliT-ом, если можно то как?!
В общем раскритикуйте мой код или укажате на слабые места, если можно с поправкой. Буду благодарен!
// Блочная сортировка---------------------------------------------------------------------------
#include <iostream.h>
using std::cout;
using std::cin;
using std::endl;

#include <iomanip.h>
using std::setw;

#include <cstring>

#include <stdlib.h>
#include <ctime.h>
using std::time;

void bucketSort(int ara[], const int sze);

int main()
{
const int size = 20000;
int array[size] = {0};
int z = 1;

srand(time(0));

cout<<" Inizialization array..."<<endl;
for(int i = 0; i < size; i++)
array[i] = rand() % size; // Генерация случайных чисел для заполнения массива первоначальными значениями

for(int j = 0; j < size; j++)
cout<<setw(8)<<array[j]; // Вывод НЕСОРТИРОВАННОГО массива

cout<<"----------------------------------------------------------------------"<<endl<<endl<<endl;

bucketSort(array, size); // Функция сортировки

cin>>z;

return 0;
}
//---------------------------------------------------------------------------
void bucketSort(int ar[], const int sz)
{
const int Rasryad = 10;
const int Position = 20000;
int TempArray[Rasryad][Position] = {0};
int /*lenght = 0,*/ temp, number = 1, Ras, counter = 0;;

// for(int j = 0; j < sz; j++){
// temp = strlen((ar[j]));
// if(lenght < temp)
// lenght = temp;
//}

// Распределяющий проход
for(int i = 0; i < 5; i++){ // Проход столько, сколько разряда у числа
for(int j = 0; j < sz; j++){ // Проход столько, сколько чисел в массиве
Ras = ar[j] / number % 10; // Вычисление позиции разряда
TempArray[Ras][j] = ar[j]; // Расположение соответсвенно разряду
}
// Собирающий проход после каждого распределяющего
counter = 0;
for(int a = 0; a < Rasryad; a++){
for(int b = 0; b < Position; b++){
if(TempArray[a][b] != 0){
ar[counter++] = TempArray[a][b];
TempArray[a][b] = 0;
}
}
}
number *= 10;
}

for(int i = 0; i < sz; i++) // Вывод сортированного массива
cout<<setw(8)<<ar[i];
}
//-------------------------------------------------------------------------

5pliT
04-01-2008, 21:19
1. Хочу, чтобы массив перебирался и вычислялось число у которого чисел в разрядах наибольшее количество, пример: "7" = 1 разряд в числе, "243" - 3 раряда в числе, "23888" - 5 разрядов, "24" - 2 разряда, и т.д. Это нужно для вычисления проходов в цикле for, Чтобы в первом цикле for можно было подставлять вычисленное число, а не вручную, как сейчас "5", мне кажется нужна функция: которая принимает число и переводит его в строку, но я не знаю эту функцию, подскажете?! »
Число в строку приобразует функция:
char * itoa ( int value, char * str, int base );
обычно её можно найти в stdlib.h.
Или можно написать самому примерно так:
char* itoa(int val, int base) {
char buf[32] = {0};
int i=30;
for(;val&&i;--i,val/=base)
buf[i]="0123456789abcdef"[val%base];
return &buf[i+1];
}
Количество разрядов можно подсчитать ещё проще примерно так:
int rzr(int nn) {
int n=nn,x=0;
while (n<>0) {
n/=10;
x++;
}
return x;
}
2. И ещё почему при размере массива в 20000 функция работает, а с размером уже больше 20 тысяч вылетает в ошибку?! Проверял только до 100000 и выставлял, число в разрядах "6". Что не так?! »
Думаю дело в диапозонах значений стандартных типов. Попробуйте использовать не int, а long long например.

Прочитал тему на форуме Последовательность чисел Подумал, а нельзя ли как-нибудь использовать исключающее "И" или "или"?! Для сортировки. Как решено в этой теме 5pliT-ом, если можно то как?! »
Исключающее ИЛИ можно использовать для обмена значений. Я не думаю что алгоритм блочной сортировки не меняет элементы массива местами, поэтому тот код также подойдёт.

Drongo
04-01-2008, 21:26
использовать не int, а long long например. »
Возможно, попробую - доложу о результатах! Функцию itoa знаю, но лишь визуально, меня смущал сам прототип! Попробую!Количество разрядов можно подсчитать ещё проще »
Просто огромнейшее спасибо!!!

pva
04-01-2008, 22:11
Drongo, отсортируйте массив: 123, 456, 7890 Мне кажется в этом месте:

ar[counter++] = TempArray[a][b];

counter превысит 3, если я правильно понял, конечно. Задали массив 3 числа, а после сортировки получили динее...

Drongo
05-01-2008, 19:31
pva, Спасибо за ответ и помощь, но ar[counter++] = TempArray[a][b]; » я не думаю, поскольку индексирование начинается с нуля "0 1 2 3 4 5 6 7 8 9", и потому счётчик counter++ лишь всегда будет равен переменной sz, если sz = 20000, то и counter после собирающего прохода тоже будет равен 20000, поскольку если элемент в массиве TempArray[a] не всегда расположен последовательно, то идёт проверка, если n-й элемент TempArray, не равен нулю, то присвоить массиву ar[] первое значение, и в итоге всё будет правильно, ведь сортируемых чисел только 20000, следовательно, правильных условий тоже будет 20000, сегодня проверял, но всё равно ошибка при значении размера массивов больше чем 20000 то "ошибается", вот тут:
TempArray[Ras][j] = ar[j]; // Расположение соответсвенно разряду Почему?! Незнаю, иной раз сортирует 14 элементов, иной раз 2, иной раз 7, почему так, хоть убейте, не знаю?!
----------------------------------------------------------------------
Привет 5pliT, тут кажись ошибка while (n<>0) { » может ты имеешь ввиду:
while(n < 0 || n > 0)
илиwhile(n < 0 && n > 0)
А по поводу Попробуйте использовать не int, а [B]long long например » разницы то нет, в типе int переменная хранится в 4-х байтах, этого хватит даже больше, чем на миллион если поставлю, кроме того, пробовал без сортировки используя только несортированный массив выводить из функции bucketSort - так функция принимает и выводит значения, вот если бы была ошибка алгоритма, то сортировки бы не было, но тем не менее при размере массива в 20000 всё работает, а больше ни в какую, причём почему-то несколько значений даже "пробуют" сортироваться, вот если не будет трудно, то попробуй на своём компиляторе скопировать мой код и попробовать изменить всего два значения, я их выделил жирным шрифтом:
int main()
{
const int size = 20000;
int array[size] = {0};
....
и тут:
void bucketSort(int ar[], const int sz)
{
const int Rasryad = 10;
const int Position = 20000;
int TempArray[Rasryad][Position] = {0};
....
Разряды не трогаем, поскольку в 50000 и в 20000 по 5 разрядов в числе, попробуй пожалуйста, посмотри что за ошибка?! Проблема явно не в типе переменной, стопроцентно!

5pliT
06-01-2008, 12:02
Привет 5pliT, тут кажись ошибка
Цитата 5pliT:while (n<>0) { » »
Ой, прошу прощения. В голове языки путаются :) <> - это знак "не равно" в паскале. А в си это так: !=

Где у вас ошибка я не знаю, это отлавливать надо. Но думаю, что или в этой строчке:
TempArray[Ras][j] = ar[j];
или в этой:
ar[counter++] = TempArray[a][b];

Drongo
06-01-2008, 21:19
А в си это так: != »
Спасибо я уже догадался! )))
Буду разбираться...

pva
07-01-2008, 13:32
Drongo, с алгоритмом похоже всё в порядке. Интересно, на каком компиляторе вы собирали и отлаживали? у меня сразу при входе в bucketSort вышла ошибка stack overflow. Варианта решения 2: сказать компилятору увеличить стек или использовать динамическую память. Вот в таком виде всё заработало:

void bucketSort(int ar[], const int sz)
{
const int Rasryad = 10;
const int Position = 100000;

vector<int> mem_TempArray(Position*Rasryad);
int* TempArray[Rasryad];

for(unsigned n=0; n<Rasryad; ++n) TempArray[n] = &mem_TempArray[Position*n];

int /*lenght = 0, temp,*/ number = 1, Ras, counter = 0;;

// Распределяющий проход
for(int i = 0; i < 5; i++){ // Проход столько, сколько разряда у числа
for(int j = 0; j < sz; j++){ // Проход столько, сколько чисел в массиве
Ras = ar[j] / number % 10; // Вычисление позиции разряда
TempArray[Ras][j] = ar[j]; // Расположение соответсвенно разряду
}
// Собирающий проход после каждого распределяющего
counter = 0;
for(int a = 0; a < Rasryad; a++){
for(int b = 0; b < Position; b++){
if(TempArray[a][b] != 0){
ar[counter++] = TempArray[a][b];
TempArray[a][b] = 0;
}
}
}
number *= 10;
}

for(int i = 0; i < sz; i++) // Вывод сортированного массива
cout<<setw(8)<<ar[i];
}
//-------------------------------------------------------------------------

Drongo
07-01-2008, 20:09
Интересно, на каком компиляторе вы собирали и отлаживали? »
Borland C++ Builder
vector<int> mem_TempArray(Position*Rasryad); »
стек » Этого я не изучал ещё....
динамическую память. » - а вот это через оператор new Но похоже не то... А Вам огромное спасибо, за подсказку, а отчего такая ошибка получается?! Подскажите?! Это мне интересно очень!!! Насколько я знаю, vector контейнерный класс, да?!

pva
08-01-2008, 16:50
Начиная ещё с первых компьютеров разработали хитрую систему для передачи данных между блоками программы и для выделения памяти под собственные нужды блоков. ПРичём надо было сделать так, чтобы

// каждый вызов func1 должен иметь собственную память для x
void func1(int z)
{
int x = z;
...

if (0<x) func1(x-1);
}

Делается это просто. Есть участок памяти, называемый "стек". Он и действует по принципу "последний зашёл, первый вышел". Есть специальный регистр процессора, содержит адрес дна стека (допустим SP). При входе в функцию ей даётся память от SP-n до SP, где n - количество байт, требуемых для функции и SP уменьшается на n. При возврате из функции SP обратно увеличивается на n.

// древний компьютер (карта памяти в килобайтах):
// R - ПЗУ, P - код программы, S - стек (задом-наперёд), пробелы - свободная память
// 00k RRRRRRRR 16k PPP SSS 32k
// свободная память постоянно уменьшается с ростом стека

сейчас сохранился тот же подход, с отличием, что страницы памяти стека могут и не быть загружены в физическую память и лежат в произвольном порядке. И ещё есть искусственное ограничение на размер стека. У меня в настройках проекта стояла цифра 1МБ. Более подробно о стеке можно прочитать в википедии.

template<typename T> class vector {...} - это шаблон C++ контейнера с упорядоченным расположением элементов в свободной памяти. Контейнер - не в том смысле, в каком употребляется в гуишных библиотеках, а для хранения одинаковых структур в памяти. В угловых скобках пишется класс, для которого (основные ограничения):
1. есть явный конструктор по умолчанию explicit T() и конструктор копирования T(const T&)
2. нет побочных эффектов при копировании
3. нет чистых вируальных функций
при раскрытии шаблона создаётся новый класс, который имеет такое хитрое имя vector<T>.

можно сделать через оператор new:

int* mem_TempArray = new int[Position*Rasryad];
...
delete[] mem_TempArray;

но в случае исключения память освобождена не будет (а вектор всегда освобождает за собой память)

Drongo
08-01-2008, 23:41
Доброго здоровья и с прошедшим Рождеством! "стек". Он и действует по принципу "последний зашёл, первый вышел". » Да, спасибо большое, я сегодня читал, по классу vector есть ещё list и deque, прочитал, что vector и deque, более "близки" по принципу, добавляют данные только в начало или в конец, а list, может добавлять в середину спискаtemplate<typename T> » шаблоны изучал, но не глубинно, ещё знаю, что есть стеки, очереди, деревья, списки, также, что принцип - "первый вошёл - первый вышел", "первый вошёл - последний вышел", но это я ещё буду основательно изучать в скором времени, но коль столкнулся уже сейчас, то почему бы паралельно не захватить багаж знаний касательно сих вещей, Вам,pva, с глубоким уважением жму руку, за терпение к моим вопросам! А так же 5pliT'у! Ошибку компилятор выдавал ту что Вы говорили, stack overflow », мне казалось, что при размере большем, чем 20000, массив правильно не выделяется, и элементам не "удаётся правильно" расположиться последовательно, поэтому происходит такая ошибка... pva, Вы могли бы мне объяснить эти строки или поправить меня?! Я сейчас напишу, как я их понял.
1.
vector<int> mem_TempArray(Position * Rasryad);
int* TempArray[Rasryad];
Вы создаёте массив целых чисел и приводите его к типу vector, а потом создаём массив указателей TempArray на целое число, для того, чтобы хранились не числа, а адреса, так будет "дешевле" для памяти... Поправьте, или дополните мои пробелы в объяснении.
И вот эту строку.
2.
for(unsigned n = 0; n < Rasryad; ++n) TempArray[n] = &mem_TempArray[Position * n]; Здесь, я немного не понял, &, операция адресации, возвращает адрес своего правого операнда, а потому, думаю, что присваивает адрес массиву указателей! [Position * n] - это расположение элементов соответствено чему?! К примеру, Position = 20000;, а n = 2;, то при умножении, будет TempArray[2] = &mem_TempArray[40000];, тоесть, третьему элементу массива TempArray, присвоится значение... я тут запутался... Объясните пожалуйста...
Кстати, с Вашей модификацией, действительно всё работает на Ура!!!

pva
09-01-2008, 19:06
по пунктам:
1. по правилам C++ vector<int> mem_TempArray(Position * Rasryad); читается как объявление переменной типа vector<int> (это как раз хитрое имя типа) с именем mem_TempArray и использованием конструктора
vector<int>::vector<int>(unsigned size, const int& init = int());
второй массив позволяет не переписывать ваш код (на самом деле есть много способов эффективно обойтись без него).
В нашем случае каждому элементу TempArray присваивается адрес каждого последовательного блока размером Position. То есть адрес начала каждой строчки.

2. В C++ можно переопределять почти все операторы. У vector<T> есть операторы:

const T& vector<T>::operator[](unsigned pos) const;
T& vector<T>::operator[](unsigned pos);

они возвращают ссылку на элемент по номеру pos. Адрес ссылки - это адрес памяти этого элемента.
таким образом, если у нас vector<int>, Position=10000, то каждому n-ному элементу TempArray присваивается адрес _data + n*10000*sizeof(int), где _data - это адрес куска, который занял вектор.

на всякий случай напомню, что для 32-разрядной ОС windows виртуальная память линейная, размером до 4Gb и считается, что типы данных имеют значения (гробо):
short -32K..+32K
long -2G..+2G
int -2G..+2G
unsigned short 0K..+64K
unsigned long 0K..+4G
unsigned int 0K..+4G
то есть теоретически в вектор может поместиться (4G - _data)/sizeof(T) значений. Думаю 100 миллионов int в памяти поместятся легко (только в глубокий свап уйдут)

Drongo
09-01-2008, 19:28
В нашем случае каждому элементу TempArray присваивается адрес каждого последовательного блока размером Position. То есть адрес начала каждой строчки. »
И мы имеем не один громадный массив, а несколько малых по сравнению с двухмерным, вернее адресов на них! Спасибо большое!!!




© OSzone.net 2001-2012