經典數據結構與算法(一):Python/C/C ++實現堆棧和隊列



 1、堆棧   javascript

堆棧是編程中有用的數據結構。就像一堆盤子彼此疊放。java


堆棧表示相似於一堆盤子



想想用這樣一堆盤子能夠作的事情python


  • 在上面放一個新盤子ios

  • 卸下頂部盤子web

  • 持續來回作實驗就知道了堆棧的意義
    算法


若是要將板放在底部,則必須先卸下頂部的全部板。這種安排稱爲「後進先出」-放置的最後一個元素是第一個外出元素。編程




LIFO堆棧原理


用編程的術語來講,將一個元素放在堆棧的頂部稱爲「推」,而將一個元素刪除則稱爲「彈出」。數組

堆棧推入和彈出操做



在上圖中,儘管元頂部3最後才保留,但它首先被移除-所以它遵循後進先出(LIFO)原則。瀏覽器




堆棧的基本操做


堆棧是一個對象,或更具體地說,是一個容許執行如下操做的抽象數據結構(ADT):微信


  • Push:將元素添加到堆棧頂部

  • Pop:從堆棧頂部刪除元素

  • IsEmpty:檢查堆棧是否爲空

  • IsFull:檢查堆棧是否已滿

  • Peek:獲取頂部元素的值而不刪除它




堆棧數據結構的工做


操做以下:


  1. 稱爲TOP用於跟蹤堆棧中的頂部元素。

  2. 初始化堆棧時,將其值設置爲-1,以即可以經過比較來檢查堆棧是否爲空TOP == -1

  3. 推送元素時,增長了TOP並將新元素放置在所指向的位置TOP

  4. 彈出元素時,返回由指向的元素TOP並下降其值。

  5. 推入以前,檢查堆棧是否已滿

  6. 彈出以前,檢查堆棧是否已爲空


堆棧數據結構的工做




Python,C和C ++中的堆棧實現


最多見的堆棧實現是使用數組,可是也可使用列表來實現。

C:


// Stack implementation in C

#include <stdio.h>
#include <stdlib.h>
#include "math.h"

/*堆棧最大存儲元素基數*/
#define MAX 10

int count = 0;

// Creating a stack
struct stack
{

    int items[MAX];//堆棧元素數組
    int top;
};
typedef struct stack st;

void createEmptyStack(st *s)
{
    s->top = -1;
}

// Check if the stack is full
int isfull(st *s)
{
    if (s->top == MAX - 1)
        return 1;
    else
        return 0;
}

// Check if the stack is empty
int isempty(st *s)
{
    if (s->top == -1)
        return 1;
    else
        return 0;
}

// Add elements into stack
void push(st *s, int newitem)
{
    if (isfull(s))
    {
        printf("STACK FULL");
    }
    else
    {
        s->top++;//相似索引遞增
        s->items[s->top] = newitem;
    }
    count++;//計算次數=個數=添加幾個元素
}

// Remove element from stack
void pop(st *s)
{
    if (isempty(s))
    {
        printf("\n STACK EMPTY \n");
    }
    else
    {
        printf("Item popped= %d", s->items[s->top]);//--的形式從數組裏移除元素
        s->top--;//逐一減去
    }
    count--;
    printf("\n");
}

// Print elements of stack
void printStack(st *s)
{
    printf("Stack: ");
    for (int i = 0; i < count; i++)
    {
        printf("%d ", s->items[i]);
    }
    printf("\n");
}

// 執行 code
int main()
{
    int ch,i;
    st *s = (st *)malloc(sizeof(st));
    /*分配一個sizeof(st)大小的空間,而且把該空間的地址賦給st指針類型的p*/
    createEmptyStack(s);

    #if 0
    push(s, 1); //推元素1
    push(s, 2); //推元素2
    push(s, 3); //推元素3
    push(s, 4); //推元素4
    #endif
    /*也能夠寫成循環的形式*/
    int j;
    for (i = 1; i < 5; i++)
    {
        j = i * (i + 1);
        push(s, j);
        // printf("%d\n",i);
    }
    printStack(s);
    printf("cnt = %d\n", count);

    /*堆棧第一次移除*/
    pop(s);
    printf("\n堆棧第一次移除After popping out\n");
    printStack(s);
    printf("cnt0 = %d\n", count);
    /*堆棧第一次移除*/
    pop(s);
    printf("\n堆棧第二次移除After popping out\n");
    printStack(s);
    printf("cnt1 = %d\n", count);

    system("pause");
    return 0;
}


執行結果:


C++:


// Stack implementation in C++

#include <stdlib.h>
#include <iostream>

using namespace std;

#define MAX 10
int size_t = 0;

// Creating a stack
struct stack
{

    int items[MAX];
    int top;
};
typedef struct stack st;

void createEmptyStack(st *s)
{
    s->top = -1;
}

// Check if the stack is full
int isfull(st *s)
{
    if (s->top == MAX - 1)
        return 1;
    else
        return 0;
}

// Check if the stack is empty
int isempty(st *s)
{
    if (s->top == -1)
        return 1;
    else
        return 0;
}

// Add elements into stack
void push(st *s, int newitem)
{
    if (isfull(s))
    {
        printf("STACK FULL");
    }
    else
    {
        s->top++;
        s->items[s->top] = newitem;
    }
    size_t++;
}

// Remove element from stack
void pop(st *s)
{
    if (isempty(s))
    {
        printf("\n STACK EMPTY \n");
    }
    else
    {
        printf("Item popped= %d", s->items[s->top]);
        s->top--;
    }
    size_t--;
    cout << endl;
}

// Print elements of stack
void printStack(st *s)
{
    printf("Stack: ");
    for (int i = 0; i < size_t; i++)
    {
        cout << s->items[i] << " ";
    }
    cout << endl;
}

// Driver code
int main()
{

    int ch;
    st *s = (st *)malloc(sizeof(st));

    createEmptyStack(s);

    push(s, 1);
    push(s, 2);
    push(s, 3);
    push(s, 4);

    printStack(s);

    pop(s);

    cout << "\nAfter popping out\n";
    printStack(s);



    cin.get();
    return 0;
}



PYTHON:


# Stack implementation in python


# Creating a stack
def create_stack():
    stack = [] #保存
    return stack


# Creating an empty stack
def check_empty(stack):
    return len(stack) == 0


# Adding items into the stack
def push(stack, item):
    stack.append(item)
    # 追加打印出結果 +
    print("pushed item: " + item)



# Removing an element from the stack
def pop(stack):
    if (check_empty(stack)):
        return "stack is empty"
        

    return stack.pop()


stack = create_stack()
# push(stack, str(1))
# push(stack, str(2))
# push(stack, str(3))
# push(stack, str(4))
for item in range(1,10):
    push(stack, str(item))
    pass
print("第 1 次移除popped item: " + pop(stack))
print("移除後剩餘的元素stack after popping an element: " + str(stack))

print("第 2 次移除popped item: " + pop(stack))
print("移除後剩餘的元素stack after popping an element: " + str(stack))
# 能夠按照循環次數來移動

for item in range(5):
    print("第",item+3, "次移除popped item: " + pop(stack))
    print("移除後剩餘的元素stack after popping an element: " + str(stack))
    pass


執行結果:



堆棧時間複雜度


對於基於數組的堆棧實現,推入和彈出操做須要花費必定的時間,即O(1)由於在兩種狀況下都只有指針移動。




堆棧數據結構的應用


儘管堆棧是一個易於實現的簡單數據結構,但它很是強大。堆棧最多見的用途是:


  • 反轉單詞-將全部字母疊放並彈出。因爲堆棧的LIFO順序,您將得到相反順序的字母。

  • 在編譯器中-編譯器使用堆棧來計算表達式的值,例如2 + 4 / 5 * (7 - 9)將表達式轉換爲前綴或後綴形式。

  • 在瀏覽器中-瀏覽器中的記錄「後退」按鈕會將您之前訪問過的全部URL保存在堆棧中。每次您訪問新頁面時,它都會被添加到堆棧頂部。當您按下「後退」按鈕時,當前URL從堆棧中刪除,並訪問前一個URL。

 


2、隊列

     

隊列是編程中有用的數據結構。它相似於電影院大廳外面的售票隊列,在該隊列中,第一個進入隊列的人是第一個得到票的人。


隊列遵循先進先出(FIFO)規則-先進入的項目也是先進入的項目。


隊列的FIFO表示



在上圖中,因爲1在2以前保留在隊列中,所以它也是第一個從隊列中刪除的隊列。它遵循FIFO規則。

用編程術語來講,將元素放入隊列稱爲「入隊」,而將元素從隊列中刪除則稱爲「出隊」。



隊列的基本操做

隊列是一個對象,或更具體地說,是一個容許執行如下操做的抽象數據結構(ADT):

  • Enqueue:將元素添加到隊列的末尾

  • Dequeue:從隊列的前面刪除一個元素

  • IsEmpty:檢查隊列是否爲空

  • IsFull:檢查隊列是否已滿

  • Peek:獲取隊列最前面的值而不刪除它




隊列工做


隊列操做以下:


  • 兩個指針 FRONT 和 REAR

  • FRONT 跟蹤隊列的第一個元素

  • REAR 跟蹤隊列的最後一個元素

  • 最初,設定值爲 FRONT 和 REAR 至-1


入隊操做


  • 檢查隊列是否已滿

  • 對於第一個元素,設置爲 FRONT至0

  • 增長 REAR 索引1

  • 在由指向的位置添加新元素 REAR


出隊操做


  • 檢查隊列是否爲空

  • 返回所指向的值 FRONT

  • 增長 FRONT 索引1

  • 對於最後一個元素,重置的值FRONT 和 REAR 至-1


入隊和出隊操做





Python,C和C ++中的隊列實現


C:


// Queue implementation in C

#include <stdio.h>
#include <stdlib.h>
#define SIZE 5

void enQueue(int value);
/*下面聲明的仍是沒有變量,是由於用全局變量代替了*/
void deQueue();
void display();

//定義數組全局變量
int items[SIZE], front = -1, rear = -1;


void enQueue(int value)
{
    //若是隊列後面的已經滿了,此時size就不能繼續入隊列
    if (rear == SIZE - 1)
        printf("\nQueue is Full!!");
    else
    {
        if (front == -1)
            front = 0;
        rear++;//則繼續向前遞增
        items[rear] = value;//繼續插入入棧元素
        printf("\nInserted -> %d", value);
    }
}

void deQueue()
{
    //出列
    if (front == -1)
        printf("\nQueue is Empty!!");
    else
    {
        printf("\nDeleted : %d", items[front]);
        front++;
        if (front > rear)
            front = rear = -1;
    }
}

// Function to print the queue
void display()
{
    if (rear == -1)
        printf("\nQueue is Empty!!!");
    else
    {
        int i;
        printf("\nQueue elements are:\n");
        for (i = front; i <= rear; i++)
            printf("%d ", items[i]);
    }
    printf("\n");
}

int main()
{
    //deQueue is not possible on empty queue
    deQueue();

    //enQueue 5 elements
    enQueue(1);
    enQueue(2);
    enQueue(3);
    enQueue(4);
    enQueue(5);

    //6th element can't be added to queue because queue is full
    enQueue(6);//超過了size[5]的個數範圍

    display();//隊列索引對應的元素

    //deQueue removes element entered first i.e. 1
    deQueue();

    //Now we have just 4 elements
    display();//展現移除後的對立

    /*再出一次隊列*/
    deQueue();
    display(); //展現移除後的對立

    system("pause");
    return 0;
}


執行結果:


C++



// Queue implementation in C++

#include <iostream>
#define SIZE 5

using namespace std;

class Queue
{

private:
    int items[SIZE], front, rear;

public:
    Queue()
    {
        front = -1;
        rear = -1;
    }

    bool isFull()
    
{
        if (front == 0 && rear == SIZE - 1)
        {
            return true;
        }
        return false;
    }

    bool isEmpty()
    
{
        if (front == -1)
            return true;
        else
            return false;
    }

    void enQueue(int element)
    
{
        if (isFull())
        {
            cout << "Queue is full";
        }
        else
        {
            if (front == -1)
                front = 0;
            rear++;
            items[rear] = element;
            cout << endl
                 << "Inserted " << element << endl;
        }
    }

    int deQueue()
    
{
        int element;
        if (isEmpty())
        {
            cout << "Queue is empty" << endl;
            return (-1);
        }
        else
        {
            element = items[front];
            if (front >= rear)
            {
                front = -1;
                rear = -1;
            } /* Q has only one element, so we reset the queue after deleting it. */
            else
            {
                front++;
            }
            cout << endl
                 << "Deleted -> " << element << endl;
            return (element);
        }
    }

    void display()
    
{
        /* Function to display elements of Queue */
        int i;
        if (isEmpty())
        {
            cout << endl
                 << "Empty Queue" << endl;
        }
        else
        {
            cout << endl
                 << "Front index-> " << front;
            cout << endl
                 << "Items -> ";
            for (i = front; i <= rear; i++)
                cout << items[i] << " ";
            cout << endl
                 << "Rear index-> " << rear << endl;
        }
    }
};

int main()
{
    Queue q;

    //deQueue is not possible on empty queue
    q.deQueue();

    //enQueue 5 elements
    q.enQueue(1);
    q.enQueue(2);
    q.enQueue(3);
    q.enQueue(4);
    q.enQueue(5);

    //6th element can't be added to queue because queue is full
    q.enQueue(6);
    q.display();

    //deQueue removes element entered first i.e. 1
    q.deQueue();
    //Now we have just 4 elements
    q.display();

    //再移動一次
    q.deQueue();
    q.display();
    
    cin.get();
    return 0;
}



執行結果:


python:



# Circular Queue implementation in Python


class MyCircularQueue():

    def __init__(self, k):
        self.k = k
        self.queue = [None] * k
        self.head = self.tail = -1

    # Insert an element into the circular queue
    def enqueue(self, data):

        if ((self.tail + 1) % self.k == self.head):
            print("The circular queue is full\n")

        elif (self.head == -1):
            self.head = 0
            self.tail = 0
            self.queue[self.tail] = data
        else:
            self.tail = (self.tail + 1) % self.k
            self.queue[self.tail] = data

    # Delete an element from the circular queue
    def dequeue(self):
        if (self.head == -1):
            print("The circular queue is empty\n")

        elif (self.head == self.tail):
            temp = self.queue[self.head]
            self.head = -1
            self.tail = -1
            return temp
        else:
            temp = self.queue[self.head]
            self.head = (self.head + 1) % self.k
            return temp

    def printCQueue(self):
        if(self.head == -1):
            print("No element in the circular queue")

        elif (self.tail >= self.head):
            for i in range(self.head, self.tail + 1):
                print(self.queue[i], end=" ")
            print()
        else:
            for i in range(self.head, self.k):
                print(self.queue[i], end=" ")
            for i in range(0, self.tail + 1):
                print(self.queue[i], end=" ")
            print()


# Your MyCircularQueue object will be instantiated and called as such:
obj = MyCircularQueue(5)
obj.enqueue(1)
obj.enqueue(2)
obj.enqueue(3)
obj.enqueue(4)
obj.enqueue(5)
print("Initial queue")
obj.printCQueue()

obj.dequeue()
print("After removing an element from the queue")
obj.printCQueue()

執行結果:

如您在下圖中所看到的,在進行一些入隊和出隊後,隊列的大小已減少。


隊列限制



只有當全部元素都已出隊後,才能在重置隊列後使用索引0和1。


後 REAR到達最後一個索引,若是咱們能夠將多餘的元素存儲在空白處(0和1),則能夠利用這些空白處。這是經過一個稱爲循環隊列的修改隊列來實現的 。



複雜度分析

使用數組的隊列中入隊和出隊操做的複雜度爲O(1)




隊列數據結構的應用


  • CPU調度,磁盤調度

  • 在兩個進程之間異步傳輸數據時。隊列用於同步。例如:IO緩衝區,管道,文件IO等

  • 實時系統中的中斷處理。

  • 呼叫中心電話系統使用隊列來令人們按順序呼叫




 

參考文獻

https://blog.csdn.net/weixin_41194129/article/details/109281031https://blog.csdn.net/weixin_41194129https://www.zhihu.com/people/zhou-kang-9-28


本文分享自微信公衆號 - AI科技與算法編程(kangsinx)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索