数据结构库——链式栈的实现

1,顺序栈的缺点:

       1,顺序栈的存储空间使用的原生数组,但是原生数组作为存储空间的时候,在初始化的时,会调用相应类型的构造函数;这样即使不存储任何元素(m_size = 0),也会使得在定义栈的时候,先构造出 N 个大小为 T 的类型的空间出来,非常浪费效率;

  2,代码如下:

 1 #include <iostream>
 2 #include "StaticStack.h"
 3 
 4 using namespace std;
 5 using namespace DTLib;
 6 
 7 class Test : public Object
 8 {
 9 public:
10     Test()
11     {
12         cout << "Test()" << endl;
13    }
14 
15     ~Test()
16     {
17         cout << "~Test()" << endl;
18     }
19 };
20 
21 int main()
22 {
23     StaticStack<int> ls;    
24    cout << ls.size() << endl;
25 
26     return 0;
27 }

         

2,链式栈的存储实现:

  

       1,本质是链表;

       2,采用和链表一样的实现方式,定义一个 top 指针(链表用指针,数组用下标),始终指向链表的首元素;

      

3,链式栈的设计要点:

       1,类模板,抽象父类 Static 的直接子类;

              1,容器,所以要用模板;

       2,在内部组合使用 LinkList 类,实现栈的链式存储;

              1,组合使用,代码复用;

       3,只在单链表成员对象的头部进行操作;

              1,不管是入栈还是出栈,仅操作下表为 0 的结点;

             

4,链式栈的设计要点:

 

      

5,编程实现链式栈;

 1 #ifndef LINKSTACK_H
 2 #define LINKSTACK_H
 3 
 4 #include "Stack.h"
 5 #include "LinkList.h"
 6 #include "Exception.h"
 7 
 8 namespace DTLib
 9 {
10 
11 template <typename T>
12 class LinkStack : public Stack<T>
13 {
14 protected:
15     LinkList<T> m_list;  // 组合使用单链表类,不用 m_top,因为用单链表的 0 下标时刻就能“指向”表头,也就是栈顶;不用 m_size,因为 m_list 里面有 m_length,可以代表链表长度;
16 public:
17     void push(const T& e)   // O(1)
18     {
19         m_list.insert(0, e);
20    }
21 
22     void pop()   // O(1)
23     {
24         if( m_list.length() > 0 )
25         {
26             m_list.remove(0);
27         }
28         else
29         {
30             THROW_EXCEPTION(InvalidOperationException, "No element in current LinkStack ...");
31         }
32    }
33 
34     T top() const   // O(1)
35     {
36         if( m_list.length() > 0 )
37         {
38             return m_list.get(0);
39         }
40         else
41         {
42             THROW_EXCEPTION(InvalidOperationException, "No elementin current LinkStack ...");
43         }
44    }
45 
46     void clear()   // O(n)
47     {
48             m_list.clear();
49    }
50 
51     int size() const  // O(1)
52     {
53         return m_list.length();
54     }
55 };
56 
57 }
58 
59 #endif // LINKSTACK_H

 

6,栈的应用实践:

       1,符号匹配问题:

              1,在 C 语言中,有一些成对匹配出现的符号;

                     1,括号:()/[]/{}/<>

                     2,引号:''/""(左符号和右符号相同)

       2,编译器如何实现符号成对检测?

              1,算法思路:

                     1,从第一个字符开始扫描:

                            1,当遇见普通字符时忽略;

                            2,当遇见左括号时压入栈中;

                            3,当遇见右括号时弹出栈顶符号,并进行匹配;

                     2,结束:

                            1,成功:所有字符扫描完毕,且栈为空;

                            2,失败:匹配失败或所有字符扫描完毕但栈非空;

 

7,符号匹配的链式检测:

 1 #include <iostream>
 2 #include "LinkStack.h"
 3 
 4 using namespace std;
 5 using namespace DTLib;
 6 
 7 bool is_left(char c)
 8 {
 9     return (c == '(') || (c == '[') || (c == '{') || (c == '<');    // 字符本质是指针, 字符串本质是变量
10 }
11 
12 bool is_right(char c)
13 {
14     return (c == ')') || (c == ']') || (c == '}') || (c == '>');
15 }
16 
17 bool is_quot(char c)
18 {
19     return (c == '\'') || (c == '\"');
20 }
21 
22 bool is_match(char l, char r)
23 {
24     return ( (l == '(') && (r == ')') ) ||
25            ( (l == '{') && (r == '}') ) ||
26            ( (l == '[') && (r == ']') ) ||
27            ( (l == '<') && (r == '>') ) ||
28            ( (l == '\'') && (r == '\'') ) ||
29            ( (l == '\"') && (r == '\"') );
30 }
31 
32 bool scan(const char* code)
33 {
34     LinkStack<char> stack;
35     int i = 0;
36     bool ret = true;
37    code = (code == NULL) ? " " : code;   // 判断参数是否为空,为什么为空了就要赋值为 “ ”, 字符串数组的真是属性到底是什么?
38 
39     while( ret && (code[i] != '\0'))      // 以字符访问字符串
40     {
41         if( is_left(code[i]) )
42         {
43             stack.push(code[i]);
44         }
45         else if( is_right(code[i]) )
46         {
47             if( (stack.size() > 0) && is_match(stack.top(), code[i]) )
48             {
49                 stack.pop();
50             }
51             else
52             {
53                 ret = false;      // 这里通过“真假”判断
54             }
55         }
56         else if( is_quot(code[i]) )
57         {
58             if( (stack.size() == 0) || !is_match(stack.top(), code[i]) )
59             {
60                 stack.push(code[i]);     // 这里通过栈“空否”可以判断
61             }
62             else if( is_match(stack.top(), code[i]) )
63             {
64                 stack.pop();
65             }
66         }
67         i++;
68    }
69 
70     return ret && (stack.size() == 0);  // “真假”是为了匹配前四种、 而“空否”是为了后两种
71 }
72 
73 int main()
74 {
75    cout << scan() << endl;
76 
77     return 0;
78 }

                    

8,小结:

       1,链式栈的实现组合使用了单链表对象;

       2,在单链表的头部进行操作能够实现高效的入栈和出栈的操作;

       3,栈“后进先出”的特性适用于检测成对出现的符号;

       4,栈非常适合于需要“就近匹配”的场合;

转载于:https://www.cnblogs.com/dishengAndziyu/p/10923061.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值