· Начало · Статистика · WASM.RU · Noir.Ru ·

 WASM Phorum (Оффлайн - 24.11.2003) —› WASM.A&O —› Мне бы сортировочку

<< . 1 . 2 . 3 . >>

Посл.отвђт Сообщенiе


Дата: Авг 23, 2003 07:30:57

Удаление элементов -- это так же операция упорядочевания.
Не могу с этим согласиться, но это, в принципе, неважно.
По поводу удаления одинаковых элементов из отсортированного массива. Удалять каждый раз по одному элементу накладно, если массив большой, а повторяющихся элементов много. Есть другой способ, попытаюсь объяснить его на примере. Пусть есть массив: 0 1 1 2 3 4 4 4 5 6 6. После нахождения единиц сдвигаем так: 0 2 3 ? ? 4 4 4 5 6 6. Символ "?" означает "пустую" ячейку. После обнаружения четвёрок делаем следующее: 0 2 3 5 ? ? ? ? ? 6 6. И, дойдя до конца - 0 2 3 5 6. Таким образом, в итоге мы перемещаем байт не более, чем размер массива.


Дата: Авг 23, 2003 09:59:48

А если при формировании массива (или списка) проверять есть такой элемент в нем или нет? и добавлять новые только по мере надобности?
(В математике это называвется множества)


Дата: Авг 23, 2003 13:28:45 · Поправил: bsl_zcs

2 volodya:
Народ, подскажите мне, тупому, какая такая сортировка есть, чтобы она мне в массиве (или в списке при связанном хранении, неважно) грохнула все одинаковые int.

При такой постановке вопроса самый правильный с точки эффективности ответ - сортировка вставками. Она позволит во-первых сортировать только уникальные значения, во-вторых обойтись без дополнительных затрат памяти. Другое дело, что она сама по себе не слишком эффективна...

А на более общий вопрос ответ гораздо более сложен. Он зависит от характера входных данных: диапазона входных значений, количества различных входных значений, общего размера входных данных.

В случае, когда диапазон входных значений невелик (например, при сортировке байтов или 16-битных слов), эффективнее всего radix sort (в данном случае, это то, о чём говорил Artem в первой реплике).

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

Для остальных случаев разумно применить хэш-таблицу.

Вариантов может быть много. Если назовёшь конкретнее сколько и чего ты там собираешься сортировать, можно будет говорить предметно.

Да, насчёт указателей: если размер сортируемых элементов вызывает серьёзные накладные разсходы на пересылку, следует сортировать массив указателей на них. Когда размер элемента равен размеру указателя, это, разумеется, смысла не имеет.


Дата: Авг 23, 2003 20:05:22

Artem

Хм... Оригинально! Но геморно реализовать!

DaemoniacaL

Стоит подумать тщательнее. Поразмыслю над этим в понедельник!

bsl_zcs

Ну гляди тады :)
Имею односвязный список (т.е. я не знаю, сколько элементов мне надо будет в него положить - предполагаю, не более 10-20, поэтому можно и тупо его перебрать, но красоты хочется) следующего вида:

struct node
{
   int int1;
   int int2;
   struct next *node;

}


в синтаксисе ошибки, ну да хрен с ними. Вывод об идентичности элементов делается просто - если int1/int2 одного узла равны int1/int2 другого. Если я встречаю такой элемент - я должен его удалить и перелинковать список (т.е. переписать поинтер предыдущего узла).

В этом случае, я полагаю, нужно использовать твою поразрядную (т.е. radix) сортировку.

http://algolist.manual.ru/sort/radix_sort.php
там как раз пример со списками - код там же. Только теперь надо вставить в тот код пример с удалением избыточности из такого списка. А для этого надо детально разобраться с этим делом! Было бы здорово если бы ты мне на пальцах расписал, куда там и что вставлять. А вообще, на RSDN хорошая статья по этому делу есть - я ее прочту.


Вообще, ребята, спасибо. Мне очень приятно, что на наш форум забредают люди с хорошо выраженными способностями к алгоритмизации, т.к. знания сами по себе достаточным условием для звания "программист" не являются. Это тривиально и зависит от количества прочитанных книжек. Вот способность к алгоритмизации - вещь серьезная. Будучи биохимиком :), у меня такие вещи вызывают уважение.


Дата: Авг 23, 2003 20:42:18 · Поправил: volodya

Я чего-то с головой дружить перестал. Какая ж тут на хрен сортировка, если в каждом узле у меня два элемента!! На фига тут сортировать и как сортировать. Нет! Лучше не допускать такие элементы в список и все.
Что до radix сортировки, то из спортивного интереса, смотрите:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

typedef struct slist_
{ 
  long val;
  struct slist_ *next; 
} slist;

