您的位置:首页 > 理论基础 > 数据结构算法

数据结构与算法C++描述(5)---模拟指针及模拟链表

2017-10-12 22:39 891 查看

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;

cou
cb33
t << "测试Search()函数:   " << S.Search(5) << endl << endl;


参考文献:

[1] 数据结构算法与应用:C++描述(Data Structures, Algorithms and Applications in C++ 的中文版)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息