在结构化存储数据集是常常使用数组即顺序表,但当数据庞大时用数组往往比较繁琐,例如我需要在数组中间添加一个元素进去,则需要移动很多个元素,而且在定义数组大小时,小了会溢出,大了会浪费。
而链表正是代替数组解决了这些问题。
链表可以在O(1)的复杂度下处理删除,添加等问题,而且可以用指针来动态分配存储空间,不会出现空间浪费的情况
例子:
编写一个Stack的用例,从输入中读取一个文本流并使用栈判定其中的括号是否配对完整。
例如:对于[()]{}{[()()]()}程序应该打印true,对于[(])则打印false.
问题分析:
这是一道栈的典型问题,利用栈“先进后出”的特性,在这个[(){}{()}中从左到右遍历,遇到左括号“[”,“(”,“{”就一一放进栈里面,每遇到一个右括号“(”,“[”,“{”就把栈顶的元素取出来对比是否为它的“伴侣”。如果不是直接就是可以“false”。
用链表来建立栈图示:
●—●—●—●
↑ ↑
next 栈顶
添加一个元素
●—●—●—●—●
↑ ↑
原栈顶 栈顶
next
●代表结点,->代表指向结点
代码详解:
#include<iostream>
using namespace std;
template<class Item>//Item可以是任意数据类型
struct Node
{
Item item;
Node *next;//指向栈顶的前一个
};
template<class Item>//每次用都需要在模板前写上这个
class Stack
{
private:
Node<Item> *first;//栈顶
Item N;//数量
public:
Stack()//构造函数
{
N = 0;
first = NULL;
}
bool isEmpty()//判断栈是否为空
{
return first == NULL ? 0 : 1;
}
//由于栈的先进后出,此处采用的是下压堆栈
void push(int items)//添加元素
{
Node<Item> *oldfirst = first;//建立一个新的结点记录原来的栈顶
first = new Node<Item>();//建议一个新的结点记录新加进来的元素
first->item = items;
first->next = oldfirst;//此时栈顶的前一个是原来的栈顶oldfirst
N++;
}
Item pop()//删除元素
{
if (isEmpty())
{
Item item = first->item;
first = first->next;
N--;
return item;
}
else
return 0;
}
void setpop()
{
while (isEmpty())
{
first = first->next;
N--;
}
}
};
int main()
{
Stack <int>A;
int a[126] = { 0 };
int flag;
//把每一个左括号都标志为1
a[40] = 1;
a[91] = 1;
a[123] = 1;
char s[100];
while (cin >> s)
{
flag = 1;
int len = strlen(s);
for (int i = 0; i < len; i++)
{
if (a[s[i]])//如果是左括号就入栈
{
A.push(s[i]);
}
//如果是右括号就取出栈顶的位置来判断是否匹配
else
{
int t = A.pop();
if (s[i] == t + 1 || s[i] == t + 2) continue;
else
{
flag = 0;
break;
}
}
}
if (!A.isEmpty() && flag)
cout << "Yes" << endl;
else
{
cout << "No" << endl;
A.setpop();
}
}
return 0;
}