// функция сортировки возвращает указатель на начало отсортированного списка 
slist *radix_list(slist *l, int t) {
  //  t - разрядность (максимальная длина числа) 
  int i, j, d, m=1;
  slist *temp, *out, *head[10], *tail[10];
  out=l;

  for (j=1; j<=t; j++) { 
    for (i=0; i<=9; i++)
      head[i] = (tail[i]=NULL);

    /*первый проход - заполняем head*/
    while ( l != NULL ){
      /*получить первую справа цифру текущего узла*/
      d = ((int)(l->val/m))%(int)10;     
      temp = tail[d];
      if ( head[d]==NULL ) head[d] = l;
      else temp->next = l;
      temp = tail[d] = l;
      l = l->next;
      temp->next = NULL;
    }
    for (i=0; i<=9; i++)
      if ( head[i] != NULL ) break;
    l = head[i];
    temp = tail[i];
    /*второй проход - сборка списка*/
    for (d=i+1; d<=9; d++) {
      if ( head[d] != NULL) { 
        temp->next = head[d];
        temp = tail[d];
      }
    }
    m*=10;
  }
  return (out);
}

void AppendNode(slist **headRef, int num) 
{
	slist *current = *headRef;
	slist *newNode;
	
	newNode = malloc(sizeof(slist));
	newNode->val = num;
	newNode->next = NULL;
	if (!current) 
	{
		*headRef = newNode;
	}
	else 
	{
		while (current->next) 
		{
			current = current->next;
		}
		current->next = newNode;
	}
}


void main(void)
{
	slist *l = NULL;
	int i = 0;
	
	srand(time(NULL));
	
	while(i<20) 
	{
		AppendNode(&l, (int)rand()%1000);
		i++;
	}
	radix_list(l, 4);
}



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


Дата: Авг 25, 2003 07:42:16 · Поправил: Artem

Хм... Оригинально! Но геморно реализовать!
Не так уж и геморно. Если кому интересно - вот исходничек:
//на входе уже отсортированный массив
void DeleteSame(T* m,DWORD &Size)
{
 int DiffEnd=0,SameEnd=0,a;
 for (a=0;a<Size-1;a++)
  if (m[a]==m[a+1]) {
   if (DiffEnd!=SameEnd)
    memmove(m+DiffEnd,m+SameEnd,(a-SameEnd)*sizeof(*m));
   DiffEnd+=a-SameEnd;
   for (a++;a<Size-1 && m[a]==m[a+1];a++);
   SameEnd=a+1;
  }
 if (DiffEnd!=SameEnd) {
  memmove(m+DiffEnd,m+SameEnd,(Size-SameEnd)*sizeof(*m));
  Size-=SameEnd-DiffEnd;
 }
}


Какая ж тут на хрен сортировка, если в каждом узле у меня два элемента!! На фига тут сортировать и как сортировать. Нет! Лучше не допускать такие элементы в список и все.

Сравнивать можно так:
int Compare(node* l,node* r)
{
 return l->int1 != r->int1 ? l->int1 - r->int1 : l->int2 -r->int2;
}


А чтобы проверить при добавлении нового элемента, есть он уже или нет, надо делать последовательный поиск, а это ужасно медленно, если массив большой и добавлять нужно часто.


Дата: Авг 25, 2003 13:25:25

Вариант с сортировкой вставками. Никаких списков, никаких предварительных сортировок, никаких удалений, никакого дополнительного расхода памяти.

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

Фича в том, что сортировка, совмещённая с проверкой, позволит сортировать только уникальные элементы. Посему - чем больше избыточность, тем эффективнее это будет работать. Поиск по отсортированному бинарный, следовательно, быстрый.

Вставку можно слегка улучшить путём размещения отсортированного массива не в начале проверенной области, а в её середине, и сдвига элементов при вставке либо вниз либо вверх, в зависимости от того, где меньше. Как упрётся в границу - сдвигать целиком на середину. Успокою: скорее всего, это не понадобится. :)

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

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


Дата: Авг 25, 2003 18:25:53 · Поправил: volodya

bsl_zcs


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


Смысл ясен. Оки-доки.

Artem

Спасибо, классно. Я разобрался :)

Только одно но, ребята. Оба ваши решения для МАССИВОВ!!!
Вот, к примеру, твоя, bsl_zcs, сортировка вставками должна двигаться по массиву НАЗАД! А по односвязанному списку ХРЕН ТАМ назад подвигаешься. А мне нужен именно односвязанный список, т.к. чем приводить такой список к массиву, сортировать массив, а потом возвращать все в круги своя - лучше последовательный поиск!
А вообще - спасибо еще раз!


Дата: Авг 26, 2003 10:42:02

А теперь объясни зачем тебе список?


Дата: Авг 26, 2003 15:21:19

volodya Добавь указатель на предыдущий элемент списка. Сможешь двигаться назад. Только добавится хлопот при изменении элементов списка, особенно в середине. Хотя довольно удобно.


