数据结构整理(二) —— 栈和队列

抵制转载并改了作者名的流氓行为,博客地址:http://www.cnblogs.com/wolfred7464/

书接上文,继续线性表。这次写一下栈和队列的简单实现和部分应用。队列的应用比较简单一些,就像现实中排队一样一样的,就不做过多赘述,主要说一下循环队列的实现,即重用已出队的空间。栈的实现也很简单,这里主要说一下栈的2种常见应用——括号匹配,算数表达式求值。

好了,先说栈吧。栈是一个后进先出的结构,只要保证后进先出,怎么实现都可以,关于代码没太多可说的,下面是一个简单的实现,简单是因为没考虑过多错误处理和动态增长。因为代码量少,所以函数的声明和定义写到一块了:

 1 template <typename T>

 2 class Stack {

 3 private:

 4     int sp;

 5     T* _stack;

 6 public:

 7     Stack(int cap = 1024) {

 8         sp = 0;

 9         _stack = new T[cap];

10     }

11     ~Stack() {

12         delete[] _stack;

13     }

14     void push(const T& x) {

15         _stack[sp++] = x;

16     }

17     void pop() {

18         sp--;

19     }

20     const T& top() {

21         return _stack[sp-1];

22     }

23     void clear() {

24         sp = 0;

25     }

26     inline int size() {

27         return sp;

28     }

29 };

利用后进先出的特点,可以利用栈做到函数的递归调用,线程切换等,不过这是操作系统考虑的问题了。这里说一下2个简单的应用。

先说括号匹配,括号匹配就是给出一个字符串,判断字符串中的括号是否是匹配的,例如"sin(a+b)"是匹配的,但是"哈哈:)"就是不匹配的。利用栈,我们把暂时未匹配的前半边括号入栈,当读取到后半边括号且能与栈顶的前半边匹配时,栈顶弹出,完成一个匹配。最好如果栈空,则是匹配的,反之不匹配。代码很简单:

 1 bool brace_match(const char* str) {

 2     Stack<char> s;

 3     for(int i = 0; str[i] != '\0'; i++) {

 4         if(strchr("()[]{}", str[i]) != NULL) {

 5             if(str[i] == ')' && s.size() > 0 && s.top() == '(') {

 6                 s.pop();

 7             } else if(str[i] == ']' && s.size() > 0 && s.top() == '[') {

 8                 s.pop();

 9             } else if(str[i] == '}' && s.size() > 0 && s.top() == '{') {

10                 s.pop();

11             } else {

12                 s.push(str[i]);

13             }

14         }

15     }

16     return !s.size();

17 }
利用栈检测括号匹配
1 void test_brace_match() {

2     cout << brace_match("sin(20+10)") << endl;

3     cout << brace_match("{[}]") << endl;

4 }
单元测试

另一个应用是算数表达式求值,就是给出一个四则运算和小括号组成的算数表达式,按照数学上的优先级计算表达式的结果。就是利用后缀式的做法。我的代码利用2个栈,一个是数字栈,一个是运算符栈,遵循一个简单的规则:

1,数字入数字栈。

2,运算符栈空时,运算符入栈。

3,当前运算符优先级大于栈顶优先级,入栈。

4,左括号"("入栈。

5,读到右括号时,运算符栈依次弹出直到遇到左括号。

6,读取完成后,运算符栈依次全部出栈。

 1 class Evaluation {

 2 private:

 3     Stack<char> s_op;

 4     Stack<int> s_num;

 5     // 比较优先级,判断是否应该入栈

 6     bool op_cmp(char op_sp, char op_cur);

 7     // 计算数字栈顶2个数的结果,结果入栈

 8     void calc(char op);

 9 public:

10     int evaluate(const char* str);

11 };

12 

13 

14 bool Evaluation::op_cmp(char op_sp, char op_cur) {

15     if(op_sp == '(' || op_cur == '(') {

16         return true;

17     } else if((op_cur == '*' || op_cur == '/') && (op_sp == '+' || op_sp == '-')) {

18         return true;

19     }

20     return false;

21 }

