Twister Мы можем разбить второй файл на блоки не более размера дерева, тогда стоимость сортировки такого блока будет сравнима со стоимостью поиска каждого элемента блока в дереве. Правда для сортировки требуется не только читать память, но еще и записывать, поэтому константа наверно будет больше. Хотя узлы дерева тоже нужно иногда обновлять. Вообще я не думаю что в первом сообщении под "невероятным количеством времени" понималось дерево или сортировка, мне кажется там было что-то совсем ужасное.
Неа Не можем мы разбивать файлы, ибо место разбиения может оказаться как-раз посреди нужной нам сигнатуры. По поводу сортировки: она нужна нам лишь единожды для построения первоначального дерева. Далее при вставке узлов ничего сортировать уже не нужно, нужно лишь вставлять в правильные места. Так что издержки на запись в память в этом случае будут минимальны. Попутный вопрос к ТС: размер сигнатуры кратен чему-нибудь или совсем произволен?
зачем сортировать то? мы просто делаем N деревьев с ветками длиной не более 12, где N - количество различных байт, присутствующих в файле наименьшего размера... корнями будут байты начала последовательностей... и ничего сортировать не надо, обращаемся к корню равному текущему байту, переходим к его веткам, и так спускаемся... если прошли по всей ветке (от 4 до 12 байт по условию), то ветку оставляем... после каждого пройденного файла, те ветки, которые не оказались "помеченными на оставление", удаляем из дерева... на практике, я думаю, что после 3-4 файла проигрыша по памяти уже не будет, но останется выигрыш по скорости...
Rel Мы немного разные варианты обсуждаем. Я предлагаю реализовать одно дерево, каждый узел которого будет являться лишь характеристикой для поиска сигнатуры. Сами же сигнатуры будут содержаться на самом нижнем уровне, эдакий двусвязный список (может и не один). Таким образом мы добъемся минимума проходов по дереву, минимум сравнений. Соответственно, один раз построив такое дерево нам останется лишь добавлять/удалять в него узлы и/или сигнатуры. Вы же предлагаете строить "N деревьев с ветками длиной не более 12, где N - количество различных байт, присутствующих в файле наименьшего размера". Сама идея довольно-таки неплоха, но, имхо, мы потеряем кучу времени на строительстве дерева для каждого файла.
чет я не совсем понял... так мы строим деревья для наименьшего файла, потом наоборот убираем ветки, которые не нашлись в последующих... те ветки, которые остались и будут сигнатурами...
А я "чет" и не знаю, как понятней объяснить... Может просто устал. Чтобы понять ту организацию данных, которую я имею ввиду, рекомендую для начала прочитать все три статьи Joe Celco об одном из способов создания деревьев в SQL. После этого, переложив полученную теорию на наш конкретный случай, должно стать ясно, как увязать дерево и двусвязный список для получения наивысшей скорости поиска.
Решение, от которого даже я, нубас со стажем, пришел в ужос, было примерно таким: Код (Text): PBYTE pfile1, pfile2; PBYTE pos1, pos2; pos1 = pfile1; pos2 = pfile2; for (x=0; x<file1_size; x++) { for(y=0; y<file2_size; y++) { if (memcmp(pos1, pos2, 12) == 0) { add_signature(pos1, 12); } } } Далее файл с сигнатурами сохранялся. И далее шло сравнения подобного файла с файлом_3. И т.д.
точнее вот так... Код (Text): PBYTE pfile1, pfile2; PBYTE pos1, pos2; for (x=0; x<file1_size; x++) { pos1 = pfile1 + x; for(y=0; y<file2_size; y++) { pos2 = pfile2 + y; if (memcmp(pos1, pos2, 12) == 0) { add_signature(pos1, 12); } } }
окей... посмотрю на следующей неделе... и раз зашел разговор о SQL, подскажи какие-нить материалы по внутреннему устройству баз данных (конкретно об организации хранилища в файле, разделении доступов и тд)...
dyn Выделяешь из файлов все тройки байт, потом четверки, 5-ки и тд Заносишь в структуру value, file Потом сортируешь. И за один проход выкидываешь лишнее.
Twister Не знаю как вы будете делать дерево, но вот вариант с двоичным поиском вместо дерева: Код (Text): #include <time.h> #include <stdio.h> #include <stdlib.h> #include <string.h> const MaxA=0x800000; const MaxB=0x800000; const mask=0xFFFFFF; int*a; int*b; void T(char*s) { static clock_t t; clock_t n=clock(); if(s) printf("%s %.3f\n",s,(n-t)/(double)CLOCKS_PER_SEC); t=n; } void fill(int *p,int n,int s,int k,int d) { int i; for(i=0;i<n;i++) { *p++=s&mask; s=s*k+d; } } int read(int*p,int n) { int r=0; while(n>0) { r+=*p; p+=4096/sizeof(*p); n-=4096/sizeof(*p); } return r; } void sort(int *p,int *n) { int *s=p,*e=n; int k=*s++; int *i,t; goto qin; while(s<e) { *e^=*s^=*e^=*s; qin: while(*e>k) e--; while(s<=n&&*s<=k) s++; } s--; *p^=*s^=*p^=*s; e++; /* for(i=p;i<=n;i++){ if(i==e) printf(" E"); printf("%3d",*i); if(i==s) printf(" S"); } printf("\n"); */ if(p<s) sort(p,s); if(e<n) sort(e,n); } find(int *p,int n,int v) { int l=0,r=n-1,a; while(l<r) { a=(l+r+1)>>1; if(p[a]<=v) l=a; else r=a-1; } return p[l]==v; } int main() { int i,s; T(0); a=malloc(MaxA*sizeof(*a)); b=malloc(MaxB*sizeof(*b)); printf("%d\n",read(a,MaxA)+read(b,MaxB)); T("alloc"); fill(a,MaxA,123456,134775813,1); fill(b,MaxB,654321,134775813,1); T("fill"); sort(a,a+MaxA-1); T("sort A"); for(i=0;i<MaxB;i++) s+=find(a,MaxA,b[i]); T("find"); sort(b,b+MaxB-1); T("sort B"); printf("%d\n",s); } время у меня получилось такое: alloc 0.050 fill 0.050 sort A 1.630 find 18.480 sort B 1.640 может у меня просто поиск криво сделан, или массивы плохо заполнены, в общем экспериментируйте.
Twister Сегодня решил поэкспериментировать с хеш-таблицей. Увеличил размер массивов в 16 раз(до 512Мб каждый), а поиск при помощи хеш-таблицы эмулировал таким кодом: Код (Text): for(k=0;k<10;k++) { fill(b,MaxB,clock(),134775813,1); T(0); for(i=0;i<MaxB;i++) s+=a[b[i]&(MaxA-1)]; T("find"); } Время получилось такое: find 19.810 find 27.100 find 22.260 find 17.750 find 15.760 find 15.720 find 18.120 find 15.470 find 15.640 find 22.690 А вот время сортировки массива B получилось около 31 секунды. Конечно заполнение массива B тут далеко от реального, в нём скорее всего нету повторяющихся значений, которые могут испортить быстрой сортировке жизнь, с другой стороны есть ведь и другие алгортмы сортировки, да и хеш-функция сильно упрощена. Так что говорить о полной победе хеш-таблицы над сортировкой применительно к данной задаче еще рано.
Готовыми статьями не интересовался. Но можно заглянуть в сорцы того же огнептица, к примеру. По поводу задачи топика: к сожалению, свободное время закончилось и заняться экспериментами пока не выйдет.