【數據結構】35_棧的概念及實現 (下)

順序棧的問題

當存儲的元素類型爲類類型,StaicStack 的對象在建立時會屢次調用元素類型的構造函數,影響效率!ios

文件:main.cpp算法

#include <iostream>
#include "StaitcStack.h"

using namespace std;
using namespace DTLib;

class Test : public Object
{
public:
    Test()
    {
        cout << "Test()" << endl;
    }

    ~Test()
    {
        cout << "~Test()" << endl;
    }
};

int main()
{
    StaticStack<Test, 5> stack;

    cout << "stack.size() = " << stack.size() << endl;

    return 0;
}

輸出:編程

Test()
Test()
stack.size() = 0
~Test()
~Test()
~Test()
~Test()
~Test()
緣由: T m_space[N];

鏈式棧的存儲實現

image.png

鏈式棧的設計要點

  • 類模板,抽象父類 Stack 的直接子類
  • 在內部組合使用 LinkList 類,實現棧的鏈式存儲
  • 只在單鏈表成員對象的頭部進行操做

image.png

編程實驗:基於鏈式存儲結構的棧

文件:LinkStack.hide

#ifndef LINKSTACK_H
#define LINKSTACK_H

#include "Stack.h"
#include "LinkList.h"
#include "Exception.h"

namespace DTLib
{

template <typename T>
class LinkStack : public Stack<T>
{
public:
    void push(const T &e) override  // O(1)
    {
        m_list.insert(0, e);
    }

    void pop() override  // O(1)
    {
        if (m_list.length() > 0)
        {
            m_list.remove(0);
        }
        else
        {
            THROW_EXCEPTION(InvalidOpertionExcetion, "No element in current LinkStack ...");
        }
    }

    T top() const override  // O(1)
    {
        if (m_list.length() > 0)
        {
            return m_list.get(0);
        }
        else
        {
            THROW_EXCEPTION(InvalidOpertionExcetion, "No element in current LinkStack ...");
        }
    }

    void clear() override  // O(n)
    {
        m_list.clear();
    }

    int size() const override  // O(1)
    {
        return m_list.length();
    }

    ~LinkStack()  // O(n)
    {
        clear();
    }

protected:
    LinkList<T> m_list;
};

}

#endif // LINKSTACK_H

文件:main.cpp函數

#include <iostream>
#include "LinkStack.h"

using namespace std;
using namespace DTLib;

class Test : public Object
{
public:
    Test()
    {
        cout << "Test()" << endl;
    }

    ~Test()
    {
        cout << "~Test()" << endl;
    }
};

int main()
{
    LinkStack<Test> stack_1;

    cout << "stack_1.size() = " << stack_1.size() << endl;

    cout << "-------" << endl;

    LinkStack<int> stack_2;

    for (int i=0; i<5; ++i)
    {
        stack_2.push(i);
    }

    while (stack_2.size() > 0)
    {
        cout << stack_2.top() << endl;
        stack_2.pop();
    }

    return 0;
}

輸出:spa

stack_1.size() = 0
-------
4
3
2
1
0

棧的應用實踐

符號匹配問題

在 C 語言中有一些成對匹配出現的符號

括號: (), [], {}, <>
引號: '', ""設計

問題: 如何實現編譯器中的符號成對檢測?

算法思路

  • 從第一字符開始掃描code

    • 當碰見普通字符時忽略
    • 當碰見左符號時壓入棧中
    • 當碰見右符號時彈出棧頂符號,並進行匹配
  • 結束對象

    • 成功:全部字符掃描完畢,且棧爲空
    • 失敗:匹配失敗或全部字符掃描完畢但棧非空

編程實驗:符號匹配問題

文件:main.cppblog

#include <iostream>
#include "LinkStack.h"

using namespace std;
using namespace DTLib;

bool is_left(char c)
{
    return (c == '(') || (c == '{') || (c == '[') || (c == '<');
}

bool is_right(char c)
{
    return (c == ')') || (c == '}') || (c == ']') || (c == '>');
}

bool is_quot(char c)
{
    return (c == '\'') || (c == '\"');
}

bool is_macth(char l, char r)
{
    return ((l == '(') && (r == ')')) ||
           ((l == '{') && (r == '}')) ||
           ((l == '[') && (r == ']')) ||
           ((l == '<') && (r == '>')) ||
           ((l == '\'') && (r == '\'')) ||
           ((l == '\"') && (r == '\"'));
}

bool scan(const char *code)
{
    bool ret = true;
    int i = 0;
    LinkStack<char> stack;

    code = (code == nullptr) ? "" : code;

    while (ret && code[i] != '\0')
    {
        if (is_left(code[i]))
        {
            stack.push(code[i]);
        }
        else if (is_right(code[i]))
        {
            if ((stack.size() > 0) && is_macth(stack.top(), code[i]))
            {
                stack.pop();
            }
            else
            {
                ret = false;
            }
        }
        else if (is_quot(code[i]))
        {
            if (stack.size() == 0 || !is_macth(stack.top(), code[i]))
            {
                stack.push(code[i]);
            }
            else if (is_macth(stack.top(), code[i]))
            {
                stack.pop();
            }
        }

        ++i;
    }

    return ret && (stack.size() == 0);
}

int main()
{
    cout << scan("<a{b(\'x\')c}d>") << endl;

    return 0;
}

輸出:

1

小結

  • 鏈式棧的實現組合使用了單鏈表對象
  • 在單鏈表的頭部進行操做可以實現高效的入棧和出棧操做
  • 棧 「後進先出」 的特性適用於檢測成對出現的括號
  • 棧很是適合於須要 「就近匹配」 的場合

以上內容整理於狄泰軟件學院系列課程,請你們保護原創!

相關文章
相關標籤/搜索