Оптимизированная Сортировка Пузырьков (Java)
Я хотел бы знать, как еще я могу оптимизировать сортировку пузырьков, чтобы он просматривал элементы, которые уже были отсортированы, даже после первого прохода.
Eg. [4, 2, 3, 1, 5, 6] --> [2, 3, 1, **4, 5, 6**]
мы наблюдаем, что [4,5,6] уже отсортированы, как можно изменить мой код, чтобы он пропустил эти 3 элемента в следующем проходе? (что означает, что сортировка будет более эффективной?) Вы предлагаете рекурсивный метод?
public static void bubblesort(int[] a) {
for(int i=1; i<a.length; i++) {
boolean is_sorted = true;
for(int j=0; j<a.length; j++) {
if(a[j] > a[j+1]) {
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
is_sorted = false;
}
}
if(is_sorted) return;
}
}
Спасибо за ваше время!
8 ответов
во-первых, у вас есть доступ вне пределов:
for(int j=0; j<a.length; j++) {
if(a[j] > a[j+1]) {
на j == a.length-1
, поэтому условие цикла должно быть j < a.length-1
.
но, в Bubble sort, вы знаете, что после k
проходит, крупнейший k
элементы сортируются по k
последние записи массива, поэтому обычная сортировка пузырьков использует
public static void bubblesort(int[] a) {
for(int i=1; i<a.length; i++) {
boolean is_sorted = true;
for(int j=0; j < a.length - i; j++) { // skip the already sorted largest elements
if(a[j] > a[j+1]) {
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
is_sorted = false;
}
}
if(is_sorted) return;
}
}
теперь это все равно сделает много ненужных итераций, когда массив имеет длинный отсортированный хвост крупнейших элементов, скажем у вас есть k,k-1,...,1
первым k
элементы и k+1
to 100000000
в порядке после этого. Стандартная сортировка пузырьков пройдет k
раз через (почти) весь массив.
но если вы помните, где вы сделали свой последний своп, вы знаете, что после этого индекса есть самые большие элементы в порядке, поэтому
public static void bubblesort(int[] a) {
int lastSwap = a.length-1;
for(int i=1; i<a.length; i++) {
boolean is_sorted = true;
int currentSwap = -1;
for(int j=0; j < lastSwap; j++) {
if(a[j] > a[j+1]) {
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
is_sorted = false;
currentSwap = j;
}
}
if(is_sorted) return;
lastSwap = currentSwap;
}
}
сортировал бы приведенный выше пример только с одним проходом через весь массив, а остальные проходят только через (короткий) префикс.
конечно, в общем, это не купит вам много, но тогда оптимизация пузыря - это довольно бесполезное упражнение.
public static Integer[] optimizedbubbleSort(Integer[] input){
long startTime = System.nanoTime();
boolean swapped = true;
for(int pass=input.length-1; pass>=0 && swapped; pass--){
swapped = false;
for(int i=0; i<pass; i++){
if(input[i]>input[i+1]){
int temp = input[i];
input[i] = input[i+1];
input[i+1] = temp;
swapped = true;
}
}
}
System.out.println("Time taken for OPTIMIZED bubbleSort: "+(System.nanoTime() - startTime));
return input;
}
вы должны использовать переменную "size" для внутреннего цикла и изменять ее на последний заменяемый элемент в каждом цикле.Таким образом, ваш внутренний цикл переходит к последнему "замененному" элементу и передает остальные, которые не заменены (ака в их correctplace). я.е
do {
int newsize =0;
for (int i = 1; i < size; i++) {
if (a[i - 1] > a[i]) {
int temp;
temp = a[i - 1];
a[i - 1] = a[i];
a[i] = temp;
newsize =i;
}
}
size = newsize;
} while (size > 0);
public static void BubbleSorter(params int[] input){
int newSize = input.Length-1, size = 0;
bool swap;
do
{
swap = false;
for (int j = 0; j < newSize; j++)
{
if (input[j] > input[j + 1])
{
int temp = input[j + 1];
input[j + 1] = input[j];
input[j] = temp;
swap = true;
size = j;
}
} newSize = size;
} while (swap);
DisplayArrayElements(input);
}
Я разработал метод, который уменьшает количество итераций, исключая части в начале и конце массива, которые были упорядочены в предыдущих циклах.
static int[] BubbleSortOptimized(int arr[]) {
int start = 0, stop = arr.length - 1, control = 0;
boolean ordered, nsCaught;
while (true){
ordered = true;
nsCaught = false;
for (int i = start; i < stop; i++) {
if (i > 1) {
if (!nsCaught && arr[i-2] > arr[i-1]){
ordered = false;
start = i-2;
nsCaught = true;
}
}
if (arr[i] > arr[i+1]){
int hold = arr[i];
arr[i] = arr[i+1];
arr[i+1] = hold;
control = i;
}
}
System.out.println(Arrays.toString(arr));
if (ordered) return arr;
stop = control;
}
}
, а как @Daniel Fischer сказал в предыдущем ответе, он не делает много с большими массивами.
в приведенном выше примере массив был отсортирован после 3-го прохода, но мы все равно продолжим с 4-м, 5-м проходом. Предположим, если массив уже отсортирован, то не будет замены (потому что соседние элементы всегда в порядке), но все же мы продолжим с проходами, и все равно будет (n-1) проходов.
Если мы можем определить, что массив отсортирован, то мы должны прекратить выполнение дальнейших проходов. Это оптимизация по исходной сортировке пузырьков алгоритм.
если нет замены в определенном проходе, это означает, что массив отсортирован, поэтому мы не должны выполнять дальнейшие проходы. Для этого мы можем иметь переменную флага, которая установлена в true перед каждым проходом и ложна при выполнении подкачки.
void bubbleSort(int *arr, int n){
for(int i=0; i<n; i++)
{
bool flag = false;
for(int j=0; j<n-i-1; j++)
{
if(array[j]>array[j+1])
{
flag = true;
int temp = array[j+1];
array[j+1] = array[j];
array[j] = temp;
}
}
// No Swapping happened, array is sorted
if(!flag){
return;
}}}
public class Tester {
static boolean bubbleFlag = true;
public static void main(String[] args) {
int array[] = new int[] {
1,
9,
2,
3,
4,
5,
6
};
bubbleSort(array);
}
private static void bubbleSort(int...array) {
System.out.println("Before Sorting: " + Arrays.toString(array));
for (int i = 0; i < array.length - 1; i++) {
if (i > 0) if (bubbleFlag) break;
for (int j = 0; j < array.length - i - 1; j++) {
if (array[j] > array[j + 1]) array = swap(j, j + 1, array);
System.out.println("Iteration " + i + " :" + Arrays.toString(array));
}
bubbleFlag = true;
}
}
private static int[] swap(int i1, int i2, int...is) {
bubbleFlag = false;
is[i1] = is[i1] + is[i2];
is[i2] = is[i1] - is[i2];
is[i1] = is[i1] - is[i2];
return is;
}
}
оптимизированная сортировка пузырьков только с 1 для цикла
/*Advanced BUBBLE SORT with ONE PASS*/
/*Authored by :: Brooks Tare AAU*/
public class Bubble {
public int[] bubble(int b[]){
int temp,temp1;
for(int i=0;i<b.length-1;i++){
if(b[i]>b[i+1] ){
///swap(b[i],b[i+1]);
temp=b[i];
b[i]=b[i+1];
b[i+1]=temp;
/*Checking if there is any number(s) greater than
the current number. If there is swap them.*/
while(i>0){
if(b[i]<b[i-1]){
///swap(b[i]<b[i-1])
temp1=b[i];
b[i]=b[i-1];
b[i-1]=temp1;
i--;
}
else if(b[i]>b[i-1]){i--;}
}
}
else{continue;}
}
return b;
}
///the following is a function to display the Array
public void see(int []a){
for(int j=0;j<a.length;j++){
System.out.print(a[j]+",");
}
}
public static void main(String []args){
///You can change the Array to your preference.. u can even make it dynamic
int b[]={5,1,4,2,0,3};
int v[]=new int[100];
Bubble br=new Bubble();
v=br.bubble(b);
br.see(v);
}
}