声明:本文内容属于本人原创,欢迎转载,请大家在转载时注明转贴地址
使用一个模板类实现了线性表的顺序表示,我对这个模板类进行了简单的测试,大家如果在使用过程中或看代码的过程中遇到错误请及时提出,谢谢!该代码已经在VS2005环境下编译通过
- /**
- * @file ListSqu.h
- * @author Wang Liuqiang
- * @version 1.0
- * @date 2008-11-30
- * @brief 该类实现了线性表的顺序表示
- */
- #ifndef LISTSQU_H_
- #define LISTSQU_H_
- #include <assert.h>
- #include <iostream>
- using namespace std;
- #define LIST_INIT_SIZE 100
- #define LISTINCREMENT 10
- #define SQUSUCCEED 0
- #define SQUERROR -1
- #define SQUOVERFLOW -2
- /*
- * 定义了两个默认的函数,如果用户在调用LocalElem()函数时没有指定
- * 函数,则使用默认的equal()函数;如果指定了自己的比较函数,则将
- * 自己的函数指针赋给LocalElem()函数
- */
- template <class T>
- bool equal(T e1, T e2)
- {
- if (e1 == e2)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- /*
- * 定义了两个默认的函数,如果用户在调用Traverse()函数时没有指定
- * 函数,则使用默认的show()函数;如果指定了自己的比较函数,则将
- * 自己的函数指针赋给Traverse()函数
- */
- template <class T>
- void show(T e)
- {
- cout<<e<<endl;
- }
- template <class T>
- class ListSqu
- {
- public:
- /*
- *name 构造函数/析构函数
- *@{
- */
- ListSqu();
- ~ListSqu();
- ListSqu(const ListSqu<T>& ls);
- ListSqu<T>& operator=(const ListSqu<T>& ls);
- /** @}*/ //构造函数/析构函数
- public:
- /*
- * 清空顺序表
- * @return 返回函数执行结果:
- * -0 表示执行成功
- * -1 表示执行出错
- */
- int ClearList();
- /*
- * 判断顺序表是否为空
- * @return 返回函数执行结果:
- * -true 表示顺序表为空
- * -false 表示顺序表不为空
- */
- bool IsEmpty();
- /*
- * 返回顺序表中元素个数
- * @return 返回顺序表中元素个数
- */
- int Length();
- /*
- * 返回线性表中第一个与e满足关系Compare()的数据元素的位序
- * @param[in] e 待判定的元素
- * @param[in] Compare 函数指针,指向判定元素的函数指针,默认为比较元素是否相等
- * @return 返回线性表中第一个与e满足关系Compare()的数据元素的位序
- */
- int LocalElem(const T& e, bool (*Compare)(T, T)= equal);
- /*
- * 返回顺序表中第i个位置的元素
- * @param[in] i 需要获取元素的位置
- * @param[out] e 顺序表中第i个位置的元素值
- * @return 返回函数执行结果
- * -SQUSUCCEED 表示函数执行成功
- * -SQUERROR 表示函数执行失败
- * @note C++中数组的下标是从0开始,因此第i个位置的元素应该取下标为i-1的元素
- */
- int GetItem(int i, T& e);
- /*
- * 在顺序表的第i个位置之前插入元素
- * @param[in] 元素的插入位置
- * @param[in] 插入元素值
- * @return 返回函数的执行结果
- * -SQUSUCCEED 表示函数执行成功
- * -SQUERROR 表示函数执行失败
- */
- int InsertItem(int i, T& e);
- /*
- * 删除顺序表中第i个位置的元素
- * @param[in] i 待删除元素位置
- * @param[out] e 删除元素的值
- * @return 返回函数的执行结果
- * -SQUSUCCEED 表示函数执行成功
- * -SQUERROR 表示函数执行失败
- */
- int DeleteItem(int i, T& e);
- /*
- * 显示顺序表中元素
- * @return 返回函数的执行结果
- * -SQUSUCCEED 表示函数执行成功
- * -SQUERROR 表示函数执行失败
- */
- int Show(); // 输出表中元素
- /*
- * 遍历线性表中元素
- * @param[in] vi 函数指针,指向处理元素函数,默认为在屏幕打印元素
- */
- void Traverse(void (*vi)(T e) = show);
- private:
- T* items;
- int length;
- int listsize;
- };
- template <class T>
- ListSqu<T>::ListSqu()
- {
- items = new T[LIST_INIT_SIZE];
- assert(items);
- length = 0;
- listsize = LIST_INIT_SIZE;
- }
- template <class T>
- ListSqu<T>::~ListSqu()
- {
- if (items != NULL)
- {
- delete[] items;
- items = NULL;
- }
- }
- template <class T>
- ListSqu<T>::ListSqu(const ListSqu<T>& ls)
- {
- length = ls.length;
- listsize = ls.listsize;
- items = new T[listsize + 1];
- memcpy(items, ls.items, _msize(ls.items));
- }
- template <class T>
- ListSqu<T>& ListSqu<T>::operator=(const ListSqu<T>& ls)
- {
- if( this == &ls )
- return *this;
- if (items != NULL)
- {
- delete[] items;
- items = NULL;
- }
- length = ls.length;
- listsize = ls.listsize;
- items = new T[listsize + 1];
- memcpy(items, ls.items, _msize(ls.items));
- return *this;
- }
- template <class T>
- int ListSqu<T>::ClearList()
- {
- length = 0;
- return SQUSUCCEED;
- }
- template <class T>
- bool ListSqu<T>::IsEmpty()
- {
- return length == 0;
- }
- template <class T>
- int ListSqu<T>::LocalElem(const T& e, bool (*Compare)(T, T))
- {
- int i = 0;
- T* p;
- p = items;
- while ( i < length && !Compare(*p++, e))
- {
- ++i;
- }
- if (i < length)
- {
- return i + 1;
- }
- else
- {
- return 0;
- }
- }
- template <class T>
- int ListSqu<T>::GetItem(int i, T& e)
- {
- if ( (i < 1) || ( i > length ))
- {
- cout<<"所给位置超出位置索引!"<<endl;
- return SQUERROR;
- }
- else
- {
- e = items[i -1];
- return SQUSUCCEED;
- }
- }
- template <class T>
- int ListSqu<T>::InsertItem(int i, T& e)
- {
- if ( i < 1 || i > length + 1)
- {
- cout<<"所给位置出错!"<<endl;
- return SQUERROR;
- }
- else
- {
- if (length >= listsize)
- {
- T* pNew = new T[LISTINCREMENT];
- memcpy(pNew, items, _msize(items));
- items = pNew;
- if (items == NULL)
- {
- cout<<"申请内存空间失败!"<<endl;
- return SQUOVERFLOW;
- }
- listsize += LISTINCREMENT;
- }
- for(int k = length; k >= i - 1; k--)
- {
- items[k+1] = items[k];
- }
- items[i-1] = e;
- length++;
- return SQUSUCCEED;
- }
- }
- template <class T>
- int ListSqu<T>::DeleteItem(int i, T& e)
- {
- if ( i < 1 || i > length )
- {
- cout<<"所给删除位置出错!"<<endl;
- return SQUERROR;
- }
- e = items[i-1];
- for (i = i -1; i < length; i++)
- {
- items[i] = items[i + 1];
- }
- length--;
- return SQUSUCCEED;
- }
- template <class T>
- int ListSqu<T>::Show()
- {
- for (int i = 0; i < length; i++)
- {
- cout<<items[i]<<endl;
- }
- return SQUSUCCEED;
- }
- template <class T>
- void ListSqu<T>::Traverse(void (*vi)(T e))
- {
- for (int i = 0; i < length; i++)
- {
- vi(items[i]);
- }
- }
- #endif
通过编写这段代码,觉得以下几点需要特别注意:
1. 需要特别注意内存越界的情况,对于动态申请的内存指针,如果对其进行越界操作,在使用delete操作释放该指针时会造成程序崩溃。在编写上面的程序时就将
template <class T> ListSqu<T>& ListSqu<T>::operator=(const ListSqu<T>& ls)
函数中items = new T[listsize + 1];错误的写成了items = new T[length + 1];而造成内存越界,详细解释如下:
template <class T>
ListSqu <T>& ListSqu <T>::operator=(const ListSqu <T>& ls)
{
if( this == &ls )
return *this;
delete[] items;
items = NULL;
length = ls.length;
listsize = ls.listsize;
items = new T[length + 1];
memcpy(items, ls.items, _msize(ls.items));
return *this;
}
items = new T[length + 1];
这里应该是
items = new T[listsize + 1];
listsize是我在类的构造函数中初始化分配的内存数,而length是当前线性表中存放的元素个数,这里用length+1分配内存,而在memcpy(items, ls.items, _msize(ls.items)); 又将sizeof(T)*listsize长的字节拷贝给items该处发生越界了
2. 注意模板类的复制构造函数和赋值操作符的声明方法
3. 注意如何把函数指针当作形参并对其使用默认参数的方法