模拟指针,也就是清华严老师《数据结构-C语言描述》中的静态链表,静态链表的引用是使用一段连续的存储区还模拟指针的功能,可以有效的利用一段连续内存进行一定范围内可变的子链表的空间分配,此数据结构原理比较简单,但是实现起来(至少我个人感觉)有一些绕,原因在于结点的指针域和所申请的整个空间数组的下标都是用整型来表示,极易出错,由于使用连续存储区,稍有不甚将指针地址错写成数组下标则很容易出错并且很难被发现。

  以下为本次实现的模拟指针代码,由三个文件构成:

  1、 simulatedPointer.h     定义了模拟指针的一些基本结构和方法

  2、excp.h       和前面一样,包含定制的异常类。

  3、simulatedPointer.cp    测试用的主函数

 //simulatedPointer.h
#ifndef __SIMULATEDPOINTER__
#define __SIMULATEDPOINTER__
#include <iostream>
#include "excp.h"
using namespace std; template<class T>
class SimPointerList; template<class T>
class Node {
public:
friend class SimPointerList<T>;
private:
T data;
int next;
}; template<class T>
class SimPointerList {
public:
SimPointerList(int maxaSize = );
~SimPointerList(){delete [] list;}
int getFreeNode();
void recycleFreeNode(int i);
bool isEmpty() const;
int getLength() const;
SimPointerList<T>& deleteElement(int k, T& x);
SimPointerList<T>& insertElement(int k, const T& x);
void findElement(int k, T& x) const;
int searchElement(const T& x) const;
void output(ostream& out) const;
int getFreeCapacity() const;
private:
int freeHeader;//point to the head of the free-list
int usedHeader;
int maxSize;
Node<T> *list;
}; template<class T>
SimPointerList<T>::SimPointerList(int maxaSize)
{
maxSize = maxaSize;
freeHeader = ;
usedHeader = -;
list = new Node<T>[maxSize];
for (int i=; i<maxSize-;i++)
list[i].next = i+;
list[maxSize-].next = -;
} template<class T>
int SimPointerList<T>::getFreeNode()
{
if (freeHeader == -)
throw FullMemory();
int i = freeHeader;
freeHeader = list[i].next;
list[i].next=-;
return i;
} template<class T>
void SimPointerList<T>::recycleFreeNode(int i)
{
if (i< || i>=maxSize)
throw OutOfBounds();
list[i].next = freeHeader;
freeHeader = i;
} template<class T>
bool SimPointerList<T>::isEmpty() const
{
return usedHeader == -;
} template<class T>
int SimPointerList<T>::getLength() const
{
int len = ;
if (usedHeader != -)
for (int begin=usedHeader; begin!=-; begin=list[begin].next)
len++;
return len;
} template<class T>
SimPointerList<T>& SimPointerList<T>::deleteElement(int k, T& x)
{
if (k<= || k>getLength())
throw OutOfBounds();
int index = ;
if (k == )
{
index = usedHeader;
usedHeader = list[usedHeader].next;
}
else if (getLength()== && k == )
{
index = list[usedHeader].next;
list[usedHeader].next = -;
}
else
{
int prior = usedHeader;
for (int i=; i<k-; i++)
prior = list[prior].next;
index = list[prior].next;
list[prior].next = list[list[prior].next].next;
}
x = list[index].data;
list[index].next = -;
recycleFreeNode(index);
return *this;
} template<class T>
SimPointerList<T>& SimPointerList<T>::insertElement(int k, const T& x)
{
int len = getLength();
if (k< || k>len+)
throw OutOfBounds();
if (len == maxSize)
throw FullMemory();
int index = getFreeNode();//.next field has been setted by -1
list[index].data = x;
if (usedHeader == - || k == )
{
list[index].next = usedHeader;
usedHeader = index;
return *this;
} int begin = usedHeader;
for (int i=; i<k-; i++)
begin = list[begin].next;
list[index].next = list[begin].next;
list[begin].next = index;
return *this;
} template<class T>
int SimPointerList<T>::getFreeCapacity() const
{
return maxSize - getLength();
} template<class T>
void SimPointerList<T>::findElement(int k, T& x) const
{
if (k<= || k>getLength())
throw OutOfBounds();
int index = usedHeader;
for (int i=; i<k; i++)
index = list[index].next;
x = list[index].data;
} template<class T>
int SimPointerList<T>::searchElement(const T& x) const
{
int index = usedHeader;
int len = ;
while (index != -)
{
if (list[index].data == x)
break;
index = list[index].next;
len++;
}
return len;
} template<class T>
void SimPointerList<T>::output(ostream& out) const
{
int len = usedHeader;
while (len != -)
{
out<<list[len].data<<" ";
len = list[len].next;
}
} template<class T>
ostream& operator<<(ostream& out, const SimPointerList<T>& x)
{
x.output(out);
return out;
}
#endif
 //excp.h
#ifndef _EXCP_
#define _EXCP_
#include <new>
using namespace std; class OutOfBounds {
public:
OutOfBounds(){}
}; class FullMemory {
public:
FullMemory(){}
}; void my_new_handler()
{
throw FullMemory();
} new_handler old_handler = set_new_handler(my_new_handler);
#endif
 //simulatedPointer.cpp
#include <iostream>
#include "excp.h"
#include "simulatedPointer.h"
using namespace std; int main()
{
try{
SimPointerList<int> L();
cout<<"length : "<<L.getLength()<<endl;
L.insertElement(, ).insertElement(, ).insertElement(, ).insertElement(, );
cout<<"length : "<<L.getLength()<<endl;
int x;
cout<<L<<endl;
L.findElement(, x);
cout<<"The second element is : "<<x<<endl;
L.deleteElement(, x);
cout<<"delete : "<<x<<endl;
cout<<"After delete : "<<L<<endl;
cout<<"new length is : "<<L.getLength()<<endl;
L.insertElement(, ).insertElement(, );
cout<<"Least : "<<L<<endl;
cout<<"Now the length is : "<<L.getLength()<<endl;
}
catch(OutOfBounds e)
{
cout<<"out of bounds error occured"<<endl;
}
catch(FullMemory e)
{
cout<<"full memory error occured"<<endl;
}
return ;
}

总结:

  1、如果要以传统思维来规范数组位置(下标从1开始),那就时刻要注意,在代码中时时小心处理和机器表示的区别,或者浪费一个存储空间list[0]以保持一致,

  2、要区分开模拟的链表下标和数组下标(因为这个,找了近两个小时的BUG,整个人都快疯掉了)。

  3、代码注意规范,变量、方法名尽量表达内丰含意。

