线性表是由一个或多个数据元素组成的有限序列
线性表根据存储方式分为:
1、顺序存储(数组描述):元素的地址是连续的
2、链式存储(链表描述):节点地址不连续,通过指针连起来
线性表的抽象类(常用的API):
#include
#include
using namespace std;
//父类线性表
template<class T>
class LineList
{
public:
virtual ~LineList() {}; //虚析构函数
virtual bool empty() const = 0; //判断线性表是否为空
virtual int size() const = 0; //返回线性表大小
virtual T& get(int theIndex) const = 0; //按索引查找元素
virtual int index(const T& theElement) const = 0; //按值查找元素
virtual void erase(int theIndex) = 0; //删除索引元素
virtual void insert(int theIndex, const T& theElement) = 0; //按索引插入元素
};
对于顺序存储方式一般用数组实现,事实上就是在内存中找个初始地址,然后通过占位的形式,把一定连续的内存空间给占了,然后把相同数据类型的数据元素依次放在这块空地中,数组大小有两种方式指定,一是静态分配,二是动态扩展。
顺序表相关的操作跟数组有关,一般都是移动数组元素。
顺序存储的实现方式:
//子类线性表,通过数组实现
template<class T>
class arrayList : public LineList<T>
{
public:
arrayList(int initialCapacity = 10);
arrayList(const arrayList<T>&);
~arrayList() { delete[] element; }
bool empty() const
{
if (ListSize == 0)
return 1;
else
return 0;
}
int size() const { return ListSize; }
T& get(int theIndex) const;
int index(const T& theElement) const;
void erase(int theIndex);
void insert(int theIndex, const T& theElement);
void output() const;
int capacity() const { return arrayLength; }
protected:
void checkIndex(int theIndex) const;
T* element;
int arrayLength;
int ListSize;
};
各成员函数:
template<class T>
arrayList<T>::arrayList(int initialCapacity)
{
if (initialCapacity < 1)
cout<<"Capability must be greater than 1"<<endl;
arrayLength = initialCapacity;
element = new T[arrayLength];
ListSize = 0;
}
template<class T>
arrayList<T>::arrayList(const arrayList<T>& theList)
{
arrayLength = theList.arrayLength;
ListSize = theList.ListSize;
element = new T[arrayLength];
copy(theList.element, theList.element + ListSize, element);
}
template<class T>
void arrayList<T>::checkIndex(int theIndex) const
{
if (theIndex < 0 || theIndex >= ListSize)
cout << "illegalindex" << endl;
}
template<class T>
T& arrayList<T>::get(int theIndex) const
{
checkIndex(theIndex);
return element[theIndex];
}
template<class T>
int arrayList<T>::index(const T& theElement) const
{
int theIndex = (int)(find(element, element + ListSize, theElement) - element);
if (theIndex == ListSize)
{
return -1;
}
else return theIndex;
}
template<class T>
void arrayList<T>::erase(int theIndex)
{
checkIndex(theIndex);
copy(element + theIndex + 1, element + ListSize, element + theIndex);
element[--ListSize].~T();
}
template<class T>
void arrayList<T>::insert(int theIndex, const T& theElement)
{
if (theIndex<0 || theIndex>ListSize)
cout << "illegalindex" << endl;
if (ListSize == arrayLength)
{
T* temp = new T[2 * arrayLength];
copy(element, element + arrayLength, temp);
delete[]element;
element = temp;
arrayLength = 2 * arrayLength;
}
copy_backward(element + theIndex, element + ListSize, element + ListSize + 1);
element[theIndex] = theElement;
ListSize++;
}
template<class T>
void arrayList<T>::output() const
{
for (int i = 0; i <= arrayLength; i++)
{
cout << element[i] << ", ";
}
cout << endl;
}
测试:
int main()
{
using namespace std;
arrayList<int> a(20);
cout << "数组的容量为:" << a.capacity() << endl;
cout << "数组的大小为:" << a.size() << endl;
a.output();
a.insert(0, 1);
a.insert(1, 3);
a.insert(2, 5);
a.insert(3, 7);
a.insert(4, 9);
cout << "数组的容量为:" << a.capacity() << endl;
cout << "数组的大小为:" << a.size() << endl;
a.output();
cout << "索引为2的元素为:" << a.get(2) << endl;
cout << "元素为5的索引为:" << a.index(5) << endl;
a.erase(3);
a.output();
cout << "索引为3的元素为:" << a.get(3) << endl;
cout << "数组的大小为:" << a.size() << endl;
a.insert(4, 11);
a.output();
system("pause");
return (0);
}
顺序存储的优缺点
线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的。这就意味着,这些元素可以存在内存未被占用的任意位置。
链表的定义是递归的,它或者为空null,或者指向另一个节点node的引用,这个节点含有下一个节点或链表的引用,线性链表的最后一个结点指针为“空”(通常用NULL或“^”符号表示)。
特点:
父类虚函数
class LineList
{
public:
virtual ~LineList() {}; //虚析构函数
virtual bool empty() const = 0; //判断线性表是否为空
virtual int size() const = 0; //返回线性表大小
virtual T& get(int theIndex) const = 0; //按索引查找元素
virtual int index(const T& theElement) const = 0; //按值查找元素
virtual void erase(int theIndex) = 0; //删除索引元素
virtual void insert(int theIndex, const T& theElement) = 0; //按索引插入元素
};
链表节点的结构定义
template <class T>
struct chainNode
{
T element; //存储数据
chainNode<T>* next; //下一个节点的地址
};
链表派生类
template <class T>
class chain :public LineList<T>
{
public:
//构造函数
chain();
chain(T a[],int n);
~chain();
//抽象数据类型
bool empty() const { return 0; }
int size() const;
T& get(int theIndex) const;
int index(const T& theElement) const;
void erase(int theIndex);
void insert(int theIndex, const T& theElement);
void output() const;
protected:
chainNode<T>* firstNode; //指向链表第一个节点的指针
};
无参构造函数
chain<T>::chain()
{
firstNode = new chainNode<T>;
firstNode->next = NULL;
}
头插法的拷贝构造函数
template <class T>
chain<T>::chain(T a[],int n)
{
firstNode = new chainNode<T>;
firstNode->next = NULL;
for (int i = 0; i < n; i++)
{
chainNode<T>* s = new chainNode<T>;
s->element = a[i];
s->next = firstNode->next;
firstNode->next = s;
}
}
template<class T>
chain<T>::chain(T a[], int n)
{
firstNode = new chainNode<T>;
chainNode<T> *r = firstNode;
for (int i = 0; i < n; i++)
{
chainNode<T>* s = new chainNode<T>;
s->element = a[i];
r->next = s;
r = s;
}
r->next = NULL;
}
template<class T>
chain<T>::~chain()
{
while (firstNode != NULL)
{
chainNode<T>* q = firstNode;
firstNode = firstNode->next;
delete q;
}
}
成员方法函数
//返回长度
template<class T>
int chain<T>::size() const
{
chainNode<T>* p = firstNode->next;
int count = 0;
while (p != NULL)
{
p = p->next;
count++;
}
return count;
}
//按位查找
template<class T>
T& chain<T>::get(int theIndex) const
{
chainNode<T>* p = firstNode->next;
int count = 1;
while (p != NULL && count < theIndex)
{
p = p->next;
count++;
}
if (p == NULL)
throw"Wrong_Index";
else
return p->element;
}
//按值查找
template<class T>
int chain<T>::index(const T& theElement) const
{
chainNode<T>* p = firstNode->next;
int count = 1;
while (p != NULL)
{
if (p->element == theElement)
return count;
p = p->next;
count++;
}
return 0;
}
//删除
template<class T>
void chain<T>::erase(int theIndex)
{
chainNode<T>* p = firstNode;
int count = 0;
while (p != NULL && count < theIndex - 1)
{
p = p->next;
count++;
}
if (p == NULL || p->next == NULL)
throw"Wrong_Index";
else
{
chainNode<T>* q = p->next;
p->next = p->next->next;
delete q;
}
}
//插入
template<class T>
void chain<T>::insert(int theIndex, const T& theElement)
{
chainNode<T>* p = firstNode;
int count = 0;
while (p != NULL && count < theIndex - 1)
{
p = p->next;
count++;
}
if (theIndex!=1&&p == NULL)
throw"Wrong_Index";
else
{
chainNode<T>* s = new chainNode<T>;
s->element = theElement;
s->next = p->next;
p->next = s;
}
}
//输出
template<class T>
void chain<T>::output() const
{
chainNode<T>* p = firstNode->next;
while (p != NULL)
{
cout << p->element << " ";
p = p->next;
}
cout << endl;
}
测试主函数
int main()
{
chain<int> p;
p.insert(1, 1);
p.insert(2, 5);
p.insert(3, 7);
p.output();
p.insert(2, 3);
p.output();
cout << "元素5位于:" << p.index(5) << endl;
cout << "元素9位于:" << p.index(9) << endl;
cout << "第2号元素为:" << p.get(2) << endl;
cout << "链表长度为:" << p.size() << endl;
p.erase(2);
p.output();
system("pause");
return 0;
}
链式存储的优缺点