Модераторы: Snowy, MetalFan, bems, Poseidon

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Сортировка массива 
:(
    Опции темы
Keeper89
Дата 4.2.2010, 17:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2580
Регистрация: 26.2.2009

Репутация: 9
Всего: 58



Доброго времени суток.

Имеется динамический массив целых чисел достаточно большой размерности (например, 100 столбцов х 100 строк).
Как грамотнее реализовать сортировку по выбранному столбцу по убыванию или возрастанию?

Это сообщение отредактировал(а) Keeper89 - 4.2.2010, 17:11


--------------------
PM MAIL WWW   Вверх
~FoX~
Дата 4.2.2010, 17:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЕ рыжий!!!
****


Профиль
Группа: Участник Клуба
Сообщений: 2819
Регистрация: 8.10.2003
Где: Зеленоград

Репутация: 5
Всего: 68



Keeper89, Ну на таких величинах прекрасно работает быстрый сорт (быстродействие O(n log n)) ... http://algolist.ru/sort/quick_sort.php


--------------------
user posted image
…множественность никогда не следует полагать без необходимости…
PM MAIL WWW ICQ Jabber   Вверх
Keeper89
Дата 4.2.2010, 21:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2580
Регистрация: 26.2.2009

Репутация: 9
Всего: 58



~FoX~, а что если использовать встроенные классы типа TList или TObjectList? В них уже есть реализация быстрой сортировки. 


--------------------
PM MAIL WWW   Вверх
Keeper89
Дата 5.2.2010, 01:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2580
Регистрация: 26.2.2009

Репутация: 9
Всего: 58



Да, и получается нужно во внутреннем цикле соответственно менять элементы столбцов, которые не сортируются?


--------------------
PM MAIL WWW   Вверх
~FoX~
Дата 5.2.2010, 08:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЕ рыжий!!!
****


Профиль
Группа: Участник Клуба
Сообщений: 2819
Регистрация: 8.10.2003
Где: Зеленоград

Репутация: 5
Всего: 68



Цитата(Keeper89 @  4.2.2010,  22:02 Найти цитируемый пост)
~FoX~, а что если использовать встроенные классы типа TList или TObjectList? В них уже есть реализация быстрой сортировки.

На счет Tlist и TObjectList не припомню что бы там сортировка хоть какая то была, А вот TStringList именно быстрым сортится... Только критерий там один - по первому символу.... Т.е. в твоем случае только по первому столбцу
Цитата(Keeper89 @  5.2.2010,  02:00 Найти цитируемый пост)
Да, и получается нужно во внутреннем цикле соответственно менять элементы столбцов, которые не сортируются? 

Придется, но это не накладно... Ну относительно алгоритма сортировки по крайней мере  smile 


--------------------
user posted image
…множественность никогда не следует полагать без необходимости…
PM MAIL WWW ICQ Jabber   Вверх
Frees
Дата 5.2.2010, 08:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2233
Регистрация: 2.12.2005
Где: Екатеринбург

Репутация: 16
Всего: 54



Цитата(~FoX~ @  5.2.2010,  11:11 Найти цитируемый пост)
Только критерий там один - по первому символу.... Т.е. в твоем случае только по первому столбцу

Функцию сравнения можно свою написать и сортировать как захочешь..


--------------------
Кольцов Виктор Владимирович
PM MAIL ICQ   Вверх
artsb
Дата 5.2.2010, 09:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2280
Регистрация: 17.7.2007
Где: центр Вселенной

Репутация: 1
Всего: 64



Цитата(Keeper89 @  5.2.2010,  01:00 Найти цитируемый пост)
Да, и получается нужно во внутреннем цикле соответственно менять элементы столбцов, которые не сортируются? 

Можно сделать так:
Загнать первый столбец, например в TStringList.
Написать свою функцию сравнения, которая возвращает -1 если нужно поменять местами объекты и 1 или 0 в противном случае.
Помимо этого, сделать проверку: если возвращается -1, тогда "вручную" поменять местами элементы всех столбцов.
Конечно, нельзя сказать, что всё это будет работать очень быстро. Но зато удовлетворяет твоим требованиям smile
Код

// внутри функции сортировки
 if  lst->Strings[iFirst][1] > lst->Strings[iSecond][1] then // сравнение чисто условное
  Result := 1;
 else if lst->Strings[iFirst][1] < lst->Strings[iSecond][1] then
  Result := -1;
 else
  Result := 0;
 
 if Result = -1 then
  begin
   // меняем местами элементы массива
  end;


Это сообщение отредактировал(а) artsb - 5.2.2010, 09:07


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
bems
Дата 5.2.2010, 12:19 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 18
Всего: 88



Код

 uses Generics.Collections, Generics.Defaults;

 type TIntArr = array of Integer;
      TInt2DArr = array of TIntArr;

 procedure Sort(var Data: TInt2DArr; Index: Integer);
 begin
 TArray.Sort<TIntArr>(Data, TComparer<TIntArr>.Construct(
   function(const Left, Right: TIntArr): Integer
   begin
   Result := Left[Index] - Right[Index]
   end));
 end;



--------------------
Обижено школьников: 8
PM MAIL   Вверх
artsb
Дата 5.2.2010, 12:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2280
Регистрация: 17.7.2007
Где: центр Вселенной

Репутация: 1
Всего: 64



Keeper89, прикрепляю пример. Посмотри и скажи, правильно ли я тебя понял.

Это сообщение отредактировал(а) artsb - 5.2.2010, 22:32

Присоединённый файл ( Кол-во скачиваний: 6 )
Присоединённый файл  sort.exe 627,00 Kb


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
Keeper89
Дата 5.2.2010, 15:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2580
Регистрация: 26.2.2009

Репутация: 9
Всего: 58



artsb, абсолютно правильно.

bems, спасибо, решение с дженериками - супер! smile
Единственное добавил еще одну вещь:
Код

type
  TSortType = (stAscending, stDescending);

procedure Sort(var Data: TMatrix; Index: Integer; SortType: TSortType);
begin
  TArray.Sort<TIntArr>(Data,
    TComparer<TIntArr>.Construct(
      function(const Left, Right: TIntArr): Integer
      begin
        Result := Left[Index] - Right[Index];
        if SortType = stDescending then
          Result := -Result;
      end)
    );
end;



--------------------
PM MAIL WWW   Вверх
artsb
Дата 5.2.2010, 16:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2280
Регистрация: 17.7.2007
Где: центр Вселенной

Репутация: 1
Всего: 64



Цитата(Keeper89 @  5.2.2010,  15:58 Найти цитируемый пост)
решение с дженериками - супер!

А этот вариант случаем не сортирует всё подряд? Вроде как нужно было по конкретному столбцу. Просто я в Делфи не силён...

Добавлено через 2 минуты и 51 секунду
Всё. Кажись понял smile


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
artsb
Дата 5.2.2010, 22:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2280
Регистрация: 17.7.2007
Где: центр Вселенной

Репутация: 1
Всего: 64



Выкладываю своё решение (правда на С++). Мало ли, кому-нибудь пригодится.
Выкладываю на С++, т.к. плохо знаком с Делфи. Хотя и могу перевести код и он даже будет работать, но скорее всего, будет не эффективен. И к тому же, могут быть скрытые ошибки.

Код

// некий массив 10х10
int mas[10][10] = {{9,5,6,2,8,1,0,5,4,1},
                   {8,3,1,6,5,7,2,8,0,2},
                   {7,8,1,0,4,7,2,9,4,6},
                   {6,5,6,2,2,4,8,6,0,4},
                   {5,1,6,3,7,8,2,5,3,0},
                   {4,7,7,5,2,7,1,0,8,5},
                   {3,4,7,2,8,1,3,5,3,8},
                   {2,1,3,7,2,9,4,7,3,0},
                   {1,4,4,7,2,8,4,6,6,9},
                   {0,5,2,6,1,7,3,8,3,7}};

// функция сортировки
// mas   - указатель на массив
// iCols - количество столбцов в массиве
// iCol  - индекс столбца, по которому нужно произвести сортировку
// L     - левый индекс сортируемого участка
// R     - правый индекс сортируемого участка
void _QuickSort(int *mas, const int iCols, const int iCol, int L, int R) {
  int I, J, P, T;

  do {
    I = L;
    J = R;
    P = mas[((L + R) >> 1)*iCols+iCol];
    do {
      while(mas[I*iCols+iCol] < P)
        ++I;
      while(mas[J*iCols+iCol] > P)
        --J;
      switch(I<=J?(I<J?0:1):-1) {
       case 0:
        for(register int i=0; i<iCols; ++i) {
          T = mas[I*iCols+i];
          mas[I*iCols+i] = mas[J*iCols+i];
          mas[J*iCols+i] = T;
        }
       case 1:
        ++I;
        --J;
      }
    } while(I < J);
    if(L < J)
      _QuickSort(mas, iCols, iCol, L, J);
    L = I;
  } while(I < R);
}

// использование:
_QuickSort(*mas, 10, 0, 0, 9);

Алгоритм стащил из реализации в classes.pas smile
Объясню почему я написал так:
Код

      switch(I<=J?(I<J?0:1):-1) {
       case 0:
        for(register int i=0; i<iCols; ++i) {
          T = mas[I*iCols+i];
          mas[I*iCols+i] = mas[J*iCols+i];
          mas[J*iCols+i] = T;
        }
       case 1:
        ++I;
        --J;
      }

, а не оставил так как это было реализовано в classes.pas:
Дело в том, что там было написано приблизительно так:
Код

      if(I<=J) {
        for(register int i=0; i<iCols; ++i) {
          T = mas[I*iCols+i];
          mas[I*iCols+i] = mas[J*iCols+i];
          mas[J*iCols+i] = T;
        }
        ++I;
        --J;
      }

Здесь получается, что когда индексы совпадают, т.е. I==J происходит перестановка элементов с этими индексами, но это бессмысленно как вы понимаете smile (пустая трата времени)

ЗЫ профи поправьте меня если что  smile 


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
bems
Дата 5.2.2010, 23:25 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 18
Всего: 88



Keeper89, попросить пояснений ты мог бы прямо в этой теме. Итак:

Класс Generics.Collections.TArray умеет искать двоичным поиском и сортировать методом быстрой сортировки. Это объеденино в класс, потому что невозможно создать обобщенную функцию, не член класса/объекта. Это ограничение языка. Все методы это методы класса, поэтому не нужно создавать экземпляр TArray.

Метод Generics.Collections.TArray.Sort<T> выполняет быструю сортировку массива элементов типа, указанного в Т. 
Код

    class procedure Sort<T>(var Values: array of T); overload;
    class procedure Sort<T>(var Values: array of T; 
      const Comparer: IComparer<T>); overload;
    class procedure Sort<T>(var Values: array of T; 
      const Comparer: IComparer<T>; Index, Count: Integer); overload;

Values - собственно массив. В моем примере я объявляю типы
Код

type TIntArr = array of Integer;
     TInt2DArr = array of TIntArr;

Это нужно только для того чтобы объявление параметра Data не воспринималось как открытый массив, это приводит к несоответствию типов. Это ограничение данного конкретного случая, а не класса TArray или дженериков в целом. Я имею в виду, что в T можно прямо указать array of Integer не объявляя промежуточного типа.
Если Index и Count не указаны, то сортируется весь массив.
Comparer, это объект, реализующий интерфейс IComparer. Если не указан, то используется компаратор по умолчанию. Я еще не вник, что же это за сравнение по умолчанию для разных типов, но случаи с целыми числами и строками очевидны. 

Класс Generics.Defaults.TComparer<T> это абстактный компаратор двух величин типа, указанного в T. Его метод Compare абстрактен, поэтому не стоит напрямую создавать экземпляры этого класса.

Метод Generics.Defaults.TComparer<T>.Construct создает объект класса, унаследованного от TComparer<T>, а значит также поддерживающего интерфейс IComparer<T> Реально создается экземпляр TDelegatedComparer<T>, у которого  метод Compare уже реализован. Эта реализация просто вызывает функцию по ссылке, переданной при вызове Construct.
Анонимные методы это отдельная тема, погугли это сам.
Благодаря тому, что Construct возвращает не сам свежесозданный объект, а его интерфейс, и тому что TComparer<T> унаследован от TInterfacedObject, ты можешь сразу передать интерфейс в TArray.Sort<T>, не заботясь о сохранении ссылки с целью освобождения. Объект будет разрушен автоматически при обнулении счетчика ссылок (в моем примере это происходит сразу после вызова Sort<T>).


Это сообщение отредактировал(а) bems - 5.2.2010, 23:38


--------------------
Обижено школьников: 8
PM MAIL   Вверх
Keeper89
Дата 6.2.2010, 03:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2580
Регистрация: 26.2.2009

Репутация: 9
Всего: 58



bems, все прояснилось, спасибо!

З.Ы. Я просто думал не засорять тему нужными только мне пояснениями, поэтому отправил ЛС.


--------------------
PM MAIL WWW   Вверх
Keeper89
Дата 21.2.2010, 16:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2580
Регистрация: 26.2.2009

Репутация: 9
Всего: 58



bems, 
Возник вопрос. Возможно ли заменить 
Код

 function(const Left, Right: TIntArr): Integer
      begin
...

на другой тип, например
Код

 function(const Left, Right: TDoubleArr): Real
      begin
...

Или даже не Real, а свой собственный?

Это сообщение отредактировал(а) Keeper89 - 21.2.2010, 16:08


--------------------
PM MAIL WWW   Вверх
bems
Дата 21.2.2010, 17:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 18
Всего: 88



Keeper89, можно, но тогда замени тип и в
TArray.Sort<TDoubleArr> и в
TComparer<TDoubleArr>.Construct



--------------------
Обижено школьников: 8
PM MAIL   Вверх
Keeper89
Дата 21.2.2010, 20:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2580
Регистрация: 26.2.2009

Репутация: 9
Всего: 58



Сделал так:
Код


  TCoefficient = Double;

  TCoefficients = array of TCoefficient;
  TDoubleCoefficients = array of TCoefficients;  // FTable

   ...

  TArray.Sort<TCoefficients>(FTable,
    TComparer<TCoefficients>.Construct(
      function(const Left, Right: TCoefficients): TCoefficient
      begin
        Result := Left[AColumn - 1] - Right[AColumn - 1];
        if ASortType = stDescending then
          Result := -Result;
      end)
    );

И выскакивает ошибка (в 15 строке, где end):
Цитата

Incompatible types: 'TComparison<uKCommonTypes.TCoefficients>' and 'Procedure'


Это сообщение отредактировал(а) Keeper89 - 21.2.2010, 20:12


--------------------
PM MAIL WWW   Вверх
bems
Дата 21.2.2010, 20:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 18
Всего: 88



Не нужно возвращать TCoefficient.
Независимо от типа сравниваемых величин, возвращается целое. <0 если меньше, 0 если равно, >0 если больше


--------------------
Обижено школьников: 8
PM MAIL   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Для новичков"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0643 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.