1、相关概念
1.1、模拟指针的定义
模拟指针可以理解为:在一个模拟空间中,存在一个指针数组,数组中的每个元素为指针类型,并且每个指针具有数据域和链接域(指向下一个数组中的指针)。
1.2、模拟指针描述单链表、间接寻址描述单链表及普通单链表之间的区别:
- 普通单链表中,各个节点没有索引值;
- 间接寻址描述单链表时,各个节点间的索引值满足一定的数学关系;
- 模拟指针描述单链表时,各个节点的索引值不用满足一定的数学关系,但每个节点的索引值唯一。
2、模拟指针的类定义及实现
利用C++语言,实现模拟指针的类定义,包括模拟空间类SimSpace和模拟节点类SimNode。初始时,模拟空间中存放了所有的节点(MaxSize个)。为了在模拟空间中实现模拟指针,那么,就必须在需要新节点的时候申请一个指向该节点的指针(从模拟空间中取出一个节点);同理,在不需要此节点的时候释放此节点的指针(向模拟空间中放入一个节点)。相当于C++函数new和delete。在程序中,利用Allocate()函数和Deallocate()函数实现。为了简单起便,上述操作在模拟空间的前部进行。
2.1 模拟指针的类定义
template <class T> class SimSpace;
template <class T> class SimChain;
template <class T>
class SimNode
{
friend SimSpace<T>; //友类模拟空间类
friend SimChain<T>; //友类模拟链表类
private:
T data; //数据
int link; //指向下一个元素
};
template <class T> class SimChain;
template <class T>
class SimSpace
{
friend SimChain<T>;
public:
SimSpace(int MaxSize=100);
~SimSpace();
int Allocate(); //取出一个节点
void Deallocate(int &i); //放入第i个节点
private:
int NumberOfNodes, frist; //NumberOfNodes为节点数目,frist为首节点索引值
SimNode<T> *node; //节点数组
};
2.2 成员函数实现
2.2.1 申请新的模拟空间
通过SimSpace类的构造函数实现。
template <class T>
SimSpace<T>::SimSpace(int MaxSize)
{
NumberOfNodes = MaxSize; //初始时,所有节点都是自由的
node = new SimNode<T>[NumberOfNodes]; //建立所有的节点,包括节点数据和指向下一节点的指针
for (int i = 0; i < NumberOfNodes - 1; i++)
node[i].link = i + 1;
//第一个节点
frist = 0;
//最后一个节点
node[NumberOfNodes - 1].link = -1;
}
template <class T>
2.2.2 释放模拟空间
通过SimSpace类的析构函数实现。
template <class T>
SimSpace<T>::~SimSpace()
{
delete[] node;
}
2.2.3 申请新的模拟指针
通过”int Allocate()”函数实现。函数返回申请后的节点索引值。
//取出一个节点
template <class T>
int SimSpace<T>::Allocate()
{
if (frist == -1) throw NoMerm();
int i = first;
first=node[i].link;
return i;
}
2.2.4 释放节点i的模拟指针
通过”void Dellocate()”实现。
//向模拟空间中放入第i个节点
template <class T>
void SimSpace<T>::Deallocate(int &i)
{
if (i >= 0 && i <= NumberOfNodes) //合法输入
{
frist = i;
node[i].link = frist;
i = -1;
}
else
throw OutOfRange();
}
3、模拟链表
利用模拟指针操作单链表,包括以下操作:
下面分别说明:
3.1 模拟链表类的定义
在类的定义中,关于模拟链表的创建和删除已经实现。
//模拟链表类
template <class T>
class SimChain
{
public:
SimChain() { frist = -1; } //给定首节点索引值
~SimChain() { Destroy(); }
void Destroy(); //清空表
int Length() const; //返回链表长度
//寻找第k个位置的元素,若存在,则将值赋给x,并返回true;否则,返回false
bool Find(int k, T &x) const;
//寻找列表中值为x的元素,若存在,则返回位置,否则,返回0
int Search(const T &x);
//删除表中第k个元素,并將值赋给x,并返回操作后的列表
SimChain<T>& Delete(int k, T &x);
//在第k个位置之后插入元素x,并并返回操作后的列表
SimChain<T>& Insert(int k, const T &x);
//输出列表函数
void Output(ostream &out) const;
private:
int frist; //第一个节点的索引
static SimSpace<T> S; //静态对象存在于共享存储空间,可使所有类型为T的模拟链表共享模拟空间S
};
3.2 释放所有节点
析构函数通过调用此Destroy()函数,实现对模拟链表对象的析构。
template <class T>
void SimChain<T>::Destroy() //释放链表所有节点
{
int next;
while (frist!=-1) //frist不是最后一个节点
{
next = S.node[frist].link; //指向下一个节点
frist = next; //迭代
}
}
3.3 获取链表长度
//返回链表长度
template <class T>
int SimChain<T>::Length() const
{
int current = frist; //当前节点指向首节点
int len = 0; //元素计数
while (current!=-1) //当前节点不是最后一个节点
{
current = S.node[current].link; //指向当前节点的下一个节点
len++;
}
return len;
}
3.4 寻找第k个位置的元素
寻找第k个位置的元素,若存在,则将值赋给x,并返回true;否则,返回false
//寻找第k个位置的元素,若存在,则将值赋给x,并返回true;否则,返回false
template <class T>
bool SimChain<T>::Find(int k, T &x) const
{
if (k > 0)
{
int current = frist; //获取当前节点
int index = 1; //节点索引值
while (index < k && current != -1) //移至第k个节点,且不为最后一个节点
{
current = S.node[current].link;
index++;
}
x = S.node[current].data;
return true;
}
else
return false;
}
3.5 寻找列表中值为x的元素
寻找列表中值为x的元素,若存在,则返回位置,否则,返回0
//寻找列表中值为x的元素,若存在,则返回位置,否则,返回0
template <class T>
int SimChain<T>::Search(const T &x)
{
int current = frist; //获取当前位置
while (current != -1) //未到末节点
{
if (x == S.node[current].data)
return current+1;
current = S.node[current].link; //指向下一节点
}
return 0;
}
3.6 删除表中第k个元素
删除表中第k个元素,并將值赋给x,并返回操作后的列表
//删除表中第k个元素,并將值赋给x,并返回操作后的列表
template <class T>
SimChain<T>& SimChain<T>::Delete(int k, T &x)
{
if (k < 1 || frist == -1) //不存在第k个元素
throw OutOfRange();
else
{
if (k == 1) //删除第一个节点
{
x = S.node[k-1].data; //将首节点元素赋给x
frist = S.node[k-1].link; //将下一节点作为首节点,即删除首节点
}
else
{
int index = 1; //索引值
int current = frist;
while (index < k - 1 && current != -1) //移至第k-1个位置
{
current = S.node[current].link; //指向下一个节点
index++;
}
if (current == -1 || S.node[current].link == -1)
throw OutOfRange();
int p = S.node[current].link; //指向第k个节点
x = S.node[p].data; //获取第k个元素值
S.node[current].link = S.node[p].link; //删除第k个元素
S.Deallocate(p); //释放空间
}
}
return *this;
}
3.7 在第k个位置之后插入元素x
在第k个位置之后插入元素x,并返回操作后的列表
//在第k个位置之后插入元素x,并返回操作后的列表
template <class T>
SimChain<T>& SimChain<T>::Insert(int k, const T &x)
{
if (k < 0)
throw OutOfRange();
int current = frist; //获取当前位置
int index = 1; //索引值
while (current!=-1 && index<k) //移动到第k个节点
{
current = S.node[current].link; //指向下一节点
index++;
}
if (k>0 && current == -1) //不是在首节点插入,当前指针不能为末节点
throw OutOfRange();
int after = S.node[current].link; //指向原来的第k+1个节点
int p = S.Allocate(); //分配一个新节点
S.node[p].data = x; //给新节点赋值
if (k) //不是首节点
{
S.node[current].link = p; //原来第k个节点指向分配的新节点
S.node[p].link = after; //新分配的节点指向原来的第k+1个节点
}
else //首节点
{
S.node[p].link = frist;
frist = p;
}
return *this;
}
3.8 输出模拟链表
通过重载运算符”<<”实现。
//输出链表函数
//重载运算符 "<<"
template <class T>
inline ostream &operator <<(ostream &out, SimChain<T> &S)
{
S.Output(out);
return out;
}
template <class T>
void SimChain<T>::Output(ostream &out) const
{
int current = frist;
while (current != -1)
{
cout << S.node[current].data << " ";
current = S.node[current].link;
}
}
4. 测试样例
//模拟链表
SimChain<int> S;
S.Insert(0, 1);
cout <<"S.Insert(0, 1): "<< S << endl<<endl;
S.Insert(1, 5);
cout << "S.Insert(1, 5): " << S << endl << endl;
for (int i = 2; i < 7; i++)
S.Insert(i, i);
cout << "测试Insert()函数: " << S << endl << endl;
int x;
S.Delete(3, x);
cout << "测试Delete()函数,删除中间元素: " << S <<" "<<x<< endl << endl;
S.Delete(1, x);
cout << "测试Delete()函数,删除首元素: " << S << " " << x << endl << endl;
S.Delete(S.Length(), x);
cout << "测试Delete()函数,删除末元素: " << S << " " << x << endl << endl;
bool find;
find=S.Find(1, x);
cout << "测试Find()函数,寻找首元素: " << find << " " << x << endl << endl;
find = S.Find(0, x);
cout << "测试Find()函数,寻找位置为0元素: " << find << " " << x << endl << endl;
find = S.Find(S.Length(), x);
cout << "测试Find()函数,寻找末元素: " << find << " " << x << endl << endl;
cout << "测试Search()函数: " << S.Search(5) << endl << endl;
参考文献:
[1] 数据结构算法与应用:C++描述(Data Structures, Algorithms and Applications in C++ 的中文版)