您的位置:首页 > 理论基础 > 数据结构算法

数据结构基础(11) --循环链表的设计与实现

2016-01-28 15:27 453 查看
循环链表:最后一个结点的指针域的指针又指回第一个结点的链表;



循环单链表与单链表的区别在于:表中最有一个节点的指针不再是NULL, 而改为指向头结点(因此要对我们原来的MyList稍作修改), 从而整个链表形成一个环.

因此, 循环单链表的判空条件不再是头结点的指针是否为空, 而是他是否等于头结点;

其实如果只是单纯的实现循环链表对单链表的性能提升是不明显的, 反而增加了代码上实现的复杂度, 但是如果与下一篇中的双向链表相结合的话, 在速度上的提升是十分惊人的, 因此这篇博客权当做是一个过渡吧, 为上一篇博客和下一篇博客的结合起着承上启下的作用.

下面是MyList.h的完整代码与解析, 由于代码较多, 希望能够仔细阅读, 但其实下面的大部分代码都与前面类似只是对其中几处稍作修改, 遇到与单链表的不同之处, 我会与++符号作为注释指出:

[cpp] view
plain copy

#ifndef MYLIST_H_INCLUDED

#define MYLIST_H_INCLUDED

#include <iostream>

#include <stdexcept>

using namespace std;

//循环链表

//前向声明

template <typename Type>

class MyList;

template <typename Type>

class ListIterator;

//链表节点

template <typename Type>

class Node

{

//可以将MyList类作为Node的友元

//同时也可以将Node类做成MyList的嵌套类, 嵌套在MyList中, 也可以完成该功能

friend class MyList<Type>;

friend class ListIterator<Type>;

template <typename T>

friend ostream &operator<<(ostream &os, const MyList<T> &list);

private:

//constructor说明:

//next = NULL; //因为这是一个新生成的节点, 因此下一个节点为空

Node(const Type &dataValue):data(dataValue), next(NULL) {}

Type data; //数据域:节点数据

Node *next; //指针域:下一个节点

};

//链表

template <typename Type>

class MyList

{

template <typename T>

friend ostream &operator<<(ostream &os, const MyList<T> &list);

friend class ListIterator<Type>;

public:

MyList();

~MyList();

//将元素插入表头

void insertFront(const Type &data);

//将元素插入到位置index上(index从1开始)

void insert(const Type &data, int index);

//删除表中所有值为data的节点

void remove(const Type &data);

bool isEmpty() const;

private:

//指向第一个节点的指针

Node<Type> *first;

};

template <typename Type>

MyList<Type>::MyList()

{

//first指向一个空节点

first = new Node<Type>(0);

// ++ 这是一个关键点

//first的下一个元素就指向first

//此时, 代表链表是否已经到达结尾处的判断已经不再是(是否等于NULL)

//而改为(是否等于first)

//因为此时first代表链表的最后一个元素

//同时,first又是第一个元素的前一个元素

first -> next = first;

}

template <typename Type>

MyList<Type>::~MyList()

{

Node<Type> *deleteNode = NULL;

// ++ 保存链表尾元素

Node<Type> *tmp = first;

// ++ first首先指向第一个真实的元素

first = first->next;

//一路到达链表结尾

while (first != tmp)

{

deleteNode = first;

first = first -> next;

delete deleteNode;

}

// ++ 释放到链表的空节点

delete tmp;

}

//这一步与前一版链表相同

template <typename Type>

void MyList<Type>::insertFront(const Type &data)

{

Node<Type> *newNode = new Node<Type>(data);

newNode -> next = first -> next;

first -> next = newNode;

}

template <typename Type>

void MyList<Type>::insert(const Type &data, int index)

{

//由于我们在表头添加了一个空节点

//因此如果链表为空, 或者在链表为1的位置添加元素

//其操作与在其他位置添加元素相同

int count = 1;

//此时searchNode肯定不为first

Node<Type> *searchNode = first;

//++ 注意:此处将NULL修改为first

// 找到要插入的位置

// 如果所给index过大(超过了链表的长度)

// 则将该元素插入到链表表尾

// 原因是 searchNode->next != first 这个条件已经不满足了

while (count < index && searchNode->next != first)

{

++ count;

searchNode = searchNode->next;

}

// 插入链表

Node<Type> *newNode = new Node<Type>(data);

newNode->next = searchNode->next;

searchNode->next = newNode;

}

template <typename Type>

void MyList<Type>::remove(const Type &data)

