簡體   English   中英

在Java中使用3個堆棧對未排序的數組進行排序

[英]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),現在嘗試將其轉換為排序算法

應該這樣做:

  1. 將所有項目從堆棧A移到堆棧B,存儲在“ x”中找到的最大值。
  2. 將所有項目從堆棧B移到堆棧A,但值“ x”從上一個詞干確定的除外。 將它們移到C。
  3. 重復直到A和B都為空。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM