棧與隊列(Stack and Queue)


1.定義

  

  棧:后進先出(LIFO-last in first out):最后插入的元素最先出來。

  隊列:先進先出(FIFO-first in first out):最先插入的元素最先出來。

2.用數組實現棧和隊列

實現棧:

  由於數組大小未知,如果每次插入元素都擴展一次數據(每次擴展都意味着構建一個新數組,然后把舊數組復制給新數組),那么性能消耗相當嚴重。

  這里使用貪心算法,數組每次被填滿后,加入下一個元素時,把數組拓展成現有數組的兩倍大小。

  每次移除元素時,檢測數組空余空間有多少。當數組里的元素個數只有整個數組大小的四分之一時,數組減半。

  為什么不是當數組里的元素個數只有整個數組大小的二分之一時,數組減半?考慮以下情況:數組有4個元素,數組大小為4個元素空間。此時,加一個元素,數組拓展成8個空間;再減一個元素,數組縮小為4個空間;如此循環,性能消耗嚴重。

  具體代碼(Java):

  

public ResizingArrayStackOfStrings()
{
    s=new String[1];
int N = 0; } pubilc
void Push(String item) { //如果下一個加入元素超出數組容量,拓展數組 if(N == s.length) Resize(2 * s.length); s[N++] = item; } private void Resize(int capacity) { String[] copy = new String[capacity]; //將舊數組元素復制給新數組 for(int i=0; i<N; i++) copy[i] = s[i]; s = copy; } public String Pop() { String item = s[--N]; s[N] = null; //剩余元素只占數組四分之一空間時,數組減半 if(N>0 && N=s.length/4) Resize(s.length/2); return item; }

效果如下圖:

 實現隊列

  與棧類似:

       數組每次被填滿后,加入下一個元素時,把數組拓展成現有數組的兩倍大小。

  每次移除元素時,檢測數組空余空間有多少。當數組里的元素個數只有整個數組大小的四分之一時,數組減半。

  不同之處在於:

       由於是先進先出,移除是從隊列的最前端開始的。所以當我們移除數個數據后,隊列數據是存儲在數組的中間部分的。令隊列數據的尾端數據ID為Num,首端數據ID為HeadIndex,則Num - HeadIndex為隊列數據元素個數。

       當隊列數據元素個數為整個數組空間的四分之一時,數組減半,且隊列數據左移至數組最左端。即Num-=HeadIndex;HeadIndex=0;

  圖中,HeadIndex=2;Num=5;

 

具體代碼:

.h:

UCLASS()
class ALGORITHM_API AStackAndQueuesExerciseTwo : public AActor
{
    GENERATED_BODY()
    
public:    
    // Sets default values for this actor's properties
    AStackAndQueuesExerciseTwo();
    // Called every frame
    virtual void Tick(float DeltaTime) override;
    //輸入
    void Enqueue(int Input);
    //重構數組(拓展或縮小)
    void Resize(int Capacity);
    //輸出且移除
    int Dequeue();
    //隊列里沒元素了?
    bool IsEmpty();

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public:    
    
private:
    //記錄數組中有多少個Int
    int Num;
    //隊列數組
    TArray<int> MyIntArray;
    //記錄下一個移除的數據ID
    int HeadIndex;
};

.cpp:

AStackAndQueuesExerciseTwo::AStackAndQueuesExerciseTwo()
{
     // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;
    //一開始數組沒成員
    Num = 0;
    HeadIndex = 0;
    //數組中有一個假元素
    MyIntArray.Add(0);
}

// Called when the game starts or when spawned
void AStackAndQueuesExerciseTwo::BeginPlay()
{
    Super::BeginPlay();
    //測試
    Enqueue(1);
    Enqueue(2);
    Enqueue(3);
    Enqueue(4);
    Enqueue(5);
    Dequeue();
    Dequeue();
    Dequeue();
    //隊列數組成員
    for (int i = HeadIndex; i < Num; i++)
    {
        UKismetSystemLibrary::PrintString(this, "i: " + FString::FromInt(i) + " End: " + FString::FromInt(MyIntArray[i]));
    }
    //隊列數組的容量
    UKismetSystemLibrary::PrintString(this, "MyIntArray.Num(): " + FString::FromInt(MyIntArray.Num()));
}

// Called every frame
void AStackAndQueuesExerciseTwo::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

}

void AStackAndQueuesExerciseTwo::Enqueue(int Input)
{
    //如果隊列數組已滿,拓展數組
    if (Num == MyIntArray.Num())
    {
        Resize(2 * MyIntArray.Num());
    }
    //拓展或者數組有空位時,添加元素
    if (Num < MyIntArray.Num())
    {
        MyIntArray[Num] = Input;
    }
    Num++;
}


void AStackAndQueuesExerciseTwo::Resize(const int Capacity)
{
    //int a[] = new int[Capacity];
    TArray<int> Copy;
    //添加數個假元素填充數組
    for (int i = 0; i < Capacity; i++)
    {
        Copy.Add(0);
    }
    //將隊列數組賦值給Copy數組,如果是縮小數組,則把隊列數組左移,節省空間
    for (int i = HeadIndex; i < Num; i++)
    {
        Copy[i - HeadIndex] = MyIntArray[i];
    }
    MyIntArray = Copy;
}

int AStackAndQueuesExerciseTwo::Dequeue()
{
    //判斷數組是否為空
    if (IsEmpty())
    {
        UKismetSystemLibrary::PrintString(this, "No Element Exist!!!");
        return 0;
    }
    else
    {
        UKismetSystemLibrary::PrintString(this, "Dequeue: " + FString::FromInt(MyIntArray[HeadIndex]));
    }
    HeadIndex++;
    //如果移除元素后,所剩元素為數組空間的四分之一,則數組減半
    if ((Num - HeadIndex) != 0 && (Num - HeadIndex) == (MyIntArray.Num() / 4))
    {
        Resize(MyIntArray.Num() / 2);
        //移除空間后,隊列數組左移,節省空間
        Num -= HeadIndex;
        HeadIndex = 0;
        return MyIntArray[HeadIndex];
    }
    else
    {
        return MyIntArray[HeadIndex - 1];
    }
    
}
//如果下一個要移除的數據不存在,則為空數組
bool AStackAndQueuesExerciseTwo::IsEmpty()
{
    return HeadIndex >= Num;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM