一、链表
链表是一种动态集合,它是由一系列元素组成的一个列表。
数组也可以实现列表这种数据结构,但数组是静态的,而链表是动态。
通常,我们定义一个结点类(或结构体)来表示链表的元素,它由两部分组成:数值域和指针域。数值域存储当前结点的键,指针域存储下一个节点的地址。
template <class Type>
struct nodeType
{
Type info;
nodeType<Type> *link;
};
链表的一些基本操作如下:
- 初始化为空表
- 判断是否为空
- 打印(遍历)链表
- 计算链表的长度
- 删除整个链表
- 获取第一个节点的键
- 获取最后一个节点的键
- 查找指定键
- 插入一个键
- 删除指定键
- 复制链表
大致的链表类图如下所示:
与其它的定义可能有所不同,这里维护了两个指针,头指针和尾指针,尾指针是为了方便某些操作,如返回最后一个元素。同时,还维护了一个int型变量来表示链表中元素的个数。这种额外的开销在实际应用时可能不可取,但为某些操作带来很大的便利。
插入和删除以及查找函数定义为纯虚函数,这是因为有序链表和无序链表的相关操作不一样,所以由它们自己实现。这也意味着这个类是抽象类。
注意:上图中有两个陌生的公共成员函数:begin()和end(),它们返回一个迭代器类型(个人喜欢这样叫)的对象。迭代器对象可以很方便地实现链表的遍历等操作,它的类图如下:
下面给出链表类的代码实现:linkedListType.h,这里把结点类和迭代器类的定义也放在这个文件了。由于用到了模板,只能把实现代码也放在定义文件内,看起来会比较长哦。
#ifndef _LINKEDLISTTYPE_H
#define _LINKEDLISTTYPE_H
#include "stdafx.h"
//节点类定义
template <class Type>
struct nodeType
{
Type info;
nodeType<Type> *link;
};
//迭代器类定义
template <class Type>
class linkedListIterator
{
public:
linkedListIterator(); //构造函数
linkedListIterator(nodeType<Type> *ptr); //复制构造函数
Type operator*(); //解引用操作符重载
linkedListIterator<Type> operator++(); //自增操作符重载
bool operator==(const linkedListIterator<Type>& right) const; //相等操作符重载
bool operator!=(const linkedListIterator<Type>& right) const; //不等操作符重载
private:
nodeType<Type> *current; //当前结点
};
//链表类定义
template <class Type>
class linkedListType
{
public:
linkedListType(); //构造函数
linkedListType(const linkedListType<Type>& otherList); //复制构造函数
~linkedListType(); //析构函数
const linkedListType<Type>& operator=(const linkedListType<Type>&); //重载赋值操作符
void initializeList(); //初始化为空表
bool isEmptyList() const; //判空
void print() const; //遍历链表
int length() const; //长度
void destroyList(); //销毁链表
Type front() const; //返回第一节点的键
Type back() const; //返回最后一个节点的键
virtual bool search(const Type& searchItem) const = 0;
virtual void insertFirst(const Type& newItem) = 0;
virtual void insertLast(const Type& newItem) = 0;
virtual void deleteNode(const Type& deleteItem) = 0;
linkedListIterator<Type> begin();
linkedListIterator<Type> end();
protected:
int count;
nodeType<Type> *first;
nodeType<Type> *last;
private:
void copyList(const linkedListType<Type>& otherList);
};
//下面是链表类的实现
template <class Type>
linkedListType<Type>::linkedListType()
{
first = NULL;
last = NULL;
count = 0;
}
template <class Type>
linkedListType<Type>::linkedListType(const linkedListType<Type>& otherList)
{
first = NULL;
copyList(otherList);
}
template <class Type>
linkedListType<Type>::~linkedListType() //destructor
{
destroyList();
}
template <class Type>
const linkedListType<Type>& linkedListType<Type>::operator=(const linkedListType<Type>& otherList)
{
if (this != &otherList)
{
copyList(otherList);
}
return *this;
}
template <class Type>
bool linkedListType<Type>::isEmptyList() const
{
return (first == NULL);
}
template <class Type>
void linkedListType<Type>::destroyList()
{
nodeType<Type> *temp; //临时保存当前需删除的节点
while (first != NULL)
{
temp = first;
first = first->link;
delete temp;
}
last = NULL;
count = 0;
}
template <class Type>
void linkedListType<Type>::initializeList()
{
destroyList();
}
template <class Type>
void linkedListType<Type>::print() const
{
nodeType<Type> *current;
current = first;
while (current != NULL)
{
cout << current->info << " ";
current = current->link;
}
}
template <class Type>
int linkedListType<Type>::length() const
{
return count;
}
template <class Type>
Type linkedListType<Type>::front() const
{
assert(first != NULL);
return first->info;
}
template <class Type>
Type linkedListType<Type>::back() const
{
assert(last != NULL);
return last->info;
}
template <class Type>
linkedListIterator<Type> linkedListType<Type>::begin()
{
linkedListIterator<Type> temp(first);
return temp;
}
template <class Type>
linkedListIterator<Type> linkedListType<Type>::end()
{
linkedListIterator<Type> temp(NULL);
return temp;
}
template <class Type>
void linkedListType<Type>::copyList(const linkedListType<Type>& otherList)
{
nodeType<Type> *newNode; //新建结点
nodeType<Type> *current; //当前需复制的结点
if (first != NULL) //先清空
destroyList();
if (otherList.first == NULL) //如果otherList是空表
{
first = NULL;
last = NULL;
count = 0;
}
else
{
count = otherList.count;//元素个数
//复制第一个元素
current = otherList.first;
first = new nodeType<Type>;
first->info = current->info;
first->link = NULL;
last = first;
//复制下一个元素
current = current->link;
while (current != NULL)
{
newNode = new nodeType<Type>;
newNode->info = current->info;
newNode->link = NULL;
last->link = newNode;
last = newNode;
current = current->link;
}
}
}
//下面是迭代器类的实现
template <class Type>
linkedListIterator<Type>::linkedListIterator()
{
current = NULL;
}
template <class Type>
linkedListIterator<Type>::linkedListIterator(nodeType<Type> *ptr)
{
current = ptr;
}
template <class Type>
Type linkedListIterator<Type>::operator*()
{
return current->info;
}
template <class Type>
linkedListIterator<Type> linkedListIterator<Type>::operator++()
{
current = current->link;
return *this;
}
template <class Type>
bool linkedListIterator<Type>::operator==(const linkedListIterator<Type>& right) const
{
return (current == right.current);
}
template <class Type>
bool linkedListIterator<Type>::operator!=(const linkedListIterator<Type>& right) const
{
return (current != right.current);
}
#endif
二、无序链表
无序链表是相对有序列表而言的,它们在插入和删除操作的区别非常大,比如:
有序链表每插入一个元素都要找到正确的位置,而无序链表则可以随意在表头或表尾插入。
我们让无序链表继承链表ADT,这样可得到无序链表的类图:
下面是无序链表的编程实现:unorderedLinkedList.h
#include "stdafx.h"
#include "linkedListType.h"
template <class Type>
class unorderedLinkedList: public linkedListType<Type>
{
public:
bool search(const Type& searchItem) const; //查找
void insertFirst(const Type& newItem); //从表头插入
void insertLast(const Type& newItem); //从表尾插入
void deleteNode(const Type& deleteItem); //删除
};
template <class Type>
bool unorderedLinkedList<Type>::search(const Type& searchItem)const
{
nodeType<Type> *current;
current = first;
while (current != NULL)
if (current->info == searchItem)
return true;
else
current = current->link;
return false;
}
template <class Type>
void unorderedLinkedList<Type>::insertFirst(const Type& newItem)
{
//从表头插入一个元素
nodeType<Type> *newNode; //新建一个结点
newNode = new nodeType<Type>;
newNode->info = newItem;
newNode->link = first;
first = newNode;
//总的元素个数加1
count++;
//如果是空表,则最后一个元素就是当前插入的元素,所以让last指向它
if (last == NULL)
last = newNode;
}
template <class Type>
void unorderedLinkedList<Type>::insertLast(const Type& newItem)
{
nodeType<Type> *newNode;
newNode = new nodeType<Type>;
newNode->info = newItem;
newNode->link = NULL;
if (first == NULL) //空表的情况:first==NULL,这时插入的节点既是头结点也是尾结点
{
first = newNode;
last = newNode;
count++; //元素个数加一
}
else //不为空表的情况:这时只要调整尾结点指针
{
last->link = newNode; //从尾部插入
last = newNode; //调整last指针
count++;
}
}
template <class Type>
void unorderedLinkedList<Type>::deleteNode(const Type& deleteItem)
{
nodeType<Type> *current; //遍历链表用的游标
nodeType<Type> *trailCurrent; //游标的上一个位置
bool found; //标记是否找到指定元素
if (first == NULL) //情况1:空表
cout << "Cannot delete from an empty list."<< endl;
else
{
if (first->info == deleteItem) //情况2:第一个元素即为需要删除的元素
{
current = first;
first = first->link;
count--;
if (first == NULL) //删除完后检查是否为空:为空则调整last指针
last = NULL;
delete current;
}
else //情况3:不是第一个元素,那只能一步步往下找了,找到了删掉它,没找到提示用户
{
found = false;
trailCurrent = first; //目前游标的上一个位置是first,即第一个元素
current = first->link; //目前游标的位置是first后面的元素,即第二个元素
while (current != NULL && !found)
{
if (current->info != deleteItem)
{
trailCurrent = current;
current = current-> link;
}
else
found = true;
}
if (found) //情况3.a:找到了,删掉它
{
trailCurrent->link = current->link;
count--;
if (last == current) //被删元素是最后一个元素,调整last指针
last = trailCurrent;
delete current; //记得释放内存哦
}
else //情况3.b:没有找到,提示用户删除失败
cout << "The item to be deleted is not in "<< "the list." << endl;
}
}
}
三、有序链表
有序链表中的元素都是按顺序链接的,第一个元素最小,最后一个元素最大,可以有重复元素。
让有序链表继承链表类,其类图如下:
与无序链表不同的是它多了一个insert函数,因为有序链表从表头表尾插入都没实际意义,它们都要通过找到合适的位置再插入,所以定义了一个一般的插入方法来实现它们。
有序链表的操作相对无序链表比较复杂一点,下面以插入函数为例介绍分析方法。
插入一个元素:我们按照遍历链表查找第一个大于插入元素的情景进行分类
用一个current指针代表当前的游标元素,用一个trailCurrent指针指向current上一个元素
情况1:表为空,这时直接插入就可以,同时需要调整first和last指针,count+1
情况2:插入元素比表里所有的元素都小,即插入位置为表头,这时插入的同时要调整first指针,同时count+1
情况3:插入元素的位置不不在表头,它在某个地方
3.a:插入元素比表中所有元素都大,也就是说没有找到比他大的元素,这时它插入表尾,需要调整last指针,count+1
3.b: 插入元素在表中间的某个位置。first和last都不需调整,只需count+1
有序链表的编程实现:orderedLinkedList.h
#include "linkedListType.h"
template <class Type>
class orderedLinkedList: public linkedListType<Type>
{
public:
bool search(const Type& searchItem) const;
void insert(const Type& newItem);
void insertFirst(const Type& newItem);
void insertLast(const Type& newItem);
void deleteNode(const Type& deleteItem);
};
template <class Type>
bool orderedLinkedList<Type>::search(const Type& searchItem) const
{
bool found = false;
nodeType<Type> *current; //遍历链表的游标
current = first; //从第一个元素开始查找
while (current != NULL && !found)
if (current->info >= searchItem)
found = true;
else
current = current->link;
if (found)
found = (current->info == searchItem); //测试一下
return found;
}
template <class Type>
void orderedLinkedList<Type>::insert(const Type& newItem)
{
nodeType<Type> *current; //遍历链表的游标
nodeType<Type> *trailCurrent; //游标的上一个元素
nodeType<Type> *newNode; //新插入的元素
bool found;//标记是否找到大于newItem的元素
newNode = new nodeType<Type>;
newNode->info = newItem;
newNode->link = NULL;
if (first == NULL) //情况1:空表,直接插入
{
first = newNode;
last = newNode;
count++;
}
else
{
//从第一个结点开始遍历,看能不能找到值大于newItem的元素,找到了就插入它前面,没找到就插入尾部
current = first;
found = false;
while (current != NULL && !found)
if (current->info >= newItem)//找到就标记
found = true;
else
{
trailCurrent = current;
current = current->link;
}
if (current == first) //情况2:第一个元素就大于newItem,插入位置为链表头,需要调整first
{
newNode->link = first;
first = newNode;
count++;
}
else //情况3:插入位置不在链表头,可能在链表尾,即可能需要调整last
{
trailCurrent->link = newNode;
newNode->link = current;
if (current == NULL)//插入链表尾部,需要调整last
last = newNode;
count++;
}
}
}
template <class Type>
void orderedLinkedList<Type>::insertFirst(const Type& newItem)
{
insert(newItem);
}
template <class Type>
void orderedLinkedList<Type>::insertLast(const Type& newItem)
{
insert(newItem);
}
template <class Type>
void orderedLinkedList<Type>::deleteNode(const Type& deleteItem)
{
nodeType<Type> *current; //遍历链表的游标
nodeType<Type> *trailCurrent; //游标的上一个元素
bool found; //标记是否找到等于newItem的元素
if (first == NULL) //情况1:空表,不能删除
cout << "Cannot delete from an empty list." << endl;
else
{
//从第一个元素开始向后遍历,看能不能找到等于deleteItem的元素
current = first;
found = false;
while (current != NULL && !found)
if (current->info >= deleteItem)//注意,我们找到大于等于的元素就标记,这个元素不一定等于deleteItem
found = true;
else
{
trailCurrent = current;
current = current->link;
}
if (current == NULL) //情况2:没有找到
cout << "The item to be deleted is not in the " << "list." << endl;
else
if (current->info == deleteItem)
{
if (first == current) //情况3:第一个元素等于newItem
{
first = first->link;
if (first == NULL)//删除完成后判断是否为空,如果为空则调整尾指针
last = NULL;
delete current;//记得释放内存
}
else //情况4:不在第一个位置找到了等于newItem的元素
{
trailCurrent->link = current->link;
if (current == last)//如果是最后一个元素,则删除之后要调整尾指针
last = trailCurrent;
delete current;
}
count--;
}
else
cout << "The item to be deleted is not in the "<< "list." << endl;
}
}