最初のパスの後でも、すでにソートされている要素を見落とすようにバブルソートを最適化する方法を他に知りたいです。
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;
}
}
御時間ありがとうございます!
まず第一に、あなたは範囲外のアクセス権を持っています:
for(int j=0; j<a.length; j++) {
if(a[j] > a[j+1]) {
j == a.length-1
の場合、ループ条件はj < a.length-1
である必要があります。
ただし、バブルソートでは、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,k-1,...,1
があり、k+1
から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;
}
}
上記の例は、配列全体を1回だけ通過し、残りは(短い)プレフィックスのみを通過してソートされます。
もちろん、一般的に、それはあなたに多くを買わないでしょう、しかしそれからバブルソートを最適化することはとにかくかなり無駄な運動です。
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;
}
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);
}
内側のループに変数「size」を使用し、各サイクルでそれを最新のスワップされた要素に変更する必要があります。このようにして、内側のループは最新の「スワップされた」要素に移動し、スワップされていない残りを渡します(別名正しい場所) )。つまり、
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);
これがあなたに必要なものだと思います。重要なのは、最後のスワップが発生したインデックス(newn)までのみ配列を検討することです。
public static void bubblesort(int[] a) {
int i, n, newn;
n = a.length;
while (n > 0) {
newn = 0;
for (i = 1; i < n; i++) {
if (a[i - 1] > a[i]) {
temp = a[i];
a[i] = a[i - 1];
a[i - 1] = temp;
newn = i;
}
}
n = newn;
}
return a;
}
上記の例では、配列は3回目のパスの後に並べ替えられましたが、4回目と5回目のパスを続行します。配列がすでにソートされている場合、スワッピングは発生しませんが(隣接する要素は常に順序付けられているため)、パスを続行し、(n-1)回のパスが存在します。
配列がソートされていることが確認できたら、それ以上のパスの実行を停止する必要があります。これは、元のバブルソートアルゴリズムに対する最適化です。
特定のパスにスワッピングがない場合は、配列がソートされていることを意味するため、それ以上のパスを実行しないでください。このために、各パスの前にtrueに設定され、スワッピングが実行されるとfalseになるフラグ変数を使用できます。
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;
}}}
これは、whileループを使用した最も単純で最良かつ最適なバブルソートアルゴリズムです。指定された配列形式の数値を左から右に昇順で並べ替えます。理解しやすく、実装も簡単です。
private static int[] bubbleSort(int[] array) {
int length = array.length - 1;
int index = 0;
while ( index < length) {
if (array[index] > array[index + 1]) {
swap(array, index, index + 1);
}
index++;
if (index == length) {
index = 0;
length--;
}
}
return array;
}
private static void swap(int[] array, int index1, int index2) {
int temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
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;
}
}
以前のループで順序付けられた配列の最初と最後の部分を除外することで、反復回数を減らす方法を考案しました。
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 が以前の回答で述べたように、 より大きな配列ではあまり効果がありません。