Запрос идей - Как отсортировать 2d массив с множеством строк и 3 столбцов, поддерживая строки данных

0

Я добился прогресса в проверке файла управления MIT Meep в токенах по расположению символов. Теперь у меня есть массив nx3 целых чисел с тремя столбцами, которые идентифицируют:

  • расположение символов
  • идентификатор токена
  • длина маркера

Кроме того, что они находятся в "найденном" порядке, а не в порядке ввода. Я отмечаю, что расположение символов может стать очень большим, легко в 10 тысяч (т.е. Тысячи строк), в то время как идентификатор токена и длина токена кажутся ниже ста.

Мне нужно отсортировать мой массив nx3 по расположению символов в порядке возрастания без потери двух других столбцов. Я исследовал и, похоже, ответ написал код, реализующий сортировку пузырьков или другой подобный алгоритм.

Есть ли функция C++, которая может сортировать записи в первом столбце моего массива без потери соответствующих записей строк? Немного моего тестового управляющего файла вызвало генерацию массива, который выглядит так:

380  2  1
401  2  1
441  2  1
442  2  1
178  4  13
178  18  7
0  26  5
59  26  5
218  26  5
330  26  5
382  26  5
23  32  5
80  32  5
142  32  5
238  32  5
256  32  5
353  32  5
74  38  5
232  38  5
347  38  5
403  44  4
Теги:
arrays
sorting

4 ответа

0
Лучший ответ

Я потратил день, пытаясь построить структуру. К сожалению, мой опыт c++ не соответствует задаче. Я не мог собрать ничего. Поэтому я пошел по старому фортрану и получил этот код для работы и выполнения того, что мне нужно.

Надувание кода? Скорее всего, из заголовков. Время работы? Циклы через весь длинный поток данных более чем в два раза. О, хорошо, это работает, но если я смогу сделать структурную работу, я бы изменил ее или, по крайней мере, сделал контрольный показатель.

#include <algorithm>    // std::sort
#include <sstream>      // std::istringstream
#include <vector>
#include <iostream>     // std::cout
#include <string>
#include <stdio.h>      // sprintf
using namespace std;

int main() {

std::vector<std::string> data(512);
int length = 8;
size_t arat[length];
int arid[length];
int arlen[length];
int n ;
int i ;
char buffer [17];

arat[0]=     0 ; arid[0] = 1;  arlen[0] = 1;
arat[1]=   418 ; arid[1] = 1;  arlen[1] = 1;
arat[2]=    57 ; arid[2] = 2;  arlen[2] = 1;
arat[3]=   442 ; arid[3] = 2;  arlen[3] = 91;
arat[4]=   178 ; arid[4] = 1;  arlen[4] = 1;
arat[5]= 178632 ; arid[5] =180;  arlen[5] = 226;
arat[6]=     0 ; arid[6] =26;  arlen[6] = 5;
arat[7]=    59 ; arid[7] =26;  arlen[7] = 5;
cout << '\n';
i = 0; 
while(i<length){
n=sprintf (buffer," %*lu  %*d  %*d", 6,arat[i], 3,arid[i], 3,arlen[i]);
if(n < 0) break;
cout << buffer ; data[i] = buffer; cout << data[i] <<'\n'; i++;}
cout << '\n';
std::sort (data.begin(), data.begin()+8); // sort data 0 thru 7, not 8.

i = 0;
while (i < length) {cout << data[i] << '\n';i++;}

cout << '\n';
i = 0;
while (i < length) {
std::istringstream iss (data[i]);
iss >> arat[i] ;        // pick off the first number
iss >> arid[i] ;        // pick off the next number
iss >> arlen[i] ;       // pick off the next number after that.
cout << " size_t value of arat[i] = "<< arat[i] << " int arid[i] = "<<arid[i]
    << " int arlen[i] "<< arlen[i]<<'\n';
 i++; }
cout << '\n';
return 0;
}

Так что это не тот ответ, который я хотел.

1

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

struct Entry {
    int loc, ident, length;
    Entry(int loc, int ident, int length)
      : loc(loc), ident(ident), length(length)
    {}

    bool operator<(const Entry& other) const {
        return loc < other.loc;
    }
};

После этого вы можете просто использовать стандартную функцию sort

std::vector<Entry> data;
// ... fill the vector ...
std::sort(data.begin(), data.end());

Если вместо этого массив уже задан как int data[][3] все более раздражает, я бы, вероятно, поместил бы вручную, создав сортировку shell-metzener:

for (int m=n>>1; m>0; m>>=1) {
    for (int j=0; j<n-m; j++) {
        for (int i=j; i>=0 && data[i][0]>data[i+m][0]; i-=m) {
            std::swap(data[i][0], data[i+m][0]);
            std::swap(data[i][1], data[i+m][1]);
            std::swap(data[i][2], data[i+m][2]);
        }
    }
}

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

1

Возможно, вы могли бы определить ваши строки как structs {a, b, c}, сравнить поля a и затем использовать функцию присваивания структуры компилятора для замены структур (по сути, свопинга строк).

typedef struct ROW {
    int a, b, c;
};
struct ROW A, B;
...
if (A.a > B.a) {
    struct ROW tmp = A; A = B; B = tmp;
}

Помогает ли это?

0
typedef struct row_head 
{
int char_loc;
int token_index;
};

vector<row_head> heads;
vector<int> token_id;
vector<int> token_length;

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

{380,0}  5 1

{401,1}  8  1

{441,2}  9  1

{442 ,3} 10  2

{178 ,4} 4  1

После сортировки данных в головах будет выглядеть так:

{178,4}

{380,0}

{401,1}

{441,2}

{442,3}

Фактические данные токена остаются неизменными:

5  1

8  1

9  1

10  2

4  1
  • 0
    Означает ли это, что когда я нахожу токены, я должен хранить char_loc; и token_index; в векторе row_heads, и token_id и длину токена в двух других векторах, вместо того, чтобы хранить их все в массиве nx3 int? Это кажется правдоподобным, поэтому все, что мне действительно нужно, это практические знания: typedef struct row_head {int char_loc; int token_index; }; Я должен искать это.
  • 0
    Вы можете иметь два массива nx2, первый массив содержит расположение символов и индекс токена. Второй массив может содержать идентификатор токена и длину токена.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню