LINUX.ORG.RU

Задачки от yandex


5

3

Хотела задать вопрос в talks, но почему у меня нет такой возможности. Я недавно занялась изучением программирования на c++, поэтому прошу сильно не ругаться.

Не так давно наткнулась на вакансию разработчика в yandex, и там обнаружила несколько вопросов. Страница уже удалена, но доступна в кэше: http://webcache.googleusercontent.com/search?q=cache:l4nvA4HtP5gJ:company.yan...

Не укажите на мои ошибки в рассуждениях?

Вопрос 1

Перепишите код, устранив имеющиеся в нём проблемы, но не изменяя функцию main

class Foo {
 public:
  Foo(int j) { i = new int[j]; }
  ~Foo() { delete i; }

 private:
  int* i;
};

class Bar: Foo {
 public:
  Bar(int j) { i = new char[j]; }
  ~Bar() { delete i; }

 private:
  char* i;
};

void main() {
  Foo* f = new Foo(100);
  Foo* b = new Bar(200);
  *f = *b;
  delete f;
  delete b;
}

Здесь, я, как поняла, деструкторы должны быть виртуальными, должен быть описан оператор присваивания, а так же необходимо поле хранящее количество элементов, чтобы при копировании знать, какой длины массив? Или я что-то упустила?

Вопрос 2

В каких из следующих стандартных контейнеров худшее время поиска элемента по значению — O(log(n))?

 std::vector
 std::list
 std::deque
 std::set
 std::multiset
 std::unordered_set
 std::unordered_multiset
 сортированный std::vector
 сортированный std::list
 сортированный std::deque

Тут у меня совсем беда. Посоветуйте какое-нибудь чтиво на русском, из которого можно будет узнать особенности контейнеров и способ организации хранения данных, скорость выполнения тех или иных операций.

Вопрос 3

Напишите код, преобразующий 32-битное целочисленное представление ip-адреса в строковое.

Догадываюсь, что что-то нужно куда-то сдвигать =)

Вопрос 4

Есть класс Bar, предназначенный для работы в многопоточной среде. Перечислите проблемы, которые вы видите в его реализации.

class Bar {
 public:
  void Add(int i, double d) {
    Locker auto_lock_d(m_doubles_);
    Locker auto_lock_i(m_integers_);
    integers_.push_back(i);
    doubles_.push_back(d);
  }

  bool Find(int i) {
    Locker auto_lock(m_integers_);
    if (std::find(integers_.begin(), integers_.end(), i) != integers_.end())
      return true;
    else
      return Find(double(i));
  }

  bool Find(double d) {
    Locker auto_lock(m_doubles_);
    return std::find(doubles_.begin(), doubles_.end(), d) != doubles_.end());
  }
    
 private:
  std::vector<int> integers_;
  std::vector<double> doubles_;
  Mutex m_integers_;
  Mutex m_doubles_;
};

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


Тред не читал, используй оператор delete[] в деструкторе.

UVV ★★★★★
()

Меня терзают смутные сомнения, что среди ЛОРовцев есть работники яндекса :)

lazyklimm ★★★★★
()
Ответ на: комментарий от nerdogeek

Этот метод

void Add(int i, double d) {
    Locker auto_lock_d(m_doubles_);
    Locker auto_lock_i(m_integers_);
    integers_.push_back(i);
    doubles_.push_back(d);
  }

целостности в общем случае не обеспечивает.

anonymous
()

1. Да, деструкторы виртуальные.

3. как-то так printf («%d.%d.%d.%d», ip&(255<<24), ip&(255<<16), ip&(255<<8), ip&(255<<24) )

4. Потоки 1 и 2 одновременно вызывают Add и Find(int). Первый поток блокирует m_doubles_, второй поток блокирует m_integers_. Далее Первый поток ждет m_integers_, а второй если не нашел искомое число в integers ждет m_doubles_, и оба висят в локе.

codeogre
()

Правильно делаешь, написав о себе в женском роде, количество ответов удваивается.

anonymous
()
Ответ на: комментарий от anonymous

Этот метод... целостности в общем случае не обеспечивает.

Почему?

pathfinder ★★★★
()

Напишите код, преобразующий 32-битное целочисленное представление ip-адреса в строковое.

Вот тут ничего не сказано о формате этого целочисленного представления. Но будем считать что у нас эээ... big-endian порядок следования четырех. Ну выразимся так. Первое число адреса самый старший байт адреса.

Я бы написал как-то так:

std::string Ip2String(uint32_t ip_addr)
{
  uint32_t addr1 = (ip_addr >> 24) & 0xff;
  uint32_t addr2 = (ip_addr >> 16) & 0xff;
  uint32_t addr3 = (ip_addr >>  8) & 0xff;
  uint32_t addr4 = ip_addr & 0xff;

  char _buf[20];
  snprintf(_buf,sizeof(buf),"%d.%d.%d.%d",(int)addr1,(int)addr2,(int)addr3,(int)addr4);
  return std::string(_buf);
}

Предполагается, что за скоростью мы тут не гонимся.

pathfinder ★★★★
()
Последнее исправление: pathfinder (всего исправлений: 2)
Ответ на: комментарий от pathfinder

ой, накосячил, правильно наоборот:

printf ("%d.%d.%d.%d", (ip >> 24) &255, (ip >> 16) &255, (ip >> 8) &255, ip&(255) );
не работать мне в яндехе :(

codeogre
()
Ответ на: комментарий от blogdron

№1 - Повнимательней взгляни на i.

И что? переменная i приватная. По моему лучше взглянуть на j. Конструктора по умолчанию уже нет, и в классе Bar при наследовании от Foo в конструкторе Bar надо вызвать конструктор Foo с параметром. Этого в приведенном коде не делается.

Например так:

Bar(int j)
  :Foo(j+100500)
{ 
   i = new char[j]; 
}

pathfinder ★★★★
()

Кажется что во втором вопросе ответ сортированный вектор. Судя по оценке предполагается использовать двоичный поиск.

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

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

PS. С++ почти не знаю

OxiD ★★★★
()
Последнее исправление: OxiD (всего исправлений: 1)

Вопрос 3

Сдвигать не обязательно.

В Си можно как-то так - char * ptr = (char *) &ipv4; printf(«%d.%d.%d.%d\n», ptr[0], ptr[1], ptr[2], ptr[3]);

Хотя на некоторых архитектурах может и не заработать ;)

OxiD ★★★★
()
Ответ на: комментарий от OxiD
uint32_t ip=0xFF00FF00;
char* ptr = (char*)&ip;
printf("%d.%d.%d.%d\n", ptr[0], ptr[1], ptr[2], ptr[3]);

Output:

0.-1.0.-1
Но это я придираюсь.

pathfinder ★★★★
()
Последнее исправление: pathfinder (всего исправлений: 2)

1. Заменить int* на std::vector<int>, в Foo сделать виртуальный деструктор, но пустой, в Bar удалить деструктор, открыто унаследовать Bar от Foo, вызвать деструктор Foo из Bar.

Begemoth ★★★★★
()
Последнее исправление: Begemoth (всего исправлений: 2)
Ответ на: комментарий от ttnl

Правильно? Лучше объявить несколько указателей в отдельных инструкциях (statements), чем уродовать код из-за идиотичности синтаксиса C, особенно с учетом того, что голый указатель должен быть довольно редкой штукой в программе.

Begemoth ★★★★★
()
Последнее исправление: Begemoth (всего исправлений: 1)

по второму вопросы - смотриш сырцы STL и эта морфируеш да

qulinxao ★★☆
()
Ответ на: комментарий от Begemoth

Прочитал этот пост и все посты выше и пришел к выводу, что никого из нас не возьмут в Яндекс.

pathfinder ★★★★
()
Ответ на: комментарий от nerdogeek

По четвёртом: вектор вместо сета, а что ещё?

unC0Rr ★★★★★
()
  void Add(int i, double d) {
    Locker auto_lock_d(m_doubles_);
    doubles_.push_back(d);
    Locker auto_lock_i(m_integers_);
    integers_.push_back(i);
  }
// в таком случае параллельный вызов Add и Find(int) приведет к тому,
// что пока в m_doubles_ будет вставляться очередной элемент,
// поиск завершится без ожидания лока для m_integers_ (в случае когда std::find(integers_) выполнится успешно)

А вообще можно std::vector< std::pair<int, double> >, тогда нужен 1 примитив синхронизации.
Также можно воспользоваться RW Lock.

nerdogeek
()

Переписал код, хрен знает что там за проблемы в нём решали, но не изменил функцию main.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

class Bar;

class Foo 
{
 public:
  Foo()
  {
    i = 0; 
  };

  Foo(int j) 
  { 
    i = new int[j]; 
    strcpy((char*)i,(const char *)"foo\n");
  }
  
 ~Foo() 
 { 
  if(i) delete (char*)i; 
  i=0;
 }


 void print()
 {
  printf("%d %d %s",(int)this,(int)i,(char*)i);
 }

 Foo &operator=(const Foo & val)
 {
   if(&val!=this)
   {
    strcpy((char*)i,(const char *)val.i);
   }
 }
 void set_pointer(void * p)
 {
  i=p;
 }
 private:
  void * i;
};

//------------------------

class Bar : public Foo
{
 public:

  Bar(int j) 
  { 
    char * p = new char[j]; 
    strcpy((char*)p,(const char *)"fbar\n");
    set_pointer(p);
  }

};

//------------------------

int main() 
{
  Foo* f = new Foo(100);
  Foo* b = new Bar(200);
  
  f->print();
  b->print();
  printf("*\n");
   *f=*b;
  f->print();
  b->print();

  delete f;
  delete b;
  return 0;
}
ilovewindows ★★★★★
()
Последнее исправление: ilovewindows (всего исправлений: 1)

по 4-му обычный лок.

зашли в Add, создали auto_lock_d, но пока нету auto_lock_i
в тоже время ищем Find(int) из которого завём Find(double), то есть есть auto_lock_i, но нету auto_lock_d.
Будут ждать друг дружку до посинения.

2 вопрос с позиции догадайся чего от тебя хотят.
Надо сначала выкинуть те алгоритмы которые не O(log(n)), оставшиеся потрошить на время и найти наихудший по времени.
Тут надо смотреть, но думаю, что std::unordered_multiset

1. виртуальный деструктор и удаление массива.

3. можно обычный сдвиг с маской, а можно чтоб сдвигал компайлер (unionn).

union IP {
    unsigned int ip;
    struct {
      unsigned char d;
      unsigned char c;
      unsigned char b;
      unsigned char a;
    } ip2;
};


https://www.google.ru/search?q=integer ip to string&ie=utf-8&oe=utf-8...
Первая ссылка http://stackoverflow.com/questions/1680365/integer-to-ip-address-c там масса вариантов

vtVitus ★★★★★
()
Последнее исправление: vtVitus (всего исправлений: 2)

Здесь, я, как поняла, деструкторы должны быть виртуальными, должен быть описан оператор присваивания, а так же необходимо поле хранящее количество элементов, чтобы при копировании знать, какой длины массив? Или я что-то упустила?

Т.е. тебя не пугает, что

*f = *b;

даннйо операцией ты потеряешь

Foo(100);

а на этом этапе

delete b;

вообще будет core dumped ? Экстрималка, че :3

Тут у меня совсем беда

Страуструп.

Напишите код, преобразующий 32-битное целочисленное представление ip-адреса в строковое.
Догадываюсь, что что-то нужно куда-то сдвигать =)

Либо я не понял задание, либо можно обойтись ostringstream (C++ же!)

Вопрос 4

Лень парсить все (ночь же),так что сейчас подойду креативно: тут не нужен class, обойдемся struct :).
//Люблю девушек-программистов С++: вы такие няши :3

comp00 ★★★★
()

Или я что-то упустила?

такие задания рассчитаны на то чтобы на то чтобы оценить уровень знаний... по этому лучше писать по максимуму что найдёшь.

Посоветуйте какое-нибудь чтиво на русском

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

Догадываюсь, что что-то нужно куда-то сдвигать

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

Разработчик Яндекс.Браузера

что-то дико знакомое но одновременно безнадёжно далёкое.

mm3 ★★★
()
Ответ на: комментарий от Begemoth

Правильно? Лучше объявить несколько указателей в отдельных инструкциях (statements), чем уродовать код из-за идиотичности синтаксиса C, особенно с учетом того, что голый указатель должен быть довольно редкой штукой в программе.

Конечно, правильно — так, как я сказал. Звездочка имеет отношение к переменной, а не к типу.

Язык Си придумали ни разу не идиоты. Стыдно так говорить

ttnl ★★★★★
()
Ответ на: комментарий от ttnl

Звездочка имеет отношение к переменной, а не к типу.

Я знаю, но это кривость синтаксиса С.

Язык Си придумали ни разу не идиоты.

Это не значит, что там нет кривых вещей, синтаксис типов - из наиболее ярких оставшихся. Ещё можно вспомнить неявное объявление функций в K&R C.

Стыдно так говорить

Стыдно некритически относиться к чему-либо.

Begemoth ★★★★★
()
Ответ на: комментарий от ttnl

Язык Си придумали ни разу не идиоты. Стыдно так говорить

Вот только не надо вбрасывать. Реалии нашей жизни таковы, что идиотом можно назвать любого, а потом это ещё и аргументированно доказать.

