Сортировка пузырьком (bubble sort) реализует сортировку путем последовательного сравнения и обмена соседних элементов. Этот процесс напоминает всплытие пузырьков снизу вверх, откуда и произошло название алгоритма.
Как показано на рисунке 11-4, процесс «всплытия» можно смоделировать через операцию обмена элементов: начиная от левого края массива и двигаясь вправо, мы последовательно сравниваем соседние элементы и, если «левый элемент > правый элемент», меняем их местами. После завершения прохода максимальный элемент будет перемещен в самый правый конец массива.
1 / 7
Рисунок 11-4 Моделирование пузырька через обмен элементов
Пусть длина массива равна . Тогда шаги сортировки пузырьком показаны на рисунке 11-5.
Сначала выполнить один проход «всплытия» по элементам, переместив максимальный элемент массива на правильную позицию.
Затем выполнить «всплытие» по оставшимся элементам, переместив второй по величине элемент на правильную позицию.
Продолжать по аналогии. После раундов «всплытия» первые по величине элементы окажутся на правильных позициях.
Оставшийся единственный элемент обязательно является минимальным, сортировать его уже не нужно, поэтому сортировка завершена.
Рисунок 11-5 Процесс сортировки пузырьком
Пример кода:
bubble_sort.py
defbubble_sort(nums:list[int]):"""Пузырьковая сортировка"""n=len(nums)# Внешний цикл: неотсортированный диапазон [0, i]foriinrange(n-1,0,-1):# Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецforjinrange(i):ifnums[j]>nums[j+1]:# Поменять местами nums[j] и nums[j + 1]nums[j],nums[j+1]=nums[j+1],nums[j]
bubble_sort.cpp
/* Пузырьковая сортировка */voidbubbleSort(vector<int>&nums){// Внешний цикл: неотсортированный диапазон [0, i]for(inti=nums.size()-1;i>0;i--){// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецfor(intj=0;j<i;j++){if(nums[j]>nums[j+1]){// Поменять местами nums[j] и nums[j + 1]// Здесь используется функция std::swap()swap(nums[j],nums[j+1]);}}}}
bubble_sort.java
/* Пузырьковая сортировка */voidbubbleSort(int[]nums){// Внешний цикл: неотсортированный диапазон [0, i]for(inti=nums.length-1;i>0;i--){// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецfor(intj=0;j<i;j++){if(nums[j]>nums[j+1]){// Поменять местами nums[j] и nums[j + 1]inttmp=nums[j];nums[j]=nums[j+1];nums[j+1]=tmp;}}}}
bubble_sort.cs
/* Пузырьковая сортировка */voidBubbleSort(int[]nums){// Внешний цикл: неотсортированный диапазон [0, i]for(inti=nums.Length-1;i>0;i--){// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецfor(intj=0;j<i;j++){if(nums[j]>nums[j+1]){// Поменять местами nums[j] и nums[j + 1](nums[j+1],nums[j])=(nums[j],nums[j+1]);}}}}
bubble_sort.go
/* Пузырьковая сортировка */funcbubbleSort(nums[]int){// Внешний цикл: неотсортированный диапазон [0, i]fori:=len(nums)-1;i>0;i--{// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецforj:=0;j<i;j++{ifnums[j]>nums[j+1]{// Поменять местами nums[j] и nums[j + 1]nums[j],nums[j+1]=nums[j+1],nums[j]}}}}
bubble_sort.swift
/* Пузырьковая сортировка */funcbubbleSort(nums:inout[Int]){// Внешний цикл: неотсортированный диапазон [0, i]foriinnums.indices.dropFirst().reversed(){// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецforjin0..<i{ifnums[j]>nums[j+1]{// Поменять местами nums[j] и nums[j + 1]nums.swapAt(j,j+1)}}}}
bubble_sort.js
/* Пузырьковая сортировка */functionbubbleSort(nums){// Внешний цикл: неотсортированный диапазон [0, i]for(leti=nums.length-1;i>0;i--){// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецfor(letj=0;j<i;j++){if(nums[j]>nums[j+1]){// Поменять местами nums[j] и nums[j + 1]lettmp=nums[j];nums[j]=nums[j+1];nums[j+1]=tmp;}}}}
bubble_sort.ts
/* Пузырьковая сортировка */functionbubbleSort(nums:number[]):void{// Внешний цикл: неотсортированный диапазон [0, i]for(leti=nums.length-1;i>0;i--){// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецfor(letj=0;j<i;j++){if(nums[j]>nums[j+1]){// Поменять местами nums[j] и nums[j + 1]lettmp=nums[j];nums[j]=nums[j+1];nums[j+1]=tmp;}}}}
bubble_sort.dart
/* Пузырьковая сортировка */voidbubbleSort(List<int>nums){// Внешний цикл: неотсортированный диапазон [0, i]for(inti=nums.length-1;i>0;i--){// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецfor(intj=0;j<i;j++){if(nums[j]>nums[j+1]){// Поменять местами nums[j] и nums[j + 1]inttmp=nums[j];nums[j]=nums[j+1];nums[j+1]=tmp;}}}}
bubble_sort.rs
/* Пузырьковая сортировка */fnbubble_sort(nums:&mut[i32]){// Внешний цикл: неотсортированный диапазон [0, i]foriin(1..nums.len()).rev(){// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецforjin0..i{ifnums[j]>nums[j+1]{// Поменять местами nums[j] и nums[j + 1]nums.swap(j,j+1);}}}}
bubble_sort.c
/* Пузырьковая сортировка */voidbubbleSort(intnums[],intsize){// Внешний цикл: неотсортированный диапазон [0, i]for(inti=size-1;i>0;i--){// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецfor(intj=0;j<i;j++){if(nums[j]>nums[j+1]){inttemp=nums[j];nums[j]=nums[j+1];nums[j+1]=temp;}}}}
bubble_sort.kt
/* Пузырьковая сортировка */funbubbleSort(nums:IntArray){// Внешний цикл: неотсортированный диапазон [0, i]for(iinnums.size-1downTo1){// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецfor(jin0..<i){if(nums[j]>nums[j+1]){// Поменять местами nums[j] и nums[j + 1]valtemp=nums[j]nums[j]=nums[j+1]nums[j+1]=temp}}}}
bubble_sort.rb
### Пузырьковая сортировка ###defbubble_sort(nums)n=nums.length# Внешний цикл: неотсортированный диапазон [0, i]foriin(n-1).downto(1)# Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецforjin0...iifnums[j]>nums[j+1]# Поменять местами nums[j] и nums[j + 1]nums[j],nums[j+1]=nums[j+1],nums[j]endendendend
Если в каком-либо раунде «всплытия» не произошло ни одного обмена, значит, массив уже отсортирован и можно сразу вернуть результат. Поэтому можно добавить флаг flag для отслеживания этой ситуации и немедленного выхода.
После такой оптимизации худшая и средняя временные сложности сортировки пузырьком по-прежнему равны . Однако если входной массив уже полностью упорядочен, достигается лучшая временная сложность .
bubble_sort.py
defbubble_sort_with_flag(nums:list[int]):"""Пузырьковая сортировка (оптимизация флагом)"""n=len(nums)# Внешний цикл: неотсортированный диапазон [0, i]foriinrange(n-1,0,-1):flag=False# Инициализировать флаг# Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецforjinrange(i):ifnums[j]>nums[j+1]:# Поменять местами nums[j] и nums[j + 1]nums[j],nums[j+1]=nums[j+1],nums[j]flag=True# Записать обмен элементовifnotflag:break# На этой итерации «всплытия» не было ни одного обмена, сразу выйти
bubble_sort.cpp
/* Пузырьковая сортировка (оптимизация флагом) */voidbubbleSortWithFlag(vector<int>&nums){// Внешний цикл: неотсортированный диапазон [0, i]for(inti=nums.size()-1;i>0;i--){boolflag=false;// Инициализировать флаг// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецfor(intj=0;j<i;j++){if(nums[j]>nums[j+1]){// Поменять местами nums[j] и nums[j + 1]// Здесь используется функция std::swap()swap(nums[j],nums[j+1]);flag=true;// Записать обмен элементов}}if(!flag)break;// На этой итерации «всплытия» не было ни одного обмена, сразу выйти}}
bubble_sort.java
/* Пузырьковая сортировка (оптимизация флагом) */voidbubbleSortWithFlag(int[]nums){// Внешний цикл: неотсортированный диапазон [0, i]for(inti=nums.length-1;i>0;i--){booleanflag=false;// Инициализировать флаг// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецfor(intj=0;j<i;j++){if(nums[j]>nums[j+1]){// Поменять местами nums[j] и nums[j + 1]inttmp=nums[j];nums[j]=nums[j+1];nums[j+1]=tmp;flag=true;// Записать обмен элементов}}if(!flag)break;// На этой итерации «всплытия» не было ни одного обмена, сразу выйти}}
bubble_sort.cs
/* Пузырьковая сортировка (оптимизация флагом) */voidBubbleSortWithFlag(int[]nums){// Внешний цикл: неотсортированный диапазон [0, i]for(inti=nums.Length-1;i>0;i--){boolflag=false;// Инициализировать флаг// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецfor(intj=0;j<i;j++){if(nums[j]>nums[j+1]){// Поменять местами nums[j] и nums[j + 1](nums[j+1],nums[j])=(nums[j],nums[j+1]);flag=true;// Записать обмен элементов}}if(!flag)break;// На этой итерации «всплытия» не было ни одного обмена, сразу выйти}}
bubble_sort.go
/* Пузырьковая сортировка (оптимизация флагом) */funcbubbleSortWithFlag(nums[]int){// Внешний цикл: неотсортированный диапазон [0, i]fori:=len(nums)-1;i>0;i--{flag:=false// Инициализировать флаг// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецforj:=0;j<i;j++{ifnums[j]>nums[j+1]{// Поменять местами nums[j] и nums[j + 1]nums[j],nums[j+1]=nums[j+1],nums[j]flag=true// Записать обмен элементов}}ifflag==false{// На этой итерации «всплытия» не было ни одного обмена, сразу выйтиbreak}}}
bubble_sort.swift
/* Пузырьковая сортировка (оптимизация флагом) */funcbubbleSortWithFlag(nums:inout[Int]){// Внешний цикл: неотсортированный диапазон [0, i]foriinnums.indices.dropFirst().reversed(){varflag=false// Инициализировать флагforjin0..<i{ifnums[j]>nums[j+1]{// Поменять местами nums[j] и nums[j + 1]nums.swapAt(j,j+1)flag=true// Записать обмен элементов}}if!flag{// На этой итерации «всплытия» не было ни одного обмена, сразу выйтиbreak}}}
bubble_sort.js
/* Пузырьковая сортировка (оптимизация флагом) */functionbubbleSortWithFlag(nums){// Внешний цикл: неотсортированный диапазон [0, i]for(leti=nums.length-1;i>0;i--){letflag=false;// Инициализировать флаг// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецfor(letj=0;j<i;j++){if(nums[j]>nums[j+1]){// Поменять местами nums[j] и nums[j + 1]lettmp=nums[j];nums[j]=nums[j+1];nums[j+1]=tmp;flag=true;// Записать обмен элементов}}if(!flag)break;// На этой итерации «всплытия» не было ни одного обмена, сразу выйти}}
bubble_sort.ts
/* Пузырьковая сортировка (оптимизация флагом) */functionbubbleSortWithFlag(nums:number[]):void{// Внешний цикл: неотсортированный диапазон [0, i]for(leti=nums.length-1;i>0;i--){letflag=false;// Инициализировать флаг// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецfor(letj=0;j<i;j++){if(nums[j]>nums[j+1]){// Поменять местами nums[j] и nums[j + 1]lettmp=nums[j];nums[j]=nums[j+1];nums[j+1]=tmp;flag=true;// Записать обмен элементов}}if(!flag)break;// На этой итерации «всплытия» не было ни одного обмена, сразу выйти}}
bubble_sort.dart
/* Пузырьковая сортировка (оптимизация флагом) */voidbubbleSortWithFlag(List<int>nums){// Внешний цикл: неотсортированный диапазон [0, i]for(inti=nums.length-1;i>0;i--){boolflag=false;// Инициализировать флаг// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецfor(intj=0;j<i;j++){if(nums[j]>nums[j+1]){// Поменять местами nums[j] и nums[j + 1]inttmp=nums[j];nums[j]=nums[j+1];nums[j+1]=tmp;flag=true;// Записать обмен элементов}}if(!flag)break;// На этой итерации «всплытия» не было ни одного обмена, сразу выйти}}
bubble_sort.rs
/* Пузырьковая сортировка (оптимизация флагом) */fnbubble_sort_with_flag(nums:&mut[i32]){// Внешний цикл: неотсортированный диапазон [0, i]foriin(1..nums.len()).rev(){letmutflag=false;// Инициализировать флаг// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецforjin0..i{ifnums[j]>nums[j+1]{// Поменять местами nums[j] и nums[j + 1]nums.swap(j,j+1);flag=true;// Записать обмен элементов}}if!flag{break;// На этой итерации «всплытия» не было ни одного обмена, сразу выйти};}}
bubble_sort.c
/* Пузырьковая сортировка (оптимизация флагом) */voidbubbleSortWithFlag(intnums[],intsize){// Внешний цикл: неотсортированный диапазон [0, i]for(inti=size-1;i>0;i--){boolflag=false;// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецfor(intj=0;j<i;j++){if(nums[j]>nums[j+1]){inttemp=nums[j];nums[j]=nums[j+1];nums[j+1]=temp;flag=true;}}if(!flag)break;}}
bubble_sort.kt
/* Пузырьковая сортировка (оптимизация флагом) */funbubbleSortWithFlag(nums:IntArray){// Внешний цикл: неотсортированный диапазон [0, i]for(iinnums.size-1downTo1){varflag=false// Инициализировать флаг// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецfor(jin0..<i){if(nums[j]>nums[j+1]){// Поменять местами nums[j] и nums[j + 1]valtemp=nums[j]nums[j]=nums[j+1]nums[j+1]=tempflag=true// Записать обмен элементов}}if(!flag)break// На этой итерации «всплытия» не было ни одного обмена, сразу выйти}}
bubble_sort.rb
### Пузырьковая сортировка ###defbubble_sort(nums)n=nums.length# Внешний цикл: неотсортированный диапазон [0, i]foriin(n-1).downto(1)# Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецforjin0...iifnums[j]>nums[j+1]# Поменять местами nums[j] и nums[j + 1]nums[j],nums[j+1]=nums[j+1],nums[j]endendendend# ## Пузырьковая сортировка (оптимизация флагом) ###defbubble_sort_with_flag(nums)n=nums.length# Внешний цикл: неотсортированный диапазон [0, i]foriin(n-1).downto(1)flag=false# Инициализировать флаг# Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конецforjin0...iifnums[j]>nums[j+1]# Поменять местами nums[j] и nums[j + 1]nums[j],nums[j+1]=nums[j+1],nums[j]flag=true# Записать обмен элементовendendbreakunlessflag# На этой итерации «всплытия» не было ни одного обмена, сразу выйтиendend
Временная сложность равна , алгоритм адаптивен: длины диапазонов, проходящих «всплытие» в разных раундах, последовательно равны , , , , , а их сумма равна . После добавления оптимизации с flag лучшая временная сложность может достигать .
Пространственная сложность равна , сортировка выполняется на месте: указатели и используют константный объем дополнительной памяти.
Стабильная сортировка: поскольку при «всплытии» равные элементы не обмениваются местами.
Оставляйте свои идеи, вопросы и предложения в комментариях