|
|
/* LinkedList.h*/
|
|
|
/**
|
|
|
* LinkedList.h实现单链表结点类LinkNode和单链表(带头结点)类LinkedList
|
|
|
**/
|
|
|
#ifndef LINKEDLIST_H //#ifndef、#define、#endif确保LinkNode类和LinkedList类的代码仅被包含和编译一次
|
|
|
#define LINKEDLIST_H
|
|
|
#include "PerfCounter.h"
|
|
|
#include <iostream>
|
|
|
using namespace std;
|
|
|
#include "LinearList.h"
|
|
|
#include <stdlib.h>
|
|
|
;
|
|
|
template <class T>
|
|
|
struct LinkNode
|
|
|
{
|
|
|
T data; //数据域,数据元素类型为T
|
|
|
LinkNode<T> *link; //指针域,指向下一结点的指针
|
|
|
LinkNode(LinkNode<T> *ptr = NULL) //仅初始化指针成员的构造函数
|
|
|
{
|
|
|
link = ptr;
|
|
|
}
|
|
|
LinkNode(const T &item, LinkNode<T> *ptr = NULL) //初始化数据与指针成员的构造函数
|
|
|
{
|
|
|
data = item;
|
|
|
link = ptr;
|
|
|
}
|
|
|
void printToEnd()
|
|
|
{
|
|
|
for (LinkNode<T> *p = this; p; p = p->link)
|
|
|
cout << p->data << " ";
|
|
|
cout << endl;
|
|
|
}
|
|
|
};
|
|
|
template <class T>
|
|
|
class LinkedList : public LinearList<T> //定义单链表类 :
|
|
|
{
|
|
|
public:
|
|
|
PerfCounter counter;
|
|
|
LinkedList() //构造函数1
|
|
|
{
|
|
|
first = new LinkNode<T>;
|
|
|
}
|
|
|
LinkedList(const T &x) //构造函数2
|
|
|
{
|
|
|
first = new LinkNode<T>(x);
|
|
|
}
|
|
|
LinkedList(LinkedList<T> &L); //复制构造函数
|
|
|
~LinkedList() //析构函数
|
|
|
{
|
|
|
makeEmpty();
|
|
|
}
|
|
|
void makeEmpty(); //将链表置为空表
|
|
|
int Length() const; //计算链表的长度
|
|
|
LinkNode<T> *getHead() const
|
|
|
{
|
|
|
return first;
|
|
|
} //返回附加头结点指针
|
|
|
void setHead(LinkNode<T> *p)
|
|
|
{
|
|
|
first = p;
|
|
|
} //设置附加头结点指针
|
|
|
LinkNode<T> *Search(T x); //搜索含数据x的元素
|
|
|
LinkNode<T> *Locate(int i) const; //搜索第i个元素的地址
|
|
|
bool getData(int i, T &x) const; //取出第i个元素
|
|
|
void setData(int i, T &x); //用x修改第i个元素的值
|
|
|
bool Insert(int i, T &x); //在第i个元素后插入x
|
|
|
bool Remove(int i, T &x); //删除第i个元素,x返回该元素的值
|
|
|
bool IsEmpty() const //判断表空否,空返回true
|
|
|
{
|
|
|
return first->link == NULL ? true : false;
|
|
|
}
|
|
|
bool IsFull() const //表不会满
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
//void Sort(); //排序
|
|
|
void inputFront(T endTag); //前插法建立单链表
|
|
|
void inputRear(T endTag); //后插法建立单链表
|
|
|
void output(); //输出
|
|
|
LinkedList<T> &operator=(LinkedList<T> &L); //重载操作符:赋值
|
|
|
///增加部分///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
void input(); //前插法或后插法建立单链表
|
|
|
void output(FILE *fp); //输出
|
|
|
void OrderInsert(const T &item); //有序插入:将x插入到单链表,且插入后单链表所有结点按值从小到大有序。
|
|
|
void Uniquify(); //踢除有序单链表中所有重复的结点
|
|
|
void Uniquify(int &mn, int &cn, int &memn); //踢除有序单链表中所有重复的结点,返回元素值比较次数、元素移动次数和内存字节数
|
|
|
void Merge(const LinkedList<T> &La, const LinkedList<T> &Lb); //将有序单链表La和Lb归并为表*this,且表*this按照值从小到大有序。
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
protected:
|
|
|
LinkNode<T> *first; //链表头指针
|
|
|
};
|
|
|
template <class T>
|
|
|
LinkedList<T>::LinkedList(LinkedList<T> &L)
|
|
|
//复制构造函数
|
|
|
{
|
|
|
T value;
|
|
|
LinkNode<T> *srcptr = L.getHead();
|
|
|
LinkNode<T> *destptr = first = new LinkNode<T>;
|
|
|
while (srcptr->link != NULL)
|
|
|
{
|
|
|
value = srcptr->link->data;
|
|
|
destptr->link = new LinkNode<T>(value);
|
|
|
destptr = destptr->link;
|
|
|
srcptr = srcptr->link;
|
|
|
}
|
|
|
destptr->link = NULL;
|
|
|
}
|
|
|
template <class T>
|
|
|
void LinkedList<T>::makeEmpty()
|
|
|
{ //将链表置为空
|
|
|
LinkNode<T> *q;
|
|
|
if (first == NULL)
|
|
|
return;
|
|
|
while (first->link != NULL)
|
|
|
{
|
|
|
q = first->link;
|
|
|
first->link = q->link;
|
|
|
delete q;
|
|
|
}
|
|
|
}
|
|
|
template <class T>
|
|
|
int LinkedList<T>::Length() const
|
|
|
{ //计算带附加头结点的单链表长度
|
|
|
LinkNode<T> *p = first->link;
|
|
|
int count = 0;
|
|
|
while (p != NULL)
|
|
|
{
|
|
|
p = p->link;
|
|
|
count++;
|
|
|
}
|
|
|
return count;
|
|
|
}
|
|
|
template <class T>
|
|
|
LinkNode<T> *LinkedList<T>::Search(T x)
|
|
|
{ //在表中搜索含数据x的结点,搜索成功时函数返回该结点地址,否则返回NULL值。
|
|
|
LinkNode<T> *current = first->link;
|
|
|
while (current != NULL)
|
|
|
{
|
|
|
if (current->data == x)
|
|
|
break;
|
|
|
else
|
|
|
current = current->link;
|
|
|
}
|
|
|
return current;
|
|
|
}
|
|
|
template <class T>
|
|
|
LinkNode<T> *LinkedList<T>::Locate(int i) const
|
|
|
{ //定位函数,返回表中第i个元素的地址。若i<0或i超出表中结点个数,则返回NULL
|
|
|
if (i < 0) return NULL;
|
|
|
LinkNode<T> *current = first;
|
|
|
int k = 0;
|
|
|
while (current != NULL && k < i)
|
|
|
{
|
|
|
current = current->link;
|
|
|
k++;
|
|
|
}
|
|
|
return current;
|
|
|
}
|
|
|
template <class T>
|
|
|
bool LinkedList<T>::getData(int i, T &x) const
|
|
|
{ //取出链表第i个元素的值
|
|
|
if (i < 0)
|
|
|
return false;
|
|
|
LinkNode<T> *current = Locate(i);
|
|
|
if (current == NULL)
|
|
|
return false;
|
|
|
else
|
|
|
{
|
|
|
x = current->data;
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
template <class T>
|
|
|
void LinkedList<T>::setData(int i, T &x)
|
|
|
{ //给链表第i个元素赋值x
|
|
|
if (i <= 0) return;
|
|
|
LinkNode<T> *current = Locate(i);
|
|
|
if (current == NULL)
|
|
|
return;
|
|
|
else
|
|
|
current->data = x;
|
|
|
}
|
|
|
template <class T>
|
|
|
bool LinkedList<T>::Insert(int i, T &x)
|
|
|
{ //将新元素x插入在链表中第i个结点之后
|
|
|
LinkNode<T> *current = Locate(i);
|
|
|
if (current == NULL)
|
|
|
return false;
|
|
|
LinkNode<T> *newNode = new LinkNode<T>(x);
|
|
|
if (newNode == NULL)
|
|
|
{
|
|
|
cout << "内存分配错误!" << endl;
|
|
|
exit(1);
|
|
|
}
|
|
|
newNode->link = current->link;
|
|
|
current->link = newNode;
|
|
|
return true;
|
|
|
}
|
|
|
template <class T>
|
|
|
bool LinkedList<T>::Remove(int i, T &x)
|
|
|
{ //将链表中第i个元素删除,通过引用类型参数x返回该元素的值
|
|
|
LinkNode<T> *current = Locate(i - 1);
|
|
|
if (current == NULL || current->link == NULL)
|
|
|
return false;
|
|
|
LinkNode<T> *del = current->link;
|
|
|
current->link = del->link;
|
|
|
x = del->data;
|
|
|
delete del;
|
|
|
return true;
|
|
|
}
|
|
|
template <class T>
|
|
|
void LinkedList<T>::output()
|
|
|
{ //单链表的输出函数:将单链表中所有数据按逻辑顺序输出到屏幕上
|
|
|
LinkNode<T> *current = first->link;
|
|
|
while (current != NULL)
|
|
|
{
|
|
|
cout << current->data << " ";
|
|
|
current = current->link;
|
|
|
}
|
|
|
cout << endl;
|
|
|
}
|
|
|
template <class T>
|
|
|
void LinkedList<T>::output(FILE *fp)
|
|
|
{ //单链表的输出函数:将单链表中所有数据按逻辑顺序输出到fp文件上
|
|
|
LinkNode<T> *current = first->link;
|
|
|
while (current != NULL)
|
|
|
{
|
|
|
fprintf(fp, "%d ", current->data);
|
|
|
current = current->link;
|
|
|
}
|
|
|
fprintf(fp, "\n");
|
|
|
}
|
|
|
template <class T>
|
|
|
LinkedList<T> &LinkedList<T>::operator=(LinkedList<T> &L)
|
|
|
{ //重载操作符:赋值操作
|
|
|
T value;
|
|
|
LinkNode<T> *srcptr = L.getHead();
|
|
|
LinkNode<T> *destptr = first = new LinkNode<T>;
|
|
|
while (srcptr->link != NULL)
|
|
|
{
|
|
|
value = srcptr->link->data;
|
|
|
destptr->link = new LinkNode<T>(value);
|
|
|
destptr = destptr->link;
|
|
|
srcptr = srcptr->link;
|
|
|
}
|
|
|
destptr->link = NULL;
|
|
|
return *this;
|
|
|
}
|
|
|
template <class T>
|
|
|
void LinkedList<T>::input()
|
|
|
{
|
|
|
T endTag;
|
|
|
int frontORrear; //前插或后插,值为0前插,值为1后插
|
|
|
cout << "建立单链表使用前插法输入0,使用后插法输入1:";
|
|
|
cin >> frontORrear;
|
|
|
cout << "输入建立结束标志:";
|
|
|
cin >> endTag;
|
|
|
cout << "输入各个数据元素值(最后一个值是结束标志值):";
|
|
|
if (frontORrear == 0)
|
|
|
inputFront(endTag);
|
|
|
else
|
|
|
inputRear(endTag);
|
|
|
}
|
|
|
template <class T>
|
|
|
void LinkedList<T>::inputFront(T endTag)
|
|
|
{ //endTag是约定的输入序列结束标志
|
|
|
LinkNode<T> *newNode;
|
|
|
T val;
|
|
|
makeEmpty();
|
|
|
cin >> val;
|
|
|
while (val != endTag)
|
|
|
{
|
|
|
newNode = new LinkNode<T>(val);
|
|
|
if (newNode == NULL)
|
|
|
{
|
|
|
cerr << "存储分配错误!" << endl;
|
|
|
exit(1);
|
|
|
}
|
|
|
newNode->link = first->link;
|
|
|
first->link = newNode;
|
|
|
cin >> val;
|
|
|
}
|
|
|
}
|
|
|
template <class T>
|
|
|
void LinkedList<T>::inputRear(T endTag)
|
|
|
{ //endTag是约定的输入序列结束标志
|
|
|
LinkNode<T> *newNode, *last;
|
|
|
T val;
|
|
|
makeEmpty();
|
|
|
cin >> val;
|
|
|
last = first;
|
|
|
while (val != endTag)
|
|
|
{
|
|
|
newNode = new LinkNode<T>(val);
|
|
|
if (newNode == NULL)
|
|
|
{
|
|
|
cerr << "存储分配错误!" << endl;
|
|
|
exit(1);
|
|
|
}
|
|
|
last->link = newNode;
|
|
|
last = newNode;
|
|
|
cin >> val;
|
|
|
}
|
|
|
last->link = NULL;
|
|
|
}
|
|
|
template <class T>
|
|
|
void LinkedList<T>::OrderInsert(const T &x) //有序插入数据元素x
|
|
|
{
|
|
|
LinkNode<T> *curr, *pre;
|
|
|
//初始化
|
|
|
curr = first->link; //curr指向首元结点
|
|
|
pre = first; //pre指向头结点
|
|
|
//定位插入位置
|
|
|
while (curr != NULL && curr->data <= x)
|
|
|
{
|
|
|
pre = curr;
|
|
|
curr = curr->link;
|
|
|
}
|
|
|
LinkNode<T> *newNode = new LinkNode<T>(x, pre->link); //申请一个结点并赋值
|
|
|
pre->link = newNode; //把新结点插入在pre所指结点后
|
|
|
}
|
|
|
/***********************************
|
|
|
作业中要实现的部分
|
|
|
***********************************/
|
|
|
//踢除有序单链表中所有重复的结点,要求单链表每个结点被访问一次,且仅被访问一次。尽可能高效。无返回值
|
|
|
template <class T>
|
|
|
void LinkedList<T>::Uniquify()
|
|
|
{
|
|
|
int _;
|
|
|
Uniquify(_, _, _);
|
|
|
//在此添加完成任务1.1的代码
|
|
|
}
|
|
|
//踢除有序单链表中所有重复的结点,要求单链表每个结点被访问一次,且仅被访问一次。尽可能高效。返回元素值比较次数、元素移动次数和内存字节数
|
|
|
template <class T>
|
|
|
void LinkedList<T>::Uniquify(int &mn, int &cn, int &memn)
|
|
|
{
|
|
|
//在此添加完成任务1.2的代码。在(任务1.1)Uniquify()函数的基础上,增加合计并返回算法中元素移动总次数、元素值比较总次数和辅助空间字节总数的代码,测试Uniquify()的高效性。
|
|
|
//算法中如果结点的data域或link域被改变,则mn需累加一次。
|
|
|
//凡出现两个结点的数据域的值比较大小,则cn需累加一次。
|
|
|
//凡出现定义辅助的变量或数组,则memn需累加相应的字节数。C++中sizeof(LinkNode<T>*)为4个字节。
|
|
|
memn = 8;
|
|
|
free(malloc(11));
|
|
|
decltype(first) cur = first, nxt;
|
|
|
while (cur && (nxt = cur->link))
|
|
|
{
|
|
|
while (nxt && cur->data == nxt->data)
|
|
|
{
|
|
|
cur->link = nxt->link;
|
|
|
mn++;
|
|
|
cn++;
|
|
|
delete nxt;
|
|
|
nxt = cur->link;
|
|
|
}
|
|
|
cn++;
|
|
|
cur = nxt;
|
|
|
}
|
|
|
}
|
|
|
//将有序单链表La和Lb归并为表*this,且表*this按照值从小到大有序。要求3个单链表La,Lb,*this每个结点被访问一次,且仅被访问一次。算法尽可能高效。
|
|
|
template <class T>
|
|
|
void LinkedList<T>::Merge(const LinkedList<T> &La, const LinkedList<T> &Lb)
|
|
|
{ //在此添加完成任务2的代码
|
|
|
counter.inc_mem(12);
|
|
|
auto pa = La.first->link, pb = Lb.first->link;
|
|
|
auto nxt = &first->link;
|
|
|
for (; pa && pb; nxt = &(*nxt)->link)
|
|
|
{
|
|
|
if (pa->data < pb->data)
|
|
|
*nxt = new LinkNode<T>(pa->data), pa = pa->link;
|
|
|
else
|
|
|
*nxt = new LinkNode<T>(pb->data), pb = pb->link;
|
|
|
counter.inc_cmp(1);
|
|
|
counter.inc_mov(1);
|
|
|
}
|
|
|
while (pa) *nxt = new LinkNode<T>(pa->data), pa = pa->link, nxt = &(*nxt)->link, counter.inc_mov(1);
|
|
|
while (pb) *nxt = new LinkNode<T>(pb->data), pb = pb->link, nxt = &(*nxt)->link, counter.inc_mov(1);
|
|
|
}
|
|
|
#endif |