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

✉️ Email: [email protected]
📲 Telegram канал: https://t.me/zer0kernelorg
💰 Donate (BTC): bc1qwvrgka76eeley8feqdxjxk2866sv0tnweylxjc
to[], weight[], next_edge[] и массивом голов head[]. Каждое ребро получает индекс, а head[v] указывает на первое ребро, исходящее из вершины v. Следующее ребро того же источника находится через next_edge[]. Такой формат не требует динамических списков и экономит память.#include <stdio.h>
#include <limits.h>
#define MAX_V 10000
#define MAX_E 100000
#define INF INT_MAX
int head[MAX_V];
int to[MAX_E];
int weight[MAX_E];
int next_edge[MAX_E];
int edge_count;
void init_graph(int n) {
for (int i = 0; i < n; i++)
head[i] = -1;
edge_count = 0;
}
void add_edge(int u, int v, int w) {
to[edge_count] = v;
weight[edge_count] = w;
next_edge[edge_count] = head[u];
head[u] = edge_count++;
}
add_edge(u, v, w) и add_edge(v, u, w).heap_push и heap_pop работают за O(log k), где k — текущий размер кучи. Вместо операции decrease-key используется ленивое удаление: при релаксации в кучу добавляется новая запись, а устаревшие записи отбрасываются при извлечении.typedef struct {
int dist;
int vertex;
} HeapNode;
HeapNode heap[MAX_E + 1];
int heap_size;
void heap_push(int dist, int vertex) {
int i = heap_size++...
racecar, madam, level. Проверка строки на палиндром — одна из первых задач, где удобно освоить работу с указателями в C. Классический подход — два указателя, сходящихся к центру, — не требует дополнительного буфера и работает за линейное время.#include <stdio.h>
#include <string.h>
int is_palindrome(const char *s)
{
if (s == NULL)
return 0;
size_t len = strlen(s);
if (len <= 1)
return 1;
const char *left = s;
const char *right = s + len - 1;
while (left < right) {
if (*left != *right)
return 0;
left++;
right--;
}
return 1;
}
int main(void)
{
const char *tests[] = {"racecar", "hello", "madam", "a", "", "abba"};
size_t n = sizeof(tests) / sizeof(tests[0]);
for (size_t i = 0; i < n; i++) {
printf("%-10s -> %s\n", tests[i],
is_palindrome(tests[i]) ? "palindrome" : "not palindrome");
}
return 0;
}
racecar -> palindrome
hello -> not palindrome
madam -> palindrome
a -> palindrome
-> palindrome
abba -> palindrome
"abba" (длина 4)...#include <stdio.h>
int fib_iter(int n) {
if (n < 0) return -1;
int a = 0, b = 1;
for (int i = 0; i < n; i++) {
int tmp = a + b;
a = b;
b = tmp;
}
return a;
}
int main(void) {
for (int i = 0; i <= 10; i++) {
printf("F(%d) = %d\n", i, fib_iter(i));
}
return 0;
}
F(0) = 0
F(1) = 1
F(2) = 1
F(3) = 2
F(4) = 3
F(5) = 5
F(6) = 8
F(7) = 13
F(8) = 21
F(9) = 34
F(10) = 55
a на каждой итерации сдвигается вперёд: после n итераций a содержит F(n). Это подтверждается и в cp-algorithms.com: линейное решение с O(1) дополнительной памяти.#include <stdio.h>
int fib_rec(int n) {
if (n <= 0) return 0;
if (n == 1) return 1;
return fib_rec(n - 1) + fib_rec(n - 2);
}
int main(void) {
printf("F(10) = %d\n", fib_rec(10));
return 0;
}
fib_rec(5) выглядит так:fib(5)
├── fib(4)
│ ├── fib(3)
│ │ ├── fib(2)
│ │ │ ├── fib(1)
│ │ │ └── fib(0)
│ │ └── fib(1)
│ └── fib(2)
│ ├── fib(1)
│ └── fib(0)
└── fib(3)
├── fib(2)
│ ├── fib(1)
│ └── fib(0)
└── fib(1)
fib(3) вычисляется дважды, fib(2) — трижды. В общем случае количество вызовов растёт...gcd(a, b) = gcd(b, a mod b)
#include <stdio.h>
int gcd_recursive(int a, int b) {
if (b == 0)
return a;
return gcd_recursive(b, a % b);
}
int main(void) {
printf("gcd(48, 18) = %d\n", gcd_recursive(48, 18));
printf("gcd(7, 13) = %d\n", gcd_recursive(7, 13));
printf("gcd(0, 5) = %d\n", gcd_recursive(0, 5));
return 0;
}
gcd(48, 18) = 6
gcd(7, 13) = 1
gcd(0, 5) = 5
a[0] и растёт на каждом шаге.a[i] (называется ключ).k итераций первые k + 1 элементов гарантированно отсортированы.#include <stdio.h>
void insertion_sort(int a[], int n)
{
for (int i = 1; i < n; i++) {
int key = a[i];
int j = i - 1;
/* Сдвигаем элементы, большие key, на одну позицию вправо */
while (j >= 0 && a[j] > key) {
a[j + 1] = a[j];
j--;
}
/* Вставляем key в найденную позицию */
a[j + 1] = key;
}
}
void print_array(const int a[], int n)
{
for (int i = 0; i < n; i++) {
printf("%d", a[i]);
if (i < n - 1) printf(", ");
}
printf("\n");
}
int main(void)
{
int arr[] = {3, 7, 4, 9, 5, 2, 6, 1};
int n = sizeof(arr) / sizeof(arr[0]);
printf("До сортировки: ");
print_array(arr, n);
insertion_sort(arr, n);
printf("После сортировки: ");
print_array(arr, n);
return 0;
}
До сортировки: 3, 7, 4, 9, 5, 2, 6, 1
После сортировки: 1, 2, 3, 4, 5, 6, 7, 9
{3, 7, 4, 9, 5, 2, 6, 1}.{64, 25, 12, 22, 11}:Исходный: 64 25 12 22 11
Шаг 1: 11 25 12 22 64 ← минимум 11 обменян с 64
Шаг 2: 11 12 25 22 64 ← минимум 12 обменян с 25
Шаг 3: 11 12 22 25 64 ← минимум 22 обменян с 25
Шаг 4: 11 12 22 25 64 ← 25 уже на месте, обмен не нужен
n - 1 раз.#include <stdio.h>
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void selection_sort(int arr[], int n)
{
for (int i = 0; i < n - 1; i++) {
int min_idx = i;
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[min_idx]) {
min_idx = j;
}
}
if (min_idx != i) {
swap(&arr[i], &arr[min_idx]);
}
}
}
void print_array(const int arr[], int n)
{
for (int i = 0; i < n; i++) {
printf("%d", arr[i]);
if (i < n - 1) printf(", ");
}
printf("\n");
}
int main(void)
{
int arr[] = {64, 25, 12, 22, 11};
int n = sizeof(arr) / sizeof(arr[0]);
printf("До сортировки: ");
print_array(arr, n);
selection_sort(arr, n);
printf("После сортировки: ");
print_array(arr, n);
return 0;
}
gcc -Wall -Wextra -o selection_sort selection_sort.c
./selection_sort
До сортировки: 64, 25, 12, 22, 11
После...
#include <stdio.h>
void bubble_sort(int arr[], int n)
{
int swapped;
do {
swapped = 0;
for (int i = 0; i < n - 1; i++) {
if (arr[i] > arr[i + 1]) {
int tmp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = tmp;
swapped = 1;
}
}
} while (swapped);
}
int main(void)
{
int arr[] = {5, 1, 4, 2, 8};
int n = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, n);
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
1 2 4 5 8
swapped позволяет завершить работу досрочно: если за проход не было ни одного обмена, массив уже отсортирован и дальнейшие итерации бессмысленны.{5, 1, 4, 2, 8} и проследим каждый проход.| Сравнение | Массив после обмена |
|---|---|
| 5 > 1 → обмен | {1, 5, 4, 2, 8} |
| 5 > 4 → обмен | {1, 4, 5, 2, 8} |
| 5 > 2 → обмен | {1, 4, 2, 5, 8} |
| 5 < 8 → без обмена | {1, 4, 2, 5, 8} |
| Сравнение | Массив после обмена |
|---|---|
| 1... |
#include <stdio.h>
int count_occurrences(const int *arr, size_t n, int target)
{
int count = 0;
for (size_t i = 0; i < n; i++) {
if (arr[i] == target) {
count++;
}
}
return count;
}
int main(void)
{
int data[] = {3, 7, 2, 7, 1, 7, 4, 7};
size_t len = sizeof(data) / sizeof(data[0]);
int target = 7;
int result = count_occurrences(data, len, target);
printf("Элемент %d встречается %d раз(а)\n", target, result);
return 0;
}
Элемент 7 встречается 4 раз(а)
sizeof(arr) вернёт размер указателя, а не размер массива. Поэтому размер всегда передаётся отдельным параметром./* arr внутри функции — это указатель, не массив */
int count_occurrences(const int *arr, size_t n, int target)
const в сигнатуре гарантирует, что функция не модифицирует исходные данные. Это не влияет на...n элементов выполняется ровно n / 2 обменов (целочисленное деление). Средний элемент при нечётной длине остаётся на месте — его менять не с чем.#include <stdio.h>
void reverse_array(int *arr, size_t n)
{
if (n < 2)
return;
size_t left = 0;
size_t right = n - 1;
while (left < right) {
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
int main(void)
{
int arr[] = {1, 2, 3, 4, 5, 6, 7};
size_t n = sizeof(arr) / sizeof(arr[0]);
printf("До: ");
for (size_t i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
reverse_array(arr, n);
printf("После: ");
for (size_t i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
До: 1 2 3 4 5 6 7
После: 7 6 5 4 3 2 1
{1, 2, 3, 4, 5} (n = 5):| Шаг | left | right | Обмен | Состояние массива |
|---|---|---|---|---|
| 0 | 0 | 4 | arr[0] ↔ arr[4] | {5, 2, 3, 4, 1} |
| 1 | 1 | 3 | arr[1] ↔ arr[3] | {5, 4, 3, 2, 1} |
| 2 | 2 | 2 | left == right, стоп | {5, 4, 3, 2, 1} |
{1, 2, 3, 4} (n = 4):| Шаг | left | right | Обмен | Состояние массива |
|---|---|---|---|---|
| 0 | 0 | 3 | arr[0] ↔ arr[3] | {4, 2, 3, 1} |
| 1 | 1 | 2 | ... |
#include <stdio.h>
/*
* Возвращает индекс первого вхождения target в массив arr
* длины n. Если элемент не найден, возвращает -1.
*/
int linear_search(const int *arr, int n, int target)
{
for (int i = 0; i < n; i++) {
if (arr[i] == target) {
return i;
}
}
return -1;
}
int main(void)
{
int data[] = {4, 2, 7, 1, 9, 3};
int n = (int)(sizeof(data) / sizeof(data[0]));
int result = linear_search(data, n, 7);
if (result != -1) {
printf("Элемент найден на позиции %d\n", result);
} else {
printf("Элемент не найден\n");
}
return 0;
}
Элемент найден на позиции 2
for проходит от индекса 0 до n - 1.arr[i] сравнивается с target.-1 — сигнал «не найдено».-1 безопасен, потому что в C индексы массива всегда неотрицательны. Это общепринятое соглашение для функций поиска.