{

if (isEmpty())

return ;

Node<Type> *previous = first; //保存要删除节点的前一个节点

for (Node<Type> *searchNode = first->next;

//searchNode != NULL; // ++ 注意此处不再是判断是否为NULL

searchNode != first; // ++ 而是不能等于first, first代表链表的末尾

searchNode = searchNode->next)

{

if (searchNode->data == data)

{

previous->next = searchNode->next;

delete searchNode;

//重新调整searchNode指针

//继续遍历链表查看是否还有相等元素

// ++ 注意

//如果当前searchNode已经到达了最后一个节点

//也就是searchNode->next已经等于first了, 则下面这条语句不能执行

if (previous->next == first)

break;

searchNode = previous->next;

}

previous = searchNode;

}

}

//注意判空条件

template <typename Type>

bool MyList<Type>::isEmpty() const

{

return first->next == first;

}

//显示链表中的所有数据(测试用)

template <typename Type>

ostream &operator<<(ostream &os, const MyList<Type> &list)

{

for (Node<Type> *searchNode = list.first -> next;

searchNode != list.first; //++ 注意

searchNode = searchNode -> next)

{

os << searchNode -> data;

if (searchNode -> next != list.first) // ++ 注意(尚未达到链表的结尾)

cout << " -> ";

}

return os;

}

//ListIterator 除了判空函数的判空条件之外, 没有任何改变

template <typename Type>

class ListIterator

{

public:

ListIterator(const MyList<Type> &_list):

list(_list),

currentNode((_list.first)->next) {}

//重载 *operator

const Type &operator*() const throw (std::out_of_range);

Type &operator*() throw (std::out_of_range);

//重载 ->operator

const Node<Type> *operator->() const throw (std::out_of_range);

Node<Type> *operator->() throw (std::out_of_range);

//重载 ++operator

ListIterator &operator++() throw (std::out_of_range);

//注意:此处返回的是值,而不是reference

ListIterator operator++(int) throw (std::out_of_range);

bool isEmpty() const;

private:

const MyList<Type> &list;

Node<Type> *currentNode;

};

template <typename Type>

bool ListIterator<Type>::isEmpty() const

{

// ++ 注意:判空条件改为list.first

if (currentNode == list.first)

return true;

return false;

}

template <typename Type>

const Type &ListIterator<Type>::operator*() const

throw (std::out_of_range)

{

if (isEmpty())

throw std::out_of_range("iterator is out of range");

// 返回当前指针指向的内容

return currentNode->data;

}

template <typename Type>

Type &ListIterator<Type>::operator*()

throw (std::out_of_range)

{

//首先为*this添加const属性,

//以调用该函数的const版本,

//然后再使用const_case,

//将该函数调用所带有的const属性转除

//operator->()的non-const版本与此类同

return

const_cast<Type &>(

static_cast<const ListIterator<Type> &>(*this).operator*()

);

}

template <typename Type>

const Node<Type> *ListIterator<Type>::operator->() const

throw (std::out_of_range)

{

if (isEmpty())

throw std::out_of_range("iterator is out of range");

//直接返回指针

return currentNode;

}

template <typename Type>

Node<Type> *ListIterator<Type>::operator->()

throw (std::out_of_range)

{

// 见上

return

const_cast<Node<Type> *> (

static_cast<const ListIterator<Type> >(*this).operator->()

);

}

template <typename Type>

ListIterator<Type> &ListIterator<Type>::operator++()

throw (std::out_of_range)

{

if (isEmpty())

throw std::out_of_range("iterator is out of range");

//指针前移

currentNode = currentNode->next;

return *this;

}

template <typename Type>

ListIterator<Type> ListIterator<Type>::operator++(int)

throw (std::out_of_range)

{

ListIterator tmp(*this);

++ (*this); //调用前向++版本

return tmp;

}

#endif // MYLIST_H_INCLUDED

附-测试代码:

[cpp] view
plain copy

int main()

{

MyList<int> iMyList;

for (int i = 0; i < 10; ++i) //1 2 3 4 5 6 7 8 9 10

iMyList.insert(i+1, i+1);

for (int i = 0; i < 5; ++i) //40 30 20 10 0 1 2 3 4 5 6 7 8 9 10

iMyList.insertFront(i*10);

iMyList.insertFront(100);//100 40 30 20 10 0 1 2 3 4 5 6 7 8 9 10

iMyList.remove(10); //100 40 30 20 0 1 2 3 4 5 6 7 8 9

iMyList.remove(8); //100 40 30 20 0 1 2 3 4 5 6 7 9

cout << "------------ MyList ------------" << endl;

for (ListIterator<int> iter(iMyList);

!(iter.isEmpty());

++ iter)

cout << *iter << ' ';

cout << endl;

cout << "Test: \n\t" << iMyList << endl;

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: