План v2 по диагностике (квиз 14/32) + 4 новые задачи (hash, heap, dijkstra, subnet) + тренажёр 60 карточек
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
// Задача 13 — арифметика подсетей IPv4.
|
||||
// Реализуй функции ниже. Заглушка намеренно не проходит проверку.
|
||||
#include <cstdint>
|
||||
|
||||
struct Subnet {
|
||||
uint32_t network = 0;
|
||||
uint32_t broadcast = 0;
|
||||
uint32_t first_host = 0;
|
||||
uint32_t last_host = 0;
|
||||
long long host_count = 0;
|
||||
};
|
||||
|
||||
Subnet subnet_of(uint32_t ip, int prefix) {
|
||||
(void)ip;
|
||||
(void)prefix;
|
||||
return Subnet{};
|
||||
}
|
||||
|
||||
bool same_subnet(uint32_t a, uint32_t b, int prefix) {
|
||||
(void)a;
|
||||
(void)b;
|
||||
(void)prefix;
|
||||
return false;
|
||||
}
|
||||
|
||||
int prefix_for_hosts(int hosts) {
|
||||
(void)hosts;
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Задача 13 — арифметика подсетей IPv4 (C++)
|
||||
|
||||
Адреса передаются в **host byte order** (`0x0A000001` = 10.0.0.1), маска — длиной префикса.
|
||||
|
||||
```c++
|
||||
struct Subnet {
|
||||
uint32_t network; // адрес сети
|
||||
uint32_t broadcast; // широковещательный адрес
|
||||
uint32_t first_host; // первый адрес для узла
|
||||
uint32_t last_host; // последний адрес для узла
|
||||
long long host_count; // сколько адресов узлов доступно (для /0 не влезает в int)
|
||||
};
|
||||
|
||||
Subnet subnet_of(uint32_t ip, int prefix); // 0 <= prefix <= 32
|
||||
bool same_subnet(uint32_t a, uint32_t b, int prefix);
|
||||
int prefix_for_hosts(int hosts); // самая узкая подсеть, куда влезает hosts
|
||||
```
|
||||
|
||||
Определения, которые нужно соблюсти:
|
||||
- для `prefix <= 30`: `host_count = 2^(32-prefix) - 2`, `first_host = network + 1`,
|
||||
`last_host = broadcast - 1`;
|
||||
- `/31` (RFC 3021): `host_count = 2`, `first_host = network`, `last_host = broadcast`;
|
||||
- `/32`: `host_count = 1`, `first_host = last_host = network = broadcast = ip`;
|
||||
- `prefix_for_hosts(h)`: **наибольший** `prefix` из диапазона `0..30` (то есть самая узкая
|
||||
подсеть), при котором `host_count >= h`. `h < 1` или `h > 2^32-2` → `-1`.
|
||||
Исключения `/31` и `/32` в подборе не участвуют — они для линков и одиночных адресов.
|
||||
|
||||
Эталонные примеры, которые обязаны сойтись: `/26` → 62 узла; `/24` → 254; `/30` → 2;
|
||||
`10.0.1.130/26` → сеть `10.0.1.128`, broadcast `10.0.1.191`, узлы `129..190`;
|
||||
`prefix_for_hosts(62)` → 26, `prefix_for_hosts(63)` → 25, `prefix_for_hosts(254)` → 24,
|
||||
`prefix_for_hosts(1)` → 30.
|
||||
|
||||
Проверка: `python3 grade.py 13`. Критерий: все `ok`, сборка без предупреждений.
|
||||
|
||||
Разбор после сдачи: как считать префикс по числу узлов за O(1) (`32 - ceil(log2(h+2))`),
|
||||
почему `/31` — исключение, что такое маска в бинарном виде.
|
||||
@@ -0,0 +1,66 @@
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
#include "solution.cpp"
|
||||
|
||||
static int failures = 0;
|
||||
#define CHECK(cond, name) do { if (cond) std::printf("ok %s\n", name); \
|
||||
else { std::printf("FAIL %s (line %d)\n", name, __LINE__); ++failures; } } while (0)
|
||||
|
||||
static uint32_t ip4(int a, int b, int c, int d) {
|
||||
return (uint32_t(a) << 24) | (uint32_t(b) << 16) | (uint32_t(c) << 8) | uint32_t(d);
|
||||
}
|
||||
|
||||
int main() {
|
||||
{
|
||||
Subnet s = subnet_of(ip4(10, 0, 1, 130), 26);
|
||||
CHECK(s.network == ip4(10, 0, 1, 128), "/26: адрес сети 10.0.1.128");
|
||||
CHECK(s.broadcast == ip4(10, 0, 1, 191), "/26: broadcast 10.0.1.191");
|
||||
CHECK(s.first_host == ip4(10, 0, 1, 129), "/26: первый узел 10.0.1.129");
|
||||
CHECK(s.last_host == ip4(10, 0, 1, 190), "/26: последний узел 10.0.1.190");
|
||||
CHECK(s.host_count == 62, "/26: 62 узла (не 64)");
|
||||
}
|
||||
{
|
||||
Subnet s = subnet_of(ip4(192, 168, 5, 200), 24);
|
||||
CHECK(s.network == ip4(192, 168, 5, 0), "/24: сеть 192.168.5.0");
|
||||
CHECK(s.broadcast == ip4(192, 168, 5, 255), "/24: broadcast 192.168.5.255");
|
||||
CHECK(s.host_count == 254, "/24: 254 узла");
|
||||
Subnet t = subnet_of(ip4(172, 16, 4, 9), 30);
|
||||
CHECK(t.network == ip4(172, 16, 4, 8) && t.broadcast == ip4(172, 16, 4, 11),
|
||||
"/30: сеть 172.16.4.8, broadcast 172.16.4.11");
|
||||
CHECK(t.host_count == 2 && t.first_host == ip4(172, 16, 4, 9) && t.last_host == ip4(172, 16, 4, 10),
|
||||
"/30: 2 узла, 9 и 10");
|
||||
Subnet z = subnet_of(ip4(10, 0, 0, 5), 32);
|
||||
CHECK(z.network == ip4(10, 0, 0, 5) && z.broadcast == ip4(10, 0, 0, 5) && z.host_count == 1,
|
||||
"/32: один адрес, сеть == broadcast == узел");
|
||||
Subnet p31 = subnet_of(ip4(10, 0, 0, 1), 31);
|
||||
CHECK(p31.host_count == 2 && p31.first_host == ip4(10, 0, 0, 0) && p31.last_host == ip4(10, 0, 0, 1),
|
||||
"/31: RFC 3021 — 2 узла без вычета");
|
||||
Subnet eight = subnet_of(ip4(10, 200, 30, 40), 8);
|
||||
CHECK(eight.network == ip4(10, 0, 0, 0) && eight.broadcast == ip4(10, 255, 255, 255),
|
||||
"/8: сеть 10.0.0.0, broadcast 10.255.255.255");
|
||||
Subnet zero = subnet_of(ip4(8, 8, 8, 8), 0);
|
||||
CHECK(zero.network == 0 && zero.broadcast == 0xFFFFFFFFu && zero.host_count == 4294967294LL,
|
||||
"/0: вся сеть, узлов 2^32-2");
|
||||
}
|
||||
{
|
||||
CHECK(same_subnet(ip4(10, 0, 1, 130), ip4(10, 0, 1, 150), 26), "/26: 130 и 150 в одной подсети");
|
||||
CHECK(!same_subnet(ip4(10, 0, 1, 130), ip4(10, 0, 1, 200), 26), "/26: 130 и 200 — разные подсети");
|
||||
CHECK(!same_subnet(ip4(10, 0, 1, 130), ip4(10, 0, 1, 127), 26), "/26: 130 и 127 — разные подсети");
|
||||
CHECK(same_subnet(ip4(10, 0, 1, 1), ip4(10, 0, 2, 1), 16), "/16: разные третьи октеты — одна сеть");
|
||||
CHECK(!same_subnet(ip4(10, 0, 1, 1), ip4(10, 1, 1, 1), 16), "/16: 10.0.x и 10.1.x — разные");
|
||||
CHECK(same_subnet(ip4(10, 0, 0, 0), ip4(10, 0, 0, 1), 31), "/31: соседи по RFC 3021");
|
||||
}
|
||||
{
|
||||
CHECK(prefix_for_hosts(62) == 26, "prefix_for_hosts(62) -> 26");
|
||||
CHECK(prefix_for_hosts(63) == 25, "prefix_for_hosts(63) -> 25 (63 в /26 не влезает)");
|
||||
CHECK(prefix_for_hosts(254) == 24, "prefix_for_hosts(254) -> 24");
|
||||
CHECK(prefix_for_hosts(255) == 23, "prefix_for_hosts(255) -> 23");
|
||||
CHECK(prefix_for_hosts(2) == 30, "prefix_for_hosts(2) -> 30");
|
||||
CHECK(prefix_for_hosts(1) == 30, "prefix_for_hosts(1) -> 30 (узкая подсеть общего вида)");
|
||||
CHECK(prefix_for_hosts(0) == -1, "prefix_for_hosts(0) -> -1");
|
||||
CHECK(prefix_for_hosts(4294967295) == -1, "prefix_for_hosts(2^32-1) -> -1 (не влезает)");
|
||||
CHECK(prefix_for_hosts(1000000) == 12, "prefix_for_hosts(1000000) -> 12");
|
||||
}
|
||||
std::printf(failures ? "\nFAILURES: %d\n" : "\nALL PASS\n", failures);
|
||||
return failures ? 1 : 0;
|
||||
}
|
||||
Reference in New Issue
Block a user