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

1、相关概念

1.1、模拟指针的定义

模拟指针可以理解为:在一个模拟空间中,存在一个指针数组,数组中的每个元素为指针类型,并且每个指针具有数据域和链接域(指向下一个数组中的指针)。

1.2、模拟指针描述单链表、间接寻址描述单链表及普通单链表之间的区别:

  1. 普通单链表中,各个节点没有索引值;
  2. 间接寻址描述单链表时,各个节点间的索引值满足一定的数学关系;
  3. 模拟指针描述单链表时,各个节点的索引值不用满足一定的数学关系,但每个节点的索引值唯一。

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++ 的中文版)

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值