Страницы

Поиск по вопросам

понедельник, 17 декабря 2018 г.

Сортировка массива структур по нескольким полям

Решил задачу, вопрос на которую ранее сам задавал, хочу поделиться.
Задача: есть структура. У структуры три поля: фамилия (char) , имя(char), год рождения (int).
Массив таких структур нужно отсортировать по каждому полю. Т.е. сначала все элементы сортируем по фамилии, затем их сортируем по имени, и потом по году. Сначала у нас идут все элементы с фамилией на А, именем на А и минимальным годом рождения среди тех у кого фамилия и имя на А... затем все с фамилией на В, именем на В и минимальным годом рождением среди тех у кого имя и фамилия на В... Это общий принцип.
Массив структур автомобилей:
struct Car { int idCar = 0; //порядковый номер элемента массива структур (id) int size = 0; //размер элемента структур char regNum[7]; //поле с регистрационным номером char markCar[10];//марка автомобиля char modelCar[10]; //модель автомобиля int mileAge = 0; //пробег автомобиля int isEmpty = 0; //индикатор, если поля марка, модель, рег. номер и пробег пустые, то == 0 };
Функция по расширению, добавлению нового элемента в конец массива структур:
void addCar(Car *cars) {
int N = cars->size; N += 1; int id = N - 1; *cars = *(Car*)realloc(cars, (N+1) * sizeof(Car)); for (int i = 0; i < N; i++) { (cars+i)->size = N; } (cars + id)->idCar = id; (cars + id)->isEmpty = 0; for (int i = 0; i<10; i++) (cars + id)->markCar[i] = '\0'; (cars + id)->mileAge = 0; for (int i = 0; i<7; i++)(cars + id)->regNum[i] = '\0'; for (int j = 0; j<10; j++) (cars + id)->modelCar[j] = '\0'; }
Функция по поиску структурированной переменной с наименьшим значением поля пробег:
void minMileAge(Car *cars) { int min = INT_MAX; for (int i = 0; i < cars->size; i++) { if (min > (cars + i)->mileAge) min = (cars + i)->mileAge; } for (int j = 0; j < cars->size; j++) { if (min == (cars + j)->mileAge && (cars + j)->mileAge != 0) { printf("%d
", (cars + j)->idCar); printf("Регистрационный номер: %s
", (cars + j)->regNum); printf("Марка автомобиля: %s
", (cars + j)->markCar); printf("Пробег автомобиля: %d
", (cars + j)->mileAge); } } }
Функции для сравнения структурированных переменных типа Car:
int my_strcmp(char *s1, char *s2) { for (; *s1 != '\0' && *s2 != '\0' && (*s1 == *s2); s1++, s2++); return *s1 - *s2; } int cmpCar(Car *t1, Car *t2) { int result; if ((result = my_strcmp(t1->markCar, t2->markCar))) return result; if((result = my_strcmp(t1->modelCar, t2->modelCar))) return result; if (result = (t1->mileAge - t2->mileAge)) return result; return my_strcmp(t1->regNum, t2->regNum); }
Функция сортировки массива структур типа Car по 4 полям (методом вставок):
void sortCar(Car *cars) { for (int i = 1; i < cars->size; ++i) { Car x = *(cars+i); int j = i; while (j > 0 && cmpCar((cars + j - 1), &x)>0) { *(cars+j) = *(cars + j - 1); j = j - 1; } *(cars + j) = x; } for(int l = 0; lsize; l++) { printf("ID номер автомобиля %d
", (cars + l)->idCar); printf("Марка автомобиля: %s
", (cars + l)->markCar); printf("Модель автомобиля: %s
", (cars + l)->modelCar); printf("Пробег автомобиля: %d
", (cars + l)->mileAge); printf("Регистрационный номер: %s
", (cars + l)->regNum); } }
И функция поиска элемента из массива структур, по полю, содержащему искомую подстроку:
void allCar(Car *cars) { int result; char sbm[10]; printf("%s", "Введите значение для поиска: "); scanf("%s", &sbm); for (int i = 0; i < cars->size; i++) { if ((strstr((cars + i)->markCar, sbm)!=NULL || (strstr((cars + i)->modelCar, sbm))!=NULL || (strstr((cars + i)->regNum, sbm)!=NULL))) { printf("id автомобилей содержащих значение %d
", (cars + i)->idCar); }
} }


Ответ

Реализация на C - обычный qsort, только функция сравнения должна быть немного сложнее, только и всего. Для типа наподобие
typedef struct Person { char f[20]; char n[20]; int y; } Person;
имеем
int comp(const void * ptr1, const void * ptr2) { Person * p1 = (const Person*)ptr1; Person * p2 = (const Person*)ptr2;
int cmp = strcmp(p1->f, p2->f); if (cmp) return cmp;
int cmp = strcmp(p1->n, p2->n); if (cmp) return cmp;
return p1->y - p2->y; }
Примерно так. Писал "на коленке", не комппилируя - просто показать принцип. Сравниваете по первому полю, при равенстве - по второму, при равенстве - по третьему.
И никаких трех сортировок...

Почему в первом коде не нужен нулевой символ?

У нас есть функция которая принимает две строки и производит слияние
void strcat(char *to, const char *from) { while (*to) to++; while (*to++ = *from++); }
Почему здесь не требуется добавить нулевой символ в отличие например от такого кода
void strcat(char *to, const char *from) { while (*to != '\0') { to++; }
while (*from != '\0') { *to = *from; from++; to++; } *to = '\0'; }


Ответ

Нулевой символ здесь добавляется автоматом.
Выражение
*to++ = *from++
выполняет присвоение, после чего возвращает новое значение *to. То есть, сначала ноль скопируется из *from в *to, а уж потом он будет проанализирован в while, который прекратится.

переменная errno в многопоточной программе

здравствуйте, допустим, в нескольких программных нитях(потоках) вызываем функцию read... и она завершается в одном из нитей, допустим, с errno = EAGAIN, в другой с errno = EBADF... потокобезопасна ли переменная errno, или в каждой нити она своя?


Ответ

Короткий ответ -- да, errno потокобезопасна. Это требование Posix. (смотри этот ответ)

mysqli вывод по одной записи

Добрый день. Есть база такого формата
Структура: id - цифры (идут не всегда по порядку) text - mediumtext (тут какая то цитата)
Задача в том, чтобы выводить их по очереди по 1 записи. А точнее при нажатии кнопки "Следующая" должна вывестись следующая запись с базы данных. Так как id не всегда по порядку, то столкнулся с проблемой реализации, так как с БД еще мало знаком.


Ответ

Вам стоит прочитать про это http://postgresql.ru.net/manual/queries-limit.html
$sql = 'SELECT `id`, `text` FROM `comments` WHERE 1 LIMIT 1 OFFSET.$page;
Вообще советую не пилить велосипед и использовать Doctrine
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/query-builder.html
Так как запросы в php весьма сложны в обслуживании.

Есть ли возможность отключить assert?

Собственно и весь вопрос в заголовке.
Если такой возможности нет, то не пойму, в чем ценность такой инструкции как assert вообще?
А то как-то все неубедительно. Ведь можно простыми if ...: print() в одну строку обойтись... P.S: я уже получил ответ от andreymal, однако интересно отключить assert первой строчкой в коде... возможно ли это? Ведь os.environ читается до первой строчки модуля...


Ответ

assert, в отличие от if, предназначен для обнаружения ситуаций, которые задумывались как в принципе невозможные в программе: для поиска багов. Отключать assert обычно не стоит, но для ускорения программы это иногда может быть полезным.
Для его отключения есть несколько способов.
Для отдельного Python-процесса
Использование флага -O (большая латинская O) включает базовую оптимизацию и отключает все assertы в данном процессе.
Пример:
$ python -Oc "assert False"
$ python -c "assert False" Traceback (most recent call last): File "", line 1, in AssertionError
Для окружения
Можно использовать переменную окружения для установки этого флага. Тогда он будет применён ко всем процессам, использующим данное окружение.
Например, установка и очистка переменной окружения в Windows:
C:\>python -c "assert False" Traceback (most recent call last): File "", line 1, in AssertionError C:\>SET PYTHONOPTIMIZE=TRUE
C:\>python -c "assert False"
C:\>SET PYTHONOPTIMIZE=
C:\>python -c "assert False" Traceback (most recent call last): File "", line 1, in AssertionError
Для конкретного места в коде
Когда выражение, прописанное в assert, ложно, выбрасывается исключение AssertionError. Если ожидается, что такой-то assert провалится, можно просто перехватить это исключение:
>>> try: ... assert False, "мы знаем, что это упадёт" ... except AssertionError as e: ... print(repr(e)) ... AssertionError('мы знаем, что это упадёт',)
После такого перехвата исключения, если вы не выбросите новое исключение, программа продолжит выполняться дальше.
(Впрочем, так делать плохо: если assert провалился, нужно принять все меры по исправлению программы так, чтобы он больше не проваливался, а не скрывать возможный баг таким костылём.)
Дополнительная информация
Из документации assert
Выражение с assert, вроде такого:
assert expression #, optional_message
Эквивалентно такому коду:
if __debug__: if not expression: raise AssertionError #(optional_message)
И
встроенная переменная __debug__ имеет значение True в обычных условиях и False, если включены оптимизации (аргумент командной строки -O).
Из документации по использованию python
-O Включает базовые оптимизации. См. также PYTHONOPTIMIZE
и
PYTHONOPTIMIZE Если эта переменная является непустой строкой, это аналогично использованию опции -O. Если в переменной указано целое число, это аналогично добавлению опции -O несколько раз.

Слегка вольный перевод ответа от Aaron Hall на enSO

заменить строки в одном текстовом файле информацией из второго

Именются 2 гигантских текстовых файла.
file1.txt (3,6 Гб) содержит только одну колонку (в том числе много дубликатов):
123456 123456 123456 абвгд абвгд 01щенок 01щенок 01щенок 01щенок 01щенок a0125uß a0125uß
file2.txt (1,5 ГБ) содержит ту же колонку, но без дубликатов плюс вторую колонку.
123456:artur абвгд:sergey 01щенок:max a0125uß:stasik
Задача: сравнить первые колонки в обеих файлах и заменить одинаковые строки в первом файле, строками из второй колонки второго файла, чтобы получилось следующее (дубликаты в первом файле должны остаться):
artur artur artur sergey sergey max max max max stasik stasik
У меня есть такой код:
import io STRFILE1 = 'file1.txt' STRFILE2 = 'file2.txt' STRFILERESULT = 'result.txt' fIN = open(STRFILE1,'r') strContent = fIN.read() fIN.close()
with open(STRFILE2,'r') as f: for line in f: mapping = line.split(":",1) strContent = strContent.replace(mapping[0],mapping[1].rstrip("
"))
fOUT = open(STRFILERESULT,'w') fOUT.write(strContent) fOUT.close()
но он работает вечно с таким объёмом строк (102.600.000 - файл 1 и 50.000.000 - файл 2). Как можно ускоритъ процесс обработки?


Ответ

Если на python, то можно так:
def story_key(): with open('te2', 'r') as f2: my_key = {i.split(':')[0]: i.split(':')[1].strip() for i in f2} return my_key
all_key = story_key()
def read_small(f_object, f_size=1024): while True: data = f_object.read(f_size) if not data: break yield data
def f_write(): with open('te1') as f1: with open('te3', 'a') as f3:
for i in read_small(f1): a = [all_key[j] + '
' for j in i.split('
') if j] f3.write(''.join(a))
f_write()

Многопоточность в java, почему порядок вывода результата разнится?

Допустим есть такой код. Его результат:[Синхронизация] [в Java] [ полезная] . Если объект Caller запускать без отдельного потока (т.е без "extends Thread" и без метода "start()"), то результат будет в другом порядке- [Синхронизация] [полезная] [в Java] Почему так происходит? Прошу дать развернутый ответ.
class CallMe{ void call(String msg){ System.out.print("[" + msg ); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("]"); } }
class Caller extends Thread{ String msg; CallMe target;
Caller(CallMe target, String msg){ this.target = target; this.msg = msg; start(); }
public void run(){ synchronized (target) { target.call(msg); } } }
public class Main { public static void main(String[] args) { CallMe callMe = new CallMe(); new Caller(callMe, "Синхронизация"); new Caller(callMe, "в Java"); new Caller(callMe, " полезная"); } }


Ответ

Поставьте задержку на 200 миллисекунд в методе run(), а в методе main() добавьте цикл операций на 100 - получите еще больше вариантов.
Потому что невозможно предсказать какой поток войдет в блок synchronized первым, даже если вы их запускаете последовательно.
Для синхронизации потоков используются классы
Semaphore CountDownLatch CyclicBarrier Lock
у них различные цели и методы. Это зависит от конкретной задачи.

Semaphore - как правило служит для ограничения количества потоков при работе с ресурсами. Доступ ограничивается с помощью счетчика, если его значение больше нуля, то доступ потоку разрешается, а значение счетчика уменьшается. Если счетчик равен нулю, то текущий поток блокируется, пока другой поток не освободит ресурс. Для получения доступа используется метод acquire(), для освобождения – release()
public class SemaphoreDemo { public static void main(String[] args) { Semaphore smp = new Semaphore(2); for (int i = 0; i < 5; i++) { final int w = i; new Thread(() -> { try { System.out.println("Поток" + w + " перед семафором"); smp.acquire(); System.out.println("Поток" + w + " получил доступ к ресурсу"); Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } finally { System.out.println("Поток" + w + " освободил ресурс"); smp.release(); } }).start(); } } }
Результат работы:
Поток 0 перед семафором Поток 0 получил доступ к ресурсу Поток 2 перед семафором Поток 2 получил доступ к ресурсу Поток 1 перед семафором Поток 4 перед семафором Поток 3 перед семафором Поток 2 освободил ресурс Поток 1 получил доступ к ресурсу Поток 0 освободил ресурс Поток 4 получил доступ к ресурсу Поток 4 освободил ресурс Поток 1 освободил ресурс Поток 3 получил доступ к ресурсу Поток 3 освободил ресурс
Одновременно семафор могут захватить(с помощью метода acquire()) только два потока, остальные потоки становятся в очередь, пока один из потоков не освободит семафор методом release()

CountDownLatch - Позволяет потоку ожидать до тех пор, пока не завершится определенное количество операций, выполняющихся в других потоках, в режим ожидания поток заходит с помощью метода await(). Количество требуемых операций задается при создании объекта, после чего уменьшается при вызове метода countDown(). Как только счетчик доходит до 0, ожидающий поток разблокируется.
public class SimpleCDL { public static void main(String[] args) { // задаем кол-во потоков final int THREADS_COUNT = 6; // задаем значение счетчика final CountDownLatch cdl = new CountDownLatch(THREADS_COUNT); System.out.println("Начинаем"); for (int i = 0; i < THREADS_COUNT; i++) { final int w = i; new Thread(() -> { try { // считаем что выполнение задачи занимает ~1 сек Thread.sleep(500 + (int)(500 * Math.random())); // как только задача выполнена, уменьшаем счетчик cdl.countDown(); System.out.println("Поток #" + w + " - готов"); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); } try { // ждем пока счетчик не сбросится в ноль, пока это не // произойдет, будем стоять на этой строке cdl.await(); } catch (InterruptedException e) { e.printStackTrace(); } // как только все потоки выполнили свои задачи - пишем сообщение System.out.println("Работа завершена"); } }
Результат работы:
Начинаем Поток #1 - готов Поток #0 - готов Поток #3 - готов Поток #2 - готов Поток #4 - готов Поток #5 - готов Работа завершена
Основной поток создает 6 потоков и ждет пока каждый из этих потоков закончит приготовление к работе.

CyclicBarrier - используется для синхронизации заданного количества потоков в одной точке. При вызове метода await() поток блокируется. Как только заданное количество потоков заблокировалось, с них одновременно снимается блокировка.
public class BarrierExample { public static void main(String[] args) { CyclicBarrier cb = new CyclicBarrier(3); for (int i = 0; i < 3; i++) { final int w = i; new Thread(() -> { try { System.out.println("Поток " + w + " готовится"); Thread.sleep(100 + (int) (3000 * Math.random())); System.out.println("Поток " + w + " готов"); cb.await(); System.out.println("Поток " + w + " запустился"); } catch (Exception e) { e.printStackTrace(); } }).start(); } } }
Результат работы:
Поток 0 готовится Поток 1 готовится Поток 2 готовится Поток 2 готов Поток 0 готов Поток 1 готов Поток 1 запустился Поток 2 запустился Поток 0 запустился Результат работы: Поток 0 готовится Поток 1 готовится Поток 2 готовится Поток 2 готов Поток 0 готов Поток 1 готов Поток 1 запустился Поток 2 запустился Поток 0 запустился
Несмотря на то, что какие-то потоки закончили подготовку раньше, какие-то позже, стартовали они в одно и то же время, так как блокировка снимается одновременно. Несмотря на то, что какие-то потоки закончили подготовку раньше, какие-то позже, стартовали они в одно и то же время, так как блокировка снимается одновременно.

Lock - Интерфейс. Представляет собой продвинутый механизм синхронизации потоков, который предоставляет большую гибкость чем блоки синхронизации. Поскольку Lock это интерфейс, для работы с ним необходимо создать объект одной из его реализаций.
Lock lock = new ReentrantLock(); lock.lock(); lock.unlock();
В начале создается объект типа Lock, после чего у этого объекта вызывается метод lock() и он захватывается. Попытка другого потока вызвать у этого же объекта метод lock() приведет к блокировке этого потока, пока поток удерживающий объект lock не освободит его с помощью метода unlock(). После вызова метода unlock() объект типа Lock освобождается и другие потоки могут его захватить Основные отличия между Lock и синхронизированными блоками:
Синхронизированные блоки не гарантируют сохранность порядка обращения потоков к критической секции; Выйти из синхронизированного блока по времени ожидания(timeout) не получится; Синхронизированные блоки должны полностью содержаться в одном методе, в то время как Lock может быть захвачен в одном метода, а освобожден в другом.