「数据结构」:模拟指针(simulated pointer)

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

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

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

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

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

  1 //simulatedPointer.h 
  2 #ifndef __SIMULATEDPOINTER__
  3 #define __SIMULATEDPOINTER__
  4 #include <iostream>
  5 #include "excp.h"
  6 using namespace std;
  7 
  8 template<class T>
  9 class SimPointerList;
 10 
 11 template<class T>
 12 class Node {
 13 public:
 14     friend class SimPointerList<T>;
 15 private:
 16     T data;
 17     int next;
 18 };
 19 
 20 template<class T>
 21 class SimPointerList {
 22 public:
 23     SimPointerList(int maxaSize = 10);
 24     ~SimPointerList(){delete [] list;}
 25     int getFreeNode();
 26     void recycleFreeNode(int i);
 27     bool isEmpty() const;
 28     int getLength() const;
 29     SimPointerList<T>& deleteElement(int k, T& x);
 30     SimPointerList<T>& insertElement(int k, const T& x);
 31     void findElement(int k, T& x) const;
 32     int searchElement(const T& x) const;
 33     void output(ostream& out) const;
 34     int getFreeCapacity() const;
 35 private:
 36     int freeHeader;//point to the head of the free-list
 37     int usedHeader;
 38     int maxSize;
 39     Node<T> *list;
 40 };
 41 
 42 template<class T>
 43 SimPointerList<T>::SimPointerList(int maxaSize)
 44 {
 45     maxSize = maxaSize;
 46     freeHeader = 0;
 47     usedHeader = -1;
 48     list = new Node<T>[maxSize];
 49     for (int i=0; i<maxSize-1;i++)
 50         list[i].next = i+1;
 51     list[maxSize-1].next = -1;
 52 }
 53 
 54 template<class T>
 55 int SimPointerList<T>::getFreeNode()
 56 {
 57     if (freeHeader == -1)
 58         throw FullMemory();
 59     int i = freeHeader;
 60     freeHeader = list[i].next;
 61     list[i].next=-1;
 62     return i;
 63 }
 64 
 65 template<class T>
 66 void SimPointerList<T>::recycleFreeNode(int i)
 67 {
 68     if (i<0 || i>=maxSize)
 69         throw OutOfBounds();
 70     list[i].next = freeHeader;
 71     freeHeader = i;
 72 }
 73 
 74 template<class T>
 75 bool SimPointerList<T>::isEmpty() const
 76 {
 77     return usedHeader == -1;
 78 }
 79 
 80 template<class T>
 81 int SimPointerList<T>::getLength() const
 82 {
 83     int len = 0;
 84     if (usedHeader != -1)
 85         for (int begin=usedHeader; begin!=-1; begin=list[begin].next)
 86             len++;
 87     return len;
 88 }
 89 
 90 template<class T>
 91 SimPointerList<T>& SimPointerList<T>::deleteElement(int k, T& x)
 92 {
 93     if (k<=0 || k>getLength())
 94         throw OutOfBounds();
 95     int index = 0;
 96     if (k == 1)
 97     {
 98         index = usedHeader;
 99         usedHeader = list[usedHeader].next;
100     }
101     else if (getLength()==2 && k == 2)
102     {
103         index = list[usedHeader].next;
104         list[usedHeader].next = -1;
105     }
106     else
107     {
108         int prior = usedHeader;
109         for (int i=1; i<k-1; i++)
110             prior = list[prior].next;
111         index = list[prior].next;
112         list[prior].next = list[list[prior].next].next;
113     }
114     x = list[index].data;
115     list[index].next = -1;
116     recycleFreeNode(index);
117     return *this;
118 }
119 
120 template<class T>
121 SimPointerList<T>& SimPointerList<T>::insertElement(int k, const T& x)
122 {
123     int len = getLength();
124     if (k<1 || k>len+1)
125         throw OutOfBounds();
126     if (len == maxSize)
127         throw FullMemory();
128     int index = getFreeNode();//.next field has been setted by -1
129     list[index].data = x;
130     if (usedHeader == -1 || k == 1)
131     {
132         list[index].next = usedHeader;
133         usedHeader = index;
134         return *this;
135     }
136 
137     int begin = usedHeader;
138     for (int i=1; i<k-1; i++)
139         begin = list[begin].next;
140     list[index].next = list[begin].next;
141     list[begin].next = index;
142     return *this;
143 }
144 
145 template<class T>
146 int SimPointerList<T>::getFreeCapacity() const
147 {
148     return maxSize - getLength();
149 }
150 
151 template<class T>
152 void SimPointerList<T>::findElement(int k, T& x) const
153 {
154     if (k<=0 || k>getLength())
155         throw OutOfBounds();
156     int index = usedHeader;
157     for (int i=1; i<k; i++)
158         index = list[index].next;
159     x = list[index].data;
160 }
161 
162 template<class T>
163 int SimPointerList<T>::searchElement(const T& x) const
164 {
165     int index = usedHeader;
166     int len = 0;
167     while (index != -1)
168     {
169         if (list[index].data == x)
170             break;
171         index = list[index].next;
172         len++;
173     }
174     return len;
175 }
176 
177 template<class T>
178 void SimPointerList<T>::output(ostream& out) const
179 {
180     int len = usedHeader;
181     while (len != -1)
182     {
183         out<<list[len].data<<" ";
184         len = list[len].next;
185     }
186 }
187 
188 template<class T>
189 ostream& operator<<(ostream& out, const SimPointerList<T>& x)
190 {
191     x.output(out);
192     return out;
193 }
194 #endif
 1 //excp.h
 2 #ifndef _EXCP_
 3 #define _EXCP_
 4 #include <new>
 5 using namespace std;
 6 
 7 class OutOfBounds {
 8 public:
 9     OutOfBounds(){}
10 };
11 
12 class FullMemory {
13 public:
14     FullMemory(){}
15 };
16 
17 void my_new_handler()
18 {
19     throw FullMemory();
20 }
21 
22 new_handler old_handler = set_new_handler(my_new_handler);
23 #endif
 1 //simulatedPointer.cpp
 2 #include <iostream>
 3 #include "excp.h"
 4 #include "simulatedPointer.h"
 5 using namespace std;
 6 
 7 int main()
 8 {
 9     try{
10         SimPointerList<int> L(10);
11         cout<<"length : "<<L.getLength()<<endl;
12         L.insertElement(1, 2).insertElement(2, 6).insertElement(2, 4).insertElement(1, 5);
13         cout<<"length : "<<L.getLength()<<endl;
14         int x;
15         cout<<L<<endl;
16         L.findElement(2, x);
17         cout<<"The second element is : "<<x<<endl;
18         L.deleteElement(2, x);
19         cout<<"delete : "<<x<<endl;
20         cout<<"After delete : "<<L<<endl;
21         cout<<"new length is : "<<L.getLength()<<endl;
22         L.insertElement(2, 3).insertElement(1, 10);
23         cout<<"Least : "<<L<<endl;
24         cout<<"Now the length is : "<<L.getLength()<<endl;
25     }
26     catch(OutOfBounds e)
27     {
28         cout<<"out of bounds error occured"<<endl;
29     }
30     catch(FullMemory e)
31     {
32         cout<<"full memory error occured"<<endl;
33     }
34     return 0;
35 }


总结:

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

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

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

posted @ 2014-02-27 21:39  sangoly  阅读(1396)  评论(0编辑  收藏  举报