[英]Sorting an unsorted array using 3 stacks in Java
這是我要回答的問題
構造一個新的排序算法,該算法僅使用標記為A,B和C的三個堆棧,稱為x的單個“雙”變量以及任何輔助變量(例如循環計數器)。 您的算法假定堆棧A包含一組UNSORTED數據,到算法結束時,其中一個堆棧將包含按升序排序的數據。
我正在嘗試找出Java中的算法,但我無法終生解決! 你能幫我嗎?!
如果有進行更快排序的好處,則可以使用3個堆棧實現自下而上的合並排序O(n log(n))。 正如greybeard指出的那樣,多相自下而上的合並排序(一種面向磁帶驅動器或其他順序設備的方法)應該是最快的3堆棧排序。
一個更簡單的合並排序將以交替方式將每次運行(初始大小== 1)從A移動到B和C,甚至運行到B,奇數運行到C,然后2方式將B和C合並回A,兩次運行大小,重復直到運行大小> =堆棧大小。 聚階段消除了移動/拆分步驟,除了初始分配步驟外,該步驟將某些元素從A移動到B和C。
設置初始的下降/上升狀態(反轉比較的意義),並跟蹤堆棧中的運行大小何時由於偽元素而改變(+1或-1)是有點棘手的。 我使用47個斐波那契整數表進行初始分布設置(處理堆棧大小最多為1/2億個元素)。 堆棧大小一開始是已知的,但是可以通過執行單個副本來生成(副本順序無關緊要,因為初始運行大小為1)。
n個元素的初始分布:假設fib(m + 1)> n> fib(m)。 將n-fib(m)元素移至B。fib(m + 1)-n元素移至C。將A和B中的n-fib(m)元素合並(推入)到C。第一次合並后, C以大小為2的n-fib(m)運行結束,大小為1的fib(m + 1)-n運行= fib(m-1)運行。 B被清空。 A以(n)-(fib(m + 1)-n)-2(n-fib(m))= 2 fib(m)-fib(m + 1)= fib(m)-fib(m結尾-1)=大小為1的fib(m-2)游程。如果n = fib(m),則fib(m-1)元素移至B,而fib(m-2)元素保留在A中。
Wiki文章還描述了與3堆棧排序類似的情況,其中磁帶驅動器向前寫入和向后讀取,但沒有在開始時提到如何分配虛擬運行(大小為0的運行)的詳細信息,但這可能包括在由greybeard提到的那本已有55年歷史的出版物。
http://en.wikipedia.org/wiki/Polyphase_merge_sort
我寫了一個C ++示例,但是由於該問題要求使用Java(下面的示例代碼),因此我將提供一個指向C ++示例的zip的鏈接。 C ++示例使用數組和每個數組的堆棧指針(ppmrg3s.cpp)代替堆棧類。 zip還具有使用數組(ppmrg.cpp)的常規多相合並排序。
http://rcgldr.net/misc/ppmrg.zip
示例Java代碼。 在我的系統上,Intel 2600K,3.4ghz,Win 7 64位,它在大約4秒內完成了1600萬雙的排序。
public class ppmrg3s {
static final int[] FIBTBL =
{ 0, 1, 1, 2, 3, 5,
8, 13, 21, 34, 55, 89,
144, 233, 377, 610, 987, 1597,
2584, 4181, 6765, 10946, 17711, 28657,
46368, 75025, 121393, 196418, 317811, 514229,
832040, 1346269, 2178309, 3524578, 5702887, 9227465,
14930352, 24157817, 39088169, 63245986, 102334155, 165580141,
267914296, 433494437, 701408733,1134903170,1836311903};
// return index of largest fib() <= n
static int flfib(int n)
{
int lo = 0;
int hi = 47;
while((hi - lo) > 1){
int i = (lo + hi)/2;
if(n < FIBTBL[i]){
hi = i;
continue;
}
if(n > FIBTBL[i]){
lo = i;
continue;
}
return i;
}
return lo;
}
// poly phase merge sort using 3 stacks
static void ppmrg3s(dstack a, dstack b, dstack c)
{
if(a.size() < 2)
return;
int ars = 1; // init run sizes
int brs = 1;
int asc = 0; // no size change
int bsc = 0;
int csc = 0;
int scv = 0-1; // size change value
boolean dsf; // == 1 if descending sequence
{ // block for local variable scope
int f = flfib(a.size()); // FIBTBL[f] >= size >= FIBTBL[f-1]
dsf = ((f%3) == 0); // init compare flag
if(FIBTBL[f] == a.size()){ // if exact fibonacci size,
for (int i = 0; i < FIBTBL[f - 1]; i++) { // move to b
b.push(a.pop());
}
} else { // else move to b, c
// update compare flag
dsf ^= 1 == ((a.size() - FIBTBL[f]) & 1);
// i = excess run count
int i = a.size() - FIBTBL[f];
// j = dummy run count
int j = FIBTBL[f + 1] - a.size();
// move excess elements to b
do{
b.push(a.pop());
}while(0 != --i);
// move dummy count elements to c
do{
c.push(a.pop());
}while(0 != --j);
csc = c.size();
}
} // end block scope
while(true){ // start merge pass
if(asc == a.size()){ // check for size count change
ars += scv; // (due to dummy run size == 0)
scv = 0-scv;
asc = 0;
csc = c.size();
}
if(bsc == b.size()){
brs += scv;
scv = 0-scv;
bsc = 0;
csc = c.size();
}
int arc = ars; // init run counters
int brc = brs;
while(true){ // start merge pair of runs
if(dsf ^ (a.peek() <= b.peek())){
c.push(a.pop()); // move a to c
if(--arc != 0) // if not end a
continue; // continue back to compare
do{ // else move rest of b run to c
c.push(b.pop());
}while(0 != --brc);
break; // and break
} else {
c.push(b.pop()); // move b to c
if(0 != --brc) // if not end b
continue; // continue back to compare
do{ // else move rest of a run to c
c.push(a.pop());
}while(0 != --arc);
break; // and break
}
} // end merge pair of runs
dsf ^= true; // toggle compare flag
if(b.empty()){ // if end b
if(a.empty()) // if end a, done
break;
b.swap(c); // swap b, c
brs += ars;
if (0 == asc)
bsc = csc;
} else { // else not end b
if(!a.empty()) // if not end a
continue; // continue back to merge pair
a.swap(c); // swap a, c
ars += brs;
if (0 == bsc)
asc = csc;
}
}
a.swap(c); // return sorted stack in a
}
我創建了一個快速堆棧類,該類使用固定的最大雙精度數組,該數組包含交換函數成員:
class dstack{
double []ar; // array
int sz; // size
int sp; // stack pointer
public dstack(int sz){ // constructor with size
this.ar = new double[sz];
this.sz = sz;
this.sp = sz;
}
public void push(double d){
this.ar[--sp] = d;
}
public double pop(){
return this.ar[sp++];
}
public double peek(){
return this.ar[sp];
}
public boolean empty(){
return sp == sz;
}
public int size(){
return sz-sp;
}
public void swap(dstack othr){
double []tempar = othr.ar;
int tempsz = othr.sz;
int tempsp = othr.sp;
othr.ar = this.ar;
othr.sz = this.sz;
othr.sp = this.sp;
this.ar = tempar;
this.sz = tempsz;
this.sp = tempsp;
}
}
測試程序。 它使用隨機整數(nextInt),在a.push(...)期間將其轉換為雙精度數。 這使早期調試更加容易。 對於其他平台,或者要進行調試,請為NUMELEM使用較小的數字,即元素數。
static final int NUMELEM = 16*1024*1024;
public static void main(String[] args) {
dstack a = new dstack(NUMELEM);
dstack b = new dstack(NUMELEM);
dstack c = new dstack(NUMELEM);
Random r = new Random();
for(int i = 0; i < NUMELEM; i++){
a.push(r.nextInt(NUMELEM));
}
long bgn, end;
bgn = System.currentTimeMillis();
ppmrg3s(a, b, c);
end = System.currentTimeMillis();
double d;
d = a.pop();
while(!a.empty()){
if(d > a.peek()){
System.out.println("error");
break;
}
d = a.pop();
}
System.out.println("milliseconds");
System.out.println(end-bgn);
}
一個簡單的程序可以從數組中獲取值,然后將其打印到命令控制台。
import java.util.*;
public class StackSort
{
static Stack<Double> A = new Stack<Double>();
public void createStackA()
{
double[] x = {-10,5, 2, 1, 9, 0, 10};
for (int i = 0; i < x.length; i++)
{
A.push(x[i]);
}
}
public void sortStackA(Stack<Double> C)
{
Stack<Double> B = new Stack<Double>();
while(!C.isEmpty())
{
double s1 = (double) C.pop();
while(!B.isEmpty() && (B.peek() > s1))
{
C.push(B.pop());
}
B.push(s1);
}
System.out.println(B);
}
public static void main(String[] args)
{
StackSort sS = new StackSort();
sS.createStackA();
sS.sortStackA(A);
}
}
對於開始提示,請檢查調車場算法,這是一種類似的方法,因為運算符(即值)被推入堆棧並根據其相對優先級(即值)彈出到另一個堆棧(即輸出隊列)
該算法有3個堆棧,a)輸入隊列(讓我們說A),b)運算符堆棧(讓我們說B)和c)輸出隊列(讓我們說C),現在嘗試將其轉換為排序算法
應該這樣做:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.