Синтаксис как с++, так и си не является верхом совершенства. Неудачных или сомнительных идей хватает. Как впрочем и во всех других языках.

pathfinder ★★★★
()
Ответ на: комментарий от vtVitus

3. можно обычный сдвиг с маской, а можно чтоб сдвигал компайлер (unionn).

union IP {
    unsigned int ip;
    struct {
      unsigned char d;
      unsigned char c;
      unsigned char b;
      unsigned char a;
    } ip2;
};

В условии задания работаем с 32-битным числом. Какова разрядность unsigned int? У тебя есть уверенность, что выравнивание в структуре ip2 будет таким, как ты хочешь?

pathfinder ★★★★
()
Ответ на: комментарий от Begemoth

вызвать деструктор Foo из Bar

вон из профессии!

anonymous
()
Ответ на: комментарий от Begemoth

Я знаю, но это кривость синтаксиса С.

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

Стыдно некритически относиться к чему-либо.

Одно дело — относиться критически, другое — говорить в столь оскорбительном гонзо-программистском стиле. Язык Си придумали не идиоты, повторяю тебе еще раз, и каждую конструкцию синтакса они досконально продумывали. Удобство в одних случаях приводит к неудобству в других. Керниган и Ритчи выбрали возможность объявлять в одной строке объект и указатель на него. Как программист со стажем, говорю, что это действительно удобная функция.

ttnl ★★★★★
()
Ответ на: комментарий от pathfinder

Реалии нашей жизни таковы, что идиотом можно назвать любого, а потом это ещё и аргументированно доказать.

Сначала надо доказать.

ttnl ★★★★★
()
Ответ на: комментарий от UVV

Молодец, возьми с полки пирожок

Спасибо

ttnl ★★★★★
()
Ответ на: комментарий от ttnl

Язык си придумали не идиоты, а всего лишь люди, имеющие слабое понятие о проектировании языков. Иначе не объяснить кошмар, который там творится в некоторых местах, особенно если вспомнить K&R C. В частности, удобства в объявлении

int a, *b, c[1], f(void)
ну вообще никакого.

unsigned ★★★★
()
Ответ на: комментарий от unsigned

int a, *b, c[1], f(void)

Что конкретно тебе кажется неудобным?

а всего лишь люди, имеющие слабое понятие о проектировании языков

Извини, они забыли спросить твое мнение, когда придумывали.

ttnl ★★★★★
()
Последнее исправление: ttnl (всего исправлений: 1)
Ответ на: комментарий от ttnl

Что конкретно тебе кажется неудобным?

Объявлять переменные и функции разных типов в одном объявлении? Ты шутишь?

они забыли спросить твое мнение, когда придумывали.

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

unsigned ★★★★
()
Ответ на: комментарий от pathfinder

Приведи пример реальной платформы и компилятора, когда приведённая структура не будет работать, мы тогда обсудим, а так пока все твои вопросы трололо.

vtVitus ★★★★★
()
Ответ на: комментарий от unsigned

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

Язык си придумали люди, которым нужен был кроссплатформенный ассемблер. Они его придумали и оно живет и здравствует, и переживет многие популярные ныне языки, так как является примером грамотного проектирования.

vtVitus ★★★★★
()
Ответ на: комментарий от vtVitus

Приведи пример реальной платформы и компилятора

Вроде как в ARM по умолчанию компилятор выравнивает все поля на границу 4 байт. Хотя я так хорошо различные платформы не знаю. Я просто знаю, что есть такая штука как выравнивание, и она отдается на усмотрение компилятора. Как он там выравнивает поля, одному компилятору известно.

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

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

Под армом это должно работать.

в общем виде ты прав, но так никто не делает в риал лайф :).

по-моему это везде будет работать, но 100% не гарантирую, как и всё в программировании, особенно для столь низкоуровневых языков.

vtVitus ★★★★★
()
Ответ на: комментарий от vtVitus

Си живет и будет жить только благодаря легаси. Да, что-то в нем сделано хорошо, но многое можно было сделать намного лучше. И это ничего не стоило, что особенно обидно.

unsigned ★★★★
()
Ответ на: комментарий от unsigned

Фиг вам, для любой новой аппаратной платформы в первую очередь переносится именно Cи или его урезанный аналог. Да и сейчас на си пишется много НОВОГО софта который без проблем можно написать на чём угодно. Я не говорю что Си это единственно правильное решение для всего, а имею в виду что он тупо универсален и реально подойдёт для чего угодно, в том его и прелесть. А минусы, минусы есть у любого языка.

blogdron
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.