Дата: Авг 26, 2003 17:54:59

bsl_zcs

Объясняю. Есть некая зубодробительная структура, в которой я не знаю сколько элементов лежит (т.е. структур поменьше). Структурки эти связаны одна с другой через односвязный список (примерно такой же). Т.е. я не могу заводить массив (вернее могу, но это тупо, т.к. придется заводить его достаточно большого размера заранее, чтобы не возиться с realloc). Кроме того, придется заводить не просто массив, а массив из структур. Ничего страшного, в общем-то, но алгоритм сортировки усложнится :)
Слушай, что мне, никто ничего по списку сказать не может?

Вот еще два алгоритма по спискам:
//Функция возвращает указатель на отсортированный список.
..
typedef struct OBJ1{
  int K;
  struct OBJ1*NEXT;
}OBJECT1;
..
OBJECT1*Sort(OBJECT1*head){//Function starts here
  OBJECT1 *newh,*max,*prev,*pmax,*cur;
  newh=NULL;
  while(head){
    max=prev=head;
    cur=head->NEXT;
    while(cur){
      if(cur->K>max->K){max=cur;pmax=prev;}
      prev=cur;cur=cur->NEXT;
    }
    if(max==head)head=head->NEXT;
    else pmax->NEXT=max->NEXT;
    max->NEXT=newh;newh=max;
  }
  return newh;
}------=_20030826132558_22220
Content-Type: text/plain; name="7.txt"
Content-Disposition: attachment; filename="7.txt"

Пример 7.
//Функция возвращает указатель на отсортированный список.
..
typedef struct OBJ1{
  int K;
  struct OBJ1*NEXT;
}OBJECT1;
..
OBJECT1*Sort(OBJECT1*head){//Function starts here
  OBJECT1 *newh,*cur,*sel;
  newh=NULL;
  while(head){
    sel=head;
    head=head->NEXT;
    if(newh==NULL||sel->K<newh->K){
      sel->NEXT=newh;newh=sel;
    }else{
      cur=newh;
      while(cur->NEXT&&cur->NEXT->K<sel->K)cur=cur->NEXT;
      sel->NEXT=cur->NEXT;
      cur->NEXT=sel;
    }
  }
  return newh;
}


Дата: Авг 26, 2003 18:22:09

Тебе связь в список вообще для чего нужна? Сортировка, то есть последовательность, же тебе некритична... Если только для того, чтобы уникальность обеспечить, то откажись от неё и всё...

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


Дата: Авг 26, 2003 19:06:26 · Поправил: volodya

bsl_zcs

Предложи другую структуру.

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

Во-во! Самое то! Произвольной вставки и удаления. Нашел я такой узел - перелинковал список и все! А в массиве? Методом Артема и сортировать его сначала?


Дата: Авг 26, 2003 20:39:05 · Поправил: volodya

void AppendNode(slist **headRef, int num, int num2) 
{
	slist *current = *headRef;
	slist *newNode;
	
	if (!current) 
	{
		newNode = malloc(sizeof(slist));
		newNode->val = num;
		newNode->val2 = num2;
		newNode->next = NULL;
		*headRef = newNode;
	}
	else 
	{
		while (current->next) 
		{
			if(current->val == num && current->val2 == num2)
			{
				return;  //вот эта самая шутка и не даст нам получить избыточность
			}
			current = current->next;
		}
		newNode = malloc(sizeof(slist));
		newNode->val = num;
		newNode->val2 = num2;
		newNode->next = NULL;
		current->next = newNode;
	}
}


Решил. Все.
Если кому интерестно больше - http://algolist.manual.ru/forum/viewtopic.php?p=3179#3179


Дата: Авг 27, 2003 07:18:18

volodya
Т.е. я не могу заводить массив (вернее могу, но это тупо, т.к. придется заводить его достаточно большого размера заранее, чтобы не возиться с realloc).
А что там с ним возиться? Не так уж и сложно. А выделять malloc'ом память под каждый элемент разорительно (там же ещё несколько байт служебной информации) и медленно.

Кроме того, придется заводить не просто массив, а массив из структур. Ничего страшного, в общем-то, но алгоритм сортировки усложнится :)
Нисколько не усложнится, изменится только функция сравнения.

Во-во! Самое то! Произвольной вставки и удаления. Нашел я такой узел - перелинковал список и все! А в массиве? Методом Артема и сортировать его сначала?
Если главное - простота реализации и удобство использования, можно постоянно поддерживать массив отсортированным и без повторяющихся элементов: при добавлении нового элемента бинарным поиском находим нужное местоположение (или обнаруживаем, что добавляемый элемент уже есть) и вставляем новый элемент туда.

А может, задача может быть решена с использованием контейнеров STL?

<< . 1 . 2 . 3 . >>


Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.063