Cайт программиста Ruby, веб-разработчика Ruby on Rails ESV Corp. Екатеринбург, Москва, Санкт-Петербург, Новосибирск, Первоуральск

Алгоритм сортировки однонаправленного связанного списка путём вставок. Дональд Э. Кнут. Rust

//
// @author ESV Corp. (C) 08.09.2026
//
// "проба пера" на Rust
// алгоритм: "метод вставки в список"
// сортировка однонаправленного связанного списка
// Д. Кнут "Искусство программирования", т.3 "Сортировка и поиск",
// глава 5.2.1, раздел "Вставки в список"
//

const N: usize = 16;

// элемент списка
#[derive(Copy, Clone, Debug)]
struct Node {
    val:  i32,   // значение (оно же ключ)
    next: usize, // указатель на следующий элемент - индекс в массиве
}

fn main() {

    println!("Donald E. Knuth algorithms: sort linked list by inserts");

    // исходный список элементов
    let source: [i32; N] = [5, 3, 2, 7, 1, -5, 10, 4, -3, 0, 12, 6, 7, 9, 11, 8];

    // возможно
    // let mut list = [Node { val: 0, next: 0 }; N + 1];
    // но для наглядности так
    let _empty_node = Node { val: 0, next: 0 };
    // статический линейный список
    let mut list = [_empty_node; N + 1];

    // корень списка - нулевой элемент массива
    list[0].val  = -1000; // некое фиктивное значение или можно хранить дополнительную информацию
    list[0].next = 1;     // указывает на первый элемент списка

    // заполняем ноды в списке
    for i in 0..N {

        // в списке элементы расположены в массиве со смещением +1
        // корень расположен в 0-ом элементе массива
        let l_index = i + 1;

        list[l_index].val  = source[i];
        list[l_index].next = if l_index < N { l_index + 1 } else { 0 };

        #[cfg(debug_assertions)]
        println!("index={l_index} \tval={} \tnext = {:?}", list[l_index].val, list[l_index].next);

    }

    print_list(&list);

    // сортировка
    sort_linked_list_by_inserts(&mut list);

    // ---
    // динамический линейный список - динамический массив
    let mut list: Vec<Node> = vec![];

    // корень списка - нулевой элемент списка
    list.push(Node {val: -1000, next: 1});

    let a_count = 2;           // количество исходных массивов
    let i_last  = N * a_count; // индекс последнего элемента (для сравнения <, а не <=)

    // заполняем динамический список
    // для примера - 2 исходных массива
    for a in 0..a_count {
        for i in 0..N {

            // в списке элементы расположены в массиве со смещением +1
            // корень расположен в 0-ом элементе массива
            let l_index = a * N + i + 1;
            let a = a as i32;
            let val: i32 = source[i] * (a + 1) - a * 2;

            list.push(
                Node {
                    val:  val,
                    next: if l_index < i_last { l_index + 1 } else { 0 }
                }
            );

            #[cfg(debug_assertions)]
            println!("index={l_index} \tval={:4} \tnext = {:?}", list[l_index].val, list[l_index].next);

        }
    }

    print_list(&list);

    // сортировка
    sort_linked_list_by_inserts(&mut list);

}


// ===
// сортировка связанного списка методом вставок
// элементы не перемещаются, но меняются указатели на следующий элемент
fn sort_linked_list_by_inserts(r: &mut [Node]) {

    let n: usize = r.len();

    debug_assert!(n > 2, "sort_linked_list_by_inserts: nothing to sort");

    let n = n - 1;

    #[cfg(debug_assertions)]
    println!("Sort linked list by inserts source: {:?}", r);

    r[0].next = n; // устанавливаем указатель начала списка на последний элемент
    r[n].next = 0; // последний элемент - указывает на корень, что фактически означает,
                   // что он последний - это признак окончания списка, список замкнут, зациклен

    // от предпоследнего элемента списка до первого
    for j in (1..n).rev() {

        let mut q: usize = 0;         // q указывает на корень, а там хранится указатель на первый элемент
        let mut p: usize = r[q].next; // p указывает на первый элемент списка, указанный в корне (q)
                                      // q фактически всегда отстаёт от p на шаг

        let k: i32 = r[j].val; // ключ (значение) элемента для сравнения

        // пока не конец списка и текущий элемент списка r[p] меньше элемента для сравнения
        while p > 0 && r[p].val < k {
            q = p;         // позиция рассмотренного, q отстаёт на шаг
            p = r[p].next; // следующий элемент в списке
        }

        // элемент вставляется перед p, после q
        r[q].next = j;
        r[j].next = p;

    }

    println!("Sort linked list by inserts sorted:");
    print_list(&r);

    #[cfg(debug_assertions)]
    println!("Sort linked list by inserts sorted (debug): {:?}", r);

}


// печать связанного списка
fn print_list(list: &[Node]) {

    let mut i = list[0].next;

    while i > 0 {
        print!("{}{}", list[i].val, if list[i].next == 0 { "\n" } else { ", " });
        i = list[i].next;
    }
}