「数据结构」:模拟指针(simulated pointer)的更多相关文章

  1. 「数据结构」Link-Cut Tree(LCT)

    #1.0 简述 #1.1 动态树问题 维护一个森林,支持删除某条边,加入某条边,并保证加边.删边之后仍然是森林.我们需要维护这个森林的一些信息. 一般的操作有两点连通性,两点路径权值和等等. #1.2 ...

  2. 「2014-3-17」C pointer again …

    记录一个比较基础的东东-- C 语言的指针,一直让人又爱又恨,爱它的人觉得它既灵活又强大,恨它的人觉得它太过于灵活太过于强大以至于容易将人绕晕.最早接触 C 语言,还是在刚进入大学的时候,算起来有好些 ...

  3. 「C++」理解智能指针

    维基百科上面对于「智能指针」是这样描述的: 智能指针(英语:Smart pointer)是一种抽象的数据类型.在程序设计中,它通常是经由类型模板(class template)来实做,借由模板(tem ...

  4. 「HNOI2016」数据结构大毒瘤

    真是 \(6\) 道数据结构毒瘤... 开始口胡各种做法... 「HNOI2016」网络 整体二分+树状数组. 开始想了一个大常数 \(O(n\log^2 n)\) 做法,然后就被卡掉了... 发现直 ...

  5. 「NOWCODER」CSP-S模拟赛第3场

    「NOWCODER」CSP模拟赛第3场 T1 货物收集 题目 考场思路即正解 T2 货物分组 题目 考场思路 题解 60pts 算法:一维 DP 100pts 算法:一维 DP ?线段树 + 单调栈 ...

  6. #10471. 「2020-10-02 提高模拟赛」灌溉 (water)

    题面:#10471. 「2020-10-02 提高模拟赛」灌溉 (water) 假设只有一组询问,我们可以用二分求解:二分最大距离是多少,然后找到深度最大的结点,并且把它的\(k\)倍祖先的一整子树删 ...

  7. #10470. 「2020-10-02 提高模拟赛」流水线 (line)

    题面:#10470. 「2020-10-02 提高模拟赛」流水线 (line) 题目中的那么多区间的条件让人感觉极其难以维护,而且贪心的做法感觉大多都能 hack 掉,因此考虑寻找一些性质,然后再设计 ...

  8. 「MoreThanJava」Day 4:面向对象基础

    「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...

  9. 「ZJOI2018」历史(LCT)

    「ZJOI2018」历史(LCT) \(ZJOI\) 也就数据结构可做了-- 题意:给定每个点 \(access\) 次数,使轻重链切换次数最大,带修改. \(30pts:\) 挺好想的.发现切换次数 ...

随机推荐

  1. m个相同苹果放的n个相同盘子中的算法

    m个相同的苹果,放在n个相同的盘子中,由于相同,使用排列组合的方法不好处理.这个问题困扰了我很久 最后由大神“或缺”给出了答案: 以8个苹果放在3个盘子中为例 思路: 8苹果3盘子 =8苹果2盘子+5 ...

  2. 使用 system.io.filesysteminfo 来查找文件。

    如何快速搜索你想找到文件呢.大家知道Windows系统自带了搜索,很方便,下面介绍自己编写的也可以达到同样的效果.注意.有些文件的访问需要更高的权限.这里暂且去掉那些文件目录的搜索.不然会出现erro ...

  3. AngularJS Directive 学习笔记

    指令 Directive 指令要点 大漠老师的教学节点 解析最简单的指令 hello: 匹配模式 restrict 解析最简单的指令 hello: template.tempmlateUrl.$tem ...

  4. JavaSE复习日记 : 算是个小前言吧

    /* * Java也学了好久了,抽个时间整理了一下课堂笔记,也有些是我刚开始学会犯的一些错误.在这里浅谈一下JavaSE的基础内容,对我来说也是一种不错的复习方式. * * 那好,对于初学者来说,学习 ...

  5. 2768: [JLOI2010]冠军调查( 最小割 )

    最小割... 怎么乱搞都可以 -------------------------------------------------------------------------------- #inc ...

  6. UNIX/Linux-进程控制(实例入门篇)

    UNIX进程   进程标识符 要想对进程控制,必须得获取进程的标识.每个进程都有一个非负整数表示的唯一进程ID,虽然是唯一的,但是进程ID可以重用.当一个进程终止后,其进程ID就可以再次使用了. 系统 ...

  7. ORA-02396: exceeded maximum idle time, please connect again的原因

    一般为了防止过多活动的session占用资源,可以对允许连接到数据库的session个数,已连接到数据库的session空闲时间等进行限制(当然也可以对尝试连接次数等其它很多内容进行限制).方式就是可 ...

  8. IOS 特定于设备的开发:Info.plist属性列表的设置

    应用程序的Info.plist属性列表使你能够在向iTunes提交应用程序时指定应用程序的要求.这些限制允许告诉iTunes应用程序需要哪些设备特性. 每个IOS单元都会提供一个独特的特性集.一些设备 ...

  9. 射频识别技术漫谈(18)——Mifare Desfire

    Mifare  DESFire(MF3 IC D40/D41,本文以D40为例)遵守14443 TypeA协议,卡内的数据以文件形式存储,所以有人认为它是准CPU卡,主要用于安全性要求较高的非接触式领 ...

  10. 基于Visual C++2013拆解世界五百强面试题--题8-数组的排序和查找

    用三种方法实现对一个数组的排序,并设计一个函数实现数的查找,要求时间越短越好,空间占用越少越好. 对数组排序的方法很多,我们选比较常用和容易的三种排序,直接插入排序,冒泡排序和快速排序. 直接插入排序 ...