在讨论线性表的顺序及链式存储映像,并在此基础上给出其基本操作的实现之前,先以模板的形式为ADT List建立一个抽象类。
//List.h
#pragma once
template <class ElemType>
class List
{
public:
//后面加个const 表明该函数不会改变成员函数的值!该函数可以被常量对象访问(const)。
//注意 加了const 与不加const的函数是两个不同的函数!
virtual bool IsEmpty() const = 0;//判断是否为空表
virtual int Length() const = 0;//求表长
virtual void Clear() = 0;//置空表
virtual bool GetElem(ElemType&, int)const = 0;//取值
virtual bool SetElem(const ElemType&, int) = 0;//表中存值
virtual int LocateElem(const ElemType&)const = 0;//查找符合条件的数据元素
virtual int LocatePrior(const ElemType&)const = 0;//查前驱
virtual int LocateNext(const ElemType&)const = 0;//查后继
virtual bool Insert(const ElemType&, int) = 0;//在指定位置插入值
virtual bool Append(const ElemType&) = 0;//尾插
virtual bool Delete(ElemType&, int i) = 0;//删值
virtual void Traverse(void(*visit)(const ElemType&))const = 0;//遍历表
};
顺序表
顺序表的特点是存储地址连续,便于取值,但不便于插入、删除
//SqList.h
#pragma once
#include "List.h"
template <class ElemType>
class SqList :public List<ElemType>
{
public:
SqList(int m = 0);
SqList(const SqList<ElemType>&);
~SqList();
bool IsEmpty()const { return len <= 0; }//len<=0时返回true
int Length()const { return len; }
void Clear() { len = 0; }//置线性表为空表
bool GetElem(ElemType&, int)const;
bool SetElem(const ElemType&, int);
int LocateElem(const ElemType&)const;
int LocatePrior(const ElemType&)const;
int LocateNext(const ElemType&)const;
bool Insert(const ElemType&, int);
bool Append(const ElemType&, int);
bool Delete(ElemType&, int);
void Traverse(void(*visit)(const ElemType&))const;
SqList<ElemType>& operator=(const SqList<ElemType>&);
private:
int len;
int size;
ElemType* elem;//基地址指针
void CopyFrom(const SqList<ElemType>&);
};
//初始化顺序表
template<class ElemType>
SqList<ElemType>::SqList(int m)
{
len = 0;
if (0 == m)
elem = NULL;
else
elem = new ElemType[m];
size = m;
}
//复制构造函数
template<class ElemType>
SqList<ElemType>::SqList(const SqList<ElemType>& r)
{
len = 0;
size = 0;
elem = NULL;
CopyFrom(r);
}
//析构函数
template<class ElemType>
SqList<ElemType>::~SqList()
{
delete[] elem;
}
//表中取值
template<class ElemType>
bool SqList<ElemType>::GetElem(ElemType& e, int i) const
{
if (i<1 || i>len)
return false;
e = elem[i - 1];
return true;
}
//表中存值
template<class ElemType>
bool SqList<ElemType>::SetElem(const ElemType& e, int i)
{
if (i<1 || i>len)
return false;
elem[i - 1] = e;
return true;
}
//按数据元素查值
template<class ElemType>
int SqList<ElemType>::LocateElem(const ElemType& e) const
{
ElemType* p = elem;
int i = 1;
while (i < len && *p != e)
{
p++;
i++;
}
if (i <= len)
return i;
return 0;
}
//查某数据元素前驱
template<class ElemType>
int SqList<ElemType>::LocatePrior(const ElemType& e) const
{
ElemType* p = elem;
int i = 1;
while (i < len && *p != e)
{
p++;
i++;
}
if (i > 1 && i <= len)
return i - 1;
return 0;
}
//查某数据元素后继
template<class ElemType>
int SqList<ElemType>::LocateNext(const ElemType& e) const
{
ElemType* p = elem;
int i = 1;
while (i < len && *p != e)
{
p++;
i++;
}
if (i >= 1 && i < len)
return i + 1;
return 0;
}
//在指定位置插入数据元素
template<class ElemType>
bool SqList<ElemType>::Insert(const ElemType& e, int i)
{
if (i<1 || i>len)
return false;
if (len >= size) {
ElemType* newbase;
newbase = new ElemType[size + 10];
if (!newbase)
return false;
for (int j = 0; j < len; j++)
newbase[j] = elem[j];
delete[] elem;
elem = newbase;
size += 10;
}
ElemType* p, * q;
q = &elem[i - 1];//将elem[i-1]的地址赋给q
for (p = &elem[len - 1]; p >= q; --p)
*(p + 1) = *p;
*q = e;
++len;
return true;
}
//在顺序表尾插入值
template<class ElemType>
bool SqList<ElemType>::Append(const ElemType& e, int i)
{
ElemType* newbase;
if (len >= size) {
newbase = new ElemType[size + 10];
if (!newbase)
return false;
for (int j = 0; j < len; j++)
newbase[j] = elem[j];
delete[] elem;
elem = newbase;
size += 10;
}
elem[len++] = e;
return true;
}
//删除指定位置数据元素,并返回其值
template<class ElemType>
bool SqList<ElemType>::Delete(ElemType& e, int i)
{
if (i<1 || i>len)
return false;
ElemType* p;
p = &elem[i - 1];
e = *p;
for (p + 1; p <= &elem[len - 1]; ++p)
*(p - 1) = *p;
len--;
return true;
}
//重载“=”
template<class ElemType>
SqList<ElemType>& SqList<ElemType>::operator=(const SqList<ElemType>& r)
{
Clear();
CopyFrom(r);
return *this;
}
//从现有一个顺序表中复制所有元素
template<class ElemType>
void SqList<ElemType>::CopyFrom(const SqList<ElemType>& r)
{
ElemType* p = r.elem;
for (int i = 0; i < r.len; i++)
Append(*p++);
}
//依次对顺序表每个元素调用一次visit()函数
template<class ElemType>
void SqList<ElemType>::Traverse(void(*visit)(const ElemType& e)) const
{
ElemType* p = elem;
for (int i = 0; i < len; i++)
visit(*p++);
}
顺序表的应用:合并两个有序表
已知两个数据元素按值非递减排列的线性表La和Lb,合并La、Lb得到新表Lc,Lc也按值非递减排列。
算法描述:
- 建立线性表La、Lb,表长分别为n、m。
- i=1, j=1, k=1。
- 当i<=n&&j<=m,重复4、5。
- 依序取出La表中第i个元素和lb表中第j个元素,分别赋给sa、sb。
- if sa<=sb,将sa插入到线性表Lc第k的位置(表尾),i++, k++;
否则,将sb插入到线性表Lc第k的位置(表尾),j++, k++。 - 若i<=n, 将La剩余元素复制到Lc表尾;
否则,将Lb剩余元素复制到Lc表尾。
//MergeList.cpp
#include<iostream>
#include "List.h"
#include "Sqlist.h"
using namespace std;
//建立线性表
void Creat(List<int>* lx, int k, char c) {
int e;
if (k > 0) {
cout << "请顺序输入" << k << "个" << c << "表中的数据:" << endl;
for (int i = 0; i < k; i++)
{
cin >> e;
lx->Append(e);
}
}
}
void MergeList(List<int>* la, List<int>* lb, List<int>* lc) {
int i = 1, j = 1;
int sa, sb;
int lalen = la->Length();
int lblen = lb->Length();
while (i <= lalen && j <= lblen) {
la->GetElem(sa, i);
lb->GetElem(sb, j);
if (la <= lb) {
lc->Append(sa);
i++;
}
else
{
lc->Append(sb);
j++;
}
}
while (i <= lalen)
{
la->GetElem(sa, i);
lc->Append(sa);
i++;
}
while (j<=lblen)
{
lb->GetElem(sb, j);
lc->Append(sb);
j++;
}
}
void Print(const int& c) {
cout << c << " ";
}
int main()
{
void Print(const int&);
void MergeList(List<int>*, List<int>*, List<int>*);
void Create(List<int>*, int, char);
int n, m;
cout << "---此程序用于合并两个有序表---" << endl;
cout << "请输入有序表A的长度: ";
cin >> n;
cout << "请输入有序表B的长度: ";
cin >> m;
cout << "抽象类模板连接的具体类是单链表类模板,数据元素是整型" << endl << endl;
SqList<int> lal(n), lbl(m), lcl(n + m);
Creat(&lal, n, 'A');
cout << endl;
Creat(&lbl, m, 'B');
cout << endl;
MergeList(&lal, &lbl, &lcl);
cout << "合并后的c表为:" << endl;
lcl.Traverse(Print);
system("pause");
return 0;
}
链表
先定义链表节点
//LinkNode.h
#pragma once
template<class ElemType>
struct LinkNode
{
ElemType data;
LinkNode<ElemType>* next;
};
链表的特点是便于插值、删除,但不便于遍历取值
下面创建链表类,并给出其基本操作的实现
//LinkList.h
#pragma once
#include "List.h"
#include "LinkNode.h"
template <class ElemType>
class LinkList:public List<ElemType>
{
public:
LinkList();
LinkList(const LinkList<ElemType>&);
~LinkList();
bool IsEmpty()const { return len <= 0; }
int Length()const { return len; }
void Clear();
bool GetElem(ElemType&, int)const;
bool SetElem(const ElemType&, int);
int LocateElem(const ElemType&)const;
int LocatePrior(const ElemType&)const;
int LocateNext(const ElemType&)const;
bool Insert(const ElemType&, int);
bool Append(const ElemType&);
bool Delete(ElemType&, int);
void Traverse(void(*visit)(const ElemType&))const;
LinkList<ElemType>& operator=(const LinkList<ElemType>&);
private:
int len;
LinkNode<ElemType>* head;
LinkNode<ElemType>* tail;
void CopyFrom(const LinkList<ElemType>&);
};
template<class ElemType>
LinkList<ElemType>::LinkList()
{
len = 0;
head = tail = new LinkNode<ElemType>;
head->next = NULL;
}
template<class ElemType>
LinkList<ElemType>::LinkList(const LinkList<ElemType>& r)
{
CopyFrom(r);
}
//从现有单链表拷贝构造出一个单链表
template<class ElemType>
LinkList<ElemType>::~LinkList()
{
Clear();
delete head; //释放头结点
}
//释放所有数据节点
template<class ElemType>
void LinkList<ElemType>::Clear()
{
LinkNode<ElemType>* p = head->next, * q;
while (p)
{
q = p->next;
delete p;
p = q;
}
tail = head;
head->next = NULL;
len = 0;
}
template<class ElemType>
bool LinkList<ElemType>::GetElem(ElemType& e, int i) const
{
if (i<1 || i>len)
return false;
LinkNode<ElemType>* p = head->next;
int k = 1;
while (k<i)
{
p = p->next;
k++;
}
e = p->data;
return true;
}
template<class ElemType>
bool LinkList<ElemType>::SetElem(const ElemType& e, int i)
{
if (i<1 || i>len)
return false;
LinkNode<ElemType>* p = head->next;
int k = 1;
while (k<i)
{
p = p->next;
k++;
}
p->data = e;
return true;
}
//要考虑表中无p的情况
template<class ElemType>
int LinkList<ElemType>::LocateElem(const ElemType& e) const
{
LinkNode<ElemType>* p = head->next;
int i = 1;
while (p && p -> data != e)
{
p = p->next;
i++;
}
if (p)
return i;
else
return 0;
}
template<class ElemType>
int LinkList<ElemType>::LocatePrior(const ElemType& e) const
{
int i = LocateElem(e);
if (i > 1)
return i - 1;
return 0;
}
template<class ElemType>
int LinkList<ElemType>::LocateNext(const ElemType& e) const
{
int i = LocateElem(e);
if (i && i < len)
return i + 1;
return 0;
}
//前插,共len+1个空位
template<class ElemType>
bool LinkList<ElemType>::Insert(const ElemType& e, int i)
{
if (i < 1 || i > len + 1)
return false;
LinkNode<ElemType>* p, * q;
int k = 1;
q = new LinkNode<ElemType>;
q->data = e;
//将p指针定位在i-1的位置上
p = head;
while (k<i)
{
p = p->next;
k++;
}
q->next = p->next;
p->next = q;
if (i == len + 1)
tail = q;
++len;
return true;
}
template<class ElemType>
bool LinkList<ElemType>::Append(const ElemType& e)
{
LinkNode<ElemType>* q;
q = new LinkNode<ElemType>;
q->data = e;
tail->next = q;
tail = q;
tail->next = NULL;
++len;
return true;
}
//删除第i个数据,并用e返回其值
template<class ElemType>
bool LinkList<ElemType>::Delete(ElemType& e, int i)
{
if (i<1 || i>len)
return false;
LinkNode<ElemType>* p, * q;
p = head;
int k = 1;
while (k<i)
{
p = p->next;
k++;
}
q = p->next;
p->next = q->next;
if (q == tail)
tail = p;
e = q->data;
delete q;
--len;
return true;
}
template<class ElemType>
LinkList<ElemType>& LinkList<ElemType>::operator=(const LinkList<ElemType>& r)
{
Clear();
delete head;
CopyFrom(r);
return *this;//返回当前对象本身
}
template<class ElemType>
void LinkList<ElemType>::CopyFrom(const LinkList<ElemType>& r)
{
len = 0;
head = tail = new LinkNode<ElemType>;
head->next = NULL;
LinkNode<ElemType>* p = r.head->next;
while (p)
{
Append(p->data);
p = p->next;
}
}
template<class ElemType>
void LinkList<ElemType>::Traverse(void(*visit)(const ElemType& r)) const
{
LinkNode<ElemType>* p = head->next;
while (p)
{
visit(p->data);
p = p->next;
}
}
链表的应用:集合运算
利用单链表类模板实现集合运算A=(A-B)∪(B-A)
// SetOperation.cpp
#include <iostream>
#include "LinkList.h"
using namespace std;
void print(const char& c) {
cout << c << " ";
}
//使用线性表实现集合运算(A-B)U(B-A),即找出两个集合中所有不同元素
void Difference(LinkList<char>& la, LinkList<char>& lb) {
int i, lblen;
lblen = lb.Length();
//逐一读入B表数据到A表查找,若存在则从A表删除,否则,插入到A表
for (i = 1; i <= lblen; i++)
{
char e;
lb.GetElem(e, i);//单链表中取值效率较顺序表低,o(n)
int k = la.LocateElem(e);
if (k)
la.Delete(e, k);//o(1)
else
la.Append(e);//尾插,o(1)
}
}
//建立以线性表存储表示的集合
void Create(LinkList<char>& la, const int& k) {
char e;
for (int i = 0; i < k; i++)
{
cin >> e;
la.Append(e);
}
}
int main()
{
int n, m;
cout << "---此程序实现集合运算(A-B)∪(B-A)---" << endl;
cout << "请输入集合A中元素个数:" << endl;
cin >> n;
cout << "请输入集合B中元素个数:" << endl;
cin >> m;
cout << "解题模板是单链表类,数据元素类型是字符型" << endl << endl;
LinkList<char> lal, lbl;
cout << "请输入" << n << "个数据元素至集合A" << endl;
Create(lal, n);
cout << "请输入" << m<< "个数据元素至集合A" << endl;
Create(lbl, m);
Difference(lal, lbl);
cout << "运算后的集合A是:" << endl;
lal.Traverse(print);
cout << endl << endl;
system("pause");
return 0;
}