22 

23 void Evaluation::calc(char op) {

24     int y = s_num.top();

25     s_num.pop();

26     int x = s_num.top();

27     s_num.pop();

28     switch(op) {

29         case '+':

30             x += y; break;

31         case '-':

32             x -= y; break;

33         case '*':

34             x *= y; break;

35         case '/':

36             x /= y; break;

37     }

38     s_num.push(x);

39 }

40 

41 int Evaluation::evaluate(const char* str) {

42     s_op.clear();

43     s_num.clear();

44 

45     int i = 0;

46     while(str[i] != '\0') {

47         char c = str[i++];

48         if(c >= '0' && c <= '9') {

49             int num = c - '0';

50             while((c = str[i]) != '\0') {

51                 if(c >= '0' && c <= '9') {

52                     num = num * 10 + c - '0';

53                     i++;

54                 } else {

55                     break;

56                 }

57             }

58             s_num.push(num);

59         } else if(c == ')') {

60             char op = s_op.top();

61             s_op.pop();

62             while(op != '(') {

63                 calc(op);

64                 op = s_op.top();

65                 s_op.pop();

66             }

67         } else if(s_op.size() == 0 || op_cmp(s_op.top(), c)) {

68             s_op.push(c);

69         } else {

70             while(s_op.size() > 0 && !op_cmp(s_op.top(), c)) {

71                 calc(s_op.top());

72                 s_op.pop();

73             }

74             s_op.push(c);

75         }

76     }

77     while(s_op.size() > 0) {

78         calc(s_op.top());

79         s_op.pop();

80     }

81     return s_num.top();

82 }
利用栈进行算数表达式求值
1 void test_evaluation() {

2     Evaluation e;

3     cout << e.evaluate("1+2*3") << endl;

4     cout << e.evaluate("(1+2)*3") << endl;

5     cout << e.evaluate("1+2*3+4+5*2") << endl;

6     cout << e.evaluate("1+2*3+(4+5*2)") << endl;

7     cout << e.evaluate("1+2*3+((4+5)*2)") << endl;

8 }
单元测试

 

栈的内容先说这些,接下来是队列。由于队列的实现和应用都比较简单,这里只说一下如何实现循环队列,重用已出队的空间,提高效率。循环队列和一般队列一样,只要保证先进先出,并且保证尾结点的后置结点是头结点就可以,用数组,链表,或者其它方式实现都可以,这里我用循环链表演示一下,为了简化编码,数据类型用int,而没有用template:

 1 class Circularqueue {

 2 private:

 3     Node* head;

 4     Node* rear;

 5     int lenth;

 6 public:

 7     Circularqueue(int cap = 128);

 8     ~Circularqueue();

 9     void enqueue(int data);

10     void dequeue();

11     int front();

12     void clear();

13     inline int size();

14 };

15 

16 Circularqueue::Circularqueue(int cap) {

17     lenth = 0;

18     head = new Node();

19     rear = head;

20     for(int i = 1; i < cap; i++) {

21         Node* node = new Node();

22         rear->next = node;

23         rear = node;

24     }

25     rear->next = head;

26     rear = head;

27 }

28 

29 Circularqueue::~Circularqueue() {

30     Node* cur = head->next;

31     while(cur != nullptr) {

32         delete head;

33         head = cur;

34         cur = cur->next;

35     }

36     delete head;

37 }

38 

39 void Circularqueue::enqueue(int data) {

40     rear->data = data;

41     rear = rear->next;

42     lenth++;

43 }

44 

45 void Circularqueue::dequeue() {

46     head = head->next;

47     lenth--;

48 }

49 

50 int Circularqueue::front() {

51     return head->data;

52 }

53 

54 void Circularqueue::clear() {

55     lenth = 0;

56     rear = head;

57 }

58 

59 int Circularqueue::size() {

60     return lenth;

61 }
循环队列

 

你可能感兴趣的:(数据结构)