前言
栈是基本的数据结构。其特点是添加和访问数据都在线性表的一端(头端)。数据访问遵循后出先进(LIFO)的原则。栈一般用数组或者链表来实现。数组需要静态分配数据空间,占用空间比较大。链表则根据实际需要动态分配数据空间,占用空间相对小一些。本文用单向链表实现栈。程序用C++实现。本文是C++、数据结构及算法学习的一个小小练习。供大家参考。
栈的操作
栈的操作主要就两个:入栈(push)和出栈(pop)。顾名思义,入栈就是将数据压入栈中保存;出栈就是将数据弹出栈,同时访问数据。
数据结构和算法描述
节点的结构
节点(Node)分为两部分,数据和链接部分。数据部分存储数据,可以根据实际情况分为若干字段。本文数据部分分两个字段:key和data。链接部分就是一个指针,指向下一个节点。然后让头指针指向第一个节点,这样一个链式的栈就形成了。C++代码如下:
struct Node {
int key;
string data;
Node *next=nullptr;
}
C++的结构允许有自己的构造函数,我们将上面的节点结构改写一下,包含构造函数:
struct Node {
int key;
string data;
Node *next=nullptr;
Node(int ky, string da, Node *nxt=nullptr) : key(ky), data(da), next(nxt) {};
}
算法描述
入栈和出栈的算法比较简单,直接用C++描述如下。
push(int ky, string da)
{
head=new Node(ky,da,head);
return;
}
pop(int &ky, string &da)
{
Node *p;
p=head;
if (nullptr!=head) {
ky=key;
da=data;
head=head->next;
delete p;
}
return;
}
类的定义
栈定义成一个类,其上定义了构造函数、析构函数、入栈(push)、出栈(pop)、判断空栈函数(isEmpty())以及指向链表头节点的指针head。C++代码如下:
class Stack
{
public:
Stack();
virtual ~Stack();
Stack(const Stack& other);
Stack& operator=(const Stack& other);
bool isEmpty() { return nullptr==head; }
void push(int ky, string da);
void pop(int &ky, string &da);
void pop();
protected:
private:
Node *head=nullptr;
};
程序清单及说明
除了以上类和结构的定义外,作为实验定义了数据读取函数readData(filename),从数据文件中读入实验数据并生成栈。主程序则对栈的操作做了相应试验。
全部程序清单如下:
#include <iostream>
#include <fstream>
using namespace std;
struct Node {
int key;
string data;
Node *next=nullptr;
Node(int ky, string da, Node *nxt=nullptr) : key(ky), data(da), next(nxt) {};
};
class Stack
{
public:
Stack();
virtual ~Stack();
Stack(const Stack& other);
Stack& operator=(const Stack& other);
bool isEmpty() { return nullptr==head; }
void push(int ky, string da);
void pop(int &ky, string &da);
void pop();
protected:
private:
Node *head=nullptr;
};
Stack::Stack()
{
head=nullptr;
}
Stack::~Stack()
{
while(!isEmpty()) { pop(); }
}
Stack::Stack(const Stack& other)
{
head=other.head;
}
Stack& Stack::operator=(const Stack& rhs)
{
if (this == &rhs) return *this;
head=rhs.head;
return *this;
}
void Stack::push(int ky, string da)
{
head=new Node(ky,da,head);
return;
}
void Stack::pop(int &ky, string &da)
{
Node *p=head;
if (!isEmpty()) {
ky=head->key;
da=head->data;
head=head->next;
delete p;
}
return;
}
void Stack::pop()
{
Node *p=head;
if (!isEmpty()) {
head=head->next;
delete p;
}
return;
}
Stack st;
int readData(string fn)
{
int itmsRead=0;
int k;
string str;
ifstream datafile(fn);
if (!datafile) {
itmsRead=-1;
}
else {
while (datafile >> k >> str) {
st.push(k,str);
itmsRead++;
}
}
return itmsRead;
}
int main()
{
int k;
string str;
int itms=0;
string datafilename="datafile.txt";
cout<<"Read data ... ";
itms=readData(datafilename);
if (-1==itms) {
cout << "404, File not found." << endl;
}
else {
cout<<itms<<" item(s) read."<<endl;
cout<<"Pop data ... "<<endl;
while (!st.isEmpty()) {
st.pop(k,str);
cout<<"("<<k<<", "<<str<<") ";
}
}
return 0;
}
小结
整个程序比较简单。唯一要注意的是指针的运用。一是要防止出现野指针。指针定义的时候要赋初值。二是操作指针前先要判断指针是否为空,以避免在空指针上操作。
附
供试验用的数据文件,datafile.txt。内容如下:
24 Xyz
2 Bcd
3 Cde
1 Abc
4 Def
10 Exa
22 Vwx
7 Ghi
8 Hij
9 Ijk
1 A
10 Jkl
5 Efg
24 Xz
11 Klm
12 Lmn
26 Z
13 Mno
25 Sam
1 Ab
14 Nop
6 Fgh
15 Opq
16 Pqr
1 bc
18 Rst
19 Stu
20 Tuv
24 Xy
21 Txt
17 Qrs
21 Uvw
23 Wxy
25 Yz