Загрузка данных


import time
import random
from tabulate import tabulate


def bubble_sort(arr):
    """Сортировка пузырьком"""
    a = arr.copy()
    n = len(a)
    for i in range(n):
        swapped = False
        for j in range(0, n - i - 1):
            if a[j] > a[j + 1]:
                a[j], a[j + 1] = a[j + 1], a[j]
                swapped = True
        if not swapped:
            break
    return a


def merge_sort(arr):
    """Сортировка слиянием"""
    if len(arr) <= 1:
        return arr
    mid = len(arr) // 2
    left = merge_sort(arr[:mid])
    right = merge_sort(arr[mid:])
    return merge(left, right)


def merge(left, right):
    result = []
    i = j = 0
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    result.extend(left[i:])
    result.extend(right[j:])
    return result


def read_array_from_file(filename):
    """Чтение массива из файла (числа через пробел/запятую/с новой строки)"""
    with open(filename, 'r', encoding='utf-8') as f:
        content = f.read().replace(',', ' ').split()
        return [int(x) for x in content]


def get_input_array():
    """Получение массива от пользователя"""
    print("\nВыберите способ ввода:")
    print("1 - Ввести вручную")
    print("2 - Загрузить из файла")
    print("3 - Сгенерировать случайный массив")
    choice = input("Ваш выбор: ").strip()

    if choice == '1':
        data = input("Введите числа через пробел: ")
        return [int(x) for x in data.split()]
    elif choice == '2':
        filename = input("Имя файла: ").strip()
        return read_array_from_file(filename)
    elif choice == '3':
        n = int(input("Размер массива: "))
        return [random.randint(-1000, 1000) for _ in range(n)]
    else:
        print("Неверный выбор. Использую случайный массив из 100 элементов.")
        return [random.randint(-1000, 1000) for _ in range(100)]


def benchmark(arr, repeats=3):
    """Замер времени работы обеих сортировок"""
    # Проверка корректности
    assert bubble_sort(arr) == merge_sort(arr) == sorted(arr), "Ошибка сортировки!"

    # Bubble sort
    bubble_times = []
    for _ in range(repeats):
        start = time.perf_counter()
        bubble_sort(arr)
        bubble_times.append(time.perf_counter() - start)

    # Merge sort
    merge_times = []
    for _ in range(repeats):
        start = time.perf_counter()
        merge_sort(arr)
        merge_times.append(time.perf_counter() - start)

    return {
        'bubble_avg': sum(bubble_times) / repeats,
        'merge_avg': sum(merge_times) / repeats,
        'bubble_min': min(bubble_times),
        'merge_min': min(merge_times),
    }


def print_table(results, n):
    """Вывод результатов в виде таблицы"""
    headers = ["Алгоритм", "Среднее время (с)", "Мин. время (с)", "Сложность (сред.)", "Сложность (худш.)"]

    table = [
        ["Пузырьковая", f"{results['bubble_avg']:.6f}",
         f"{results['bubble_min']:.6f}", "O(n²)", "O(n²)"],
        ["Слиянием", f"{results['merge_avg']:.6f}",
         f"{results['merge_min']:.6f}", "O(n log n)", "O(n log n)"],
    ]

    print(f"\n{'=' * 70}")
    print(f"  Сравнение сортировок для массива из {n} элементов")
    print(f"{'=' * 70}")
    print(tabulate(table, headers=headers, tablefmt="grid"))

    # Ускорение
    if results['merge_avg'] > 0:
        speedup = results['bubble_avg'] / results['merge_avg']
        print(f"\nСортировка слиянием быстрее в {speedup:.2f} раз(а)")

    # Оценка теоретической сложности
    n2 = n * n
    nlogn = n * (n.bit_length())  # ~n log n
    print(f"\nТеоретическое соотношение (n² / n·log₂n) ≈ {n2 / nlogn:.1f}")
    print(f"Практическое соотношение (bubble / merge)    ≈ "
          f"{results['bubble_avg'] / results['merge_avg']:.1f}")


def compare_different_sizes():
    """Сравнение на массивах разного размера"""
    print("\n--- Сравнение на массивах разного размера ---")
    sizes = [100, 500, 1000, 2000, 5000]
    headers = ["Размер", "Пузырьковая (с)", "Слиянием (с)", "Отношение"]
    table = []

    for n in sizes:
        arr = [random.randint(-10000, 10000) for _ in range(n)]
        res = benchmark(arr, repeats=2)
        ratio = res['bubble_avg'] / res['merge_avg'] if res['merge_avg'] > 0 else float('inf')
        table.append([
            n,
            f"{res['bubble_avg']:.6f}",
            f"{res['merge_avg']:.6f}",
            f"{ratio:.1f}x"
        ])

    print(tabulate(table, headers=headers, tablefmt="grid"))


def main():
    print("=" * 70)
    print(" СРАВНЕНИЕ ЭФФЕКТИВНОСТИ СОРТИРОВОК: ПУЗЫРЬКОМ vs СЛИЯНИЕМ")
    print("=" * 70)

    while True:
        print("\nМеню:")
        print("1 - Сравнить на своём массиве (ручной ввод / файл / генерация)")
        print("2 - Сравнить на массивах разного размера")
        print("0 - Выход")

        choice = input("Ваш выбор: ").strip()

        if choice == '1':
            arr = get_input_array()
            print(f"\nИсходный массив ({len(arr)} элементов): {arr[:20]}"
                  f"{'...' if len(arr) > 20 else ''}")
            results = benchmark(arr)
            print_table(results, len(arr))

        elif choice == '2':
            compare_different_sizes()

        elif choice == '0':
            print("До свидания!")
            break
        else:
            print("Неверный выбор.")


if __name__ == "__main__":
    main()
pip install tabulate