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

C++数据结构: 链表

2015-11-14 21:15 423 查看
我用Java写的链表是带头尾节点的双向链表,这次用C++透彻一点,不带头尾节点的单向链表。

实现了一些常用方法,没顺序表详细。

链表的查找、插入、删除的时间复杂度都是O(N)。因为它要遍历到指定位置,如果在原地进行上述操作的话,时间复杂度为O(1)。

但总归是比不过顺序表,这大概就是为什么我们总是被教导:大部分时间都只需要vector(ArrayList)!

但链表还是有它自己的优势的,以它为基础的高级数据结构能有更好地性能。

#include <iostream>
#include <Windows.h>
#include <sstream>
#include "ArrayListException.h"
using namespace std;

template <typename T>
class LNode
{
public:
T element;//存放数据
LNode<T> *next;//指向下一个节点

LNode(const T &e, LNode<T> *nxt=nullptr)
:element(e),next(nxt) {}
};

template <typename T>
class CppLinkedList //不带头结点的单项链表
{
private:
unsigned list_size;//链表长度
LNode<T> *firstNode;//第一个节点
void checkIndex(unsigned idx) const;
public:
CppLinkedList() :list_size(0), firstNode(nullptr) {}//初始化链表
CppLinkedList(const CppLinkedList<T> &c);//拷贝复制
~CppLinkedList();

//返回表是否为空
bool isEmpty() { return list_size == 0; }
//返回表中元素数
unsigned size() const { return list_size; }
//在末端插入元素e
void add_back(const T &e);
//在索引出插入元素e
void insert(unsigned idx, const T &e);
//获取索引出元素的引用
T get(unsigned idx) const;
//将索引出元素值改为e
void set(unsigned idx, const T &e);
//删除索引出元素
void erase(unsigned idx);
//返回元素的索引
int indexOf(const T &e) const;
//删除一个范围内的元素,[s , r)
void removeRange(int s, int r);
//打印
void print_list() const;

//forward iterator
class iterator;
iterator begin() { return iterator(firstNode); }
iterator end() { return iterator(NULL); }

class iterator
{
public:
// 类定义
typedef forward_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;

// 构造器
iterator(LNode<T>* theNode = NULL)
{
node = theNode;
}

// 解引用
T& operator*() const { return node->element; }
T* operator->() const { return &node->element; }

iterator& operator++()   // 前置++
{
node = node->next;
return *this;
}
iterator operator++(int) // 后置++
{
iterator old = *this;
node = node->next;
return old;
}

bool operator!=(const iterator right) const
{
return node != right.node;
}
bool operator==(const iterator right) const
{
return node == right.node;
}
protected:
LNode<T>* node;
};
};

template <typename T>
CppLinkedList<T>::CppLinkedList(const CppLinkedList<T> &c)
:list_size(c.list_size),firstNode(nullptr)
{
if (list_size == 0)
return;

LNode<T> *srcNode = c.firstNode;
firstNode = new LNode<T>(srcNode->element,nullptr);
LNode<T> *currentNode = firstNode;

while (srcNode->next != nullptr)
{
currentNode->next = new LNode<T>(srcNode->next->element, nullptr);
srcNode = srcNode->next;
currentNode = currentNode->next;
}
}

template <typename T>
CppLinkedList<T>::~CppLinkedList()
{
while (firstNode != nullptr)
{
LNode<T> *currentNode = firstNode;
cout << currentNode->element << " ";
firstNode = firstNode->next;
delete currentNode;
currentNode = firstNode;
}
}

template <typename T>//O(1) 检查get、erase、操作符[]的索引
void CppLinkedList<T>::checkIndex(unsigned idx) const
{
if (idx < 0 || idx >= list_size)
throw invalidIndex("index out of range");
}

template <typename T>//O(N)
void CppLinkedList<T>::add_back(const T &e)
{
LNode<T> *newNode = new LNode<T>(e, nullptr);
++list_size;//在if语句前++,免得写两遍
if (list_size == 1)
{
firstNode = newNode;
return;
}
LNode<T> *currentNode = firstNode;
for (int i = 0; i < list_size - 2; ++i)
currentNode = currentNode->next;

currentNode->next = newNode;
}

template <typename T>//O(N)
void CppLinkedList<T>::insert(unsigned idx, const T &e)
{
if (idx < 0 || idx > list_size)//检查索引位置
throw invalidIndex("index out of range!");

if (idx == 0)//插入第一个位置
firstNode = new LNode<T>(e, firstNode);
else {
LNode<T> *currentNode = firstNode;
//让currenetNode跑到索引的前一个位置
for (int i = 0; i < idx - 1; ++i)
currentNode = currentNode->next;

currentNode->next = new LNode<T>(e, currentNode->next);
}
++list_size;
}

template <typename T>//O(N)
T CppLinkedList<T>::get(unsigned idx) const
{
checkIndex(idx);
LNode<T> *currentNode = firstNode;
//遍历到索引位置
for (int i = 0; i < idx; ++i)
currentNode = currentNode->next;

return currentNode->element;
}

template <typename T>//O(N)
void CppLinkedList<T>::set(unsigned idx, const T &e)
{
checkIndex(idx);
LNode<T> *currentNode = firstNode;
for (int i = 0; i < idx; ++i)
currentNode = currentNode->next;

currentNode->element = e;
}

template <typename T>//O(N),因为要遍历到索引位置,索引还是会花费线性时间。删除操作只花费常数时间。
void CppLinkedList<T>::erase(unsigned idx)
{
checkIndex(idx);
LNode<T> *currentNode = firstNode;
if (idx == 0)
{
firstNode = firstNode->next;
delete currentNode;
}
else
{
for (int i = 0; i < idx - 1; ++i)
currentNode = currentNode->next;

LNode<T> *oldNode = currentNode->next;
currentNode->next = oldNode->next;
delete oldNode;
}
--list_size;
}

template <typename T>
void CppLinkedList<T>::removeRange(int s, int r)
{
//检查索引合法性
if (s > r) {
ostringstream st;
st << s << "必须小于等于" << r;
throw invalidIndex(st.str());
}
checkIndex(s);
checkIndex(r - 1);

LNode<T> *leftNode = firstNode;
for (int i = 0; i < s - 1; ++i)//到s的前一个元素
leftNode = leftNode->next;

if (s == 0)
leftNode = new LNode<T>(firstNode->element, firstNode);

LNode<T> *rightNode = leftNode->next;
for (int i = 0; i < r - s; ++i)//到索引为r的元素
{
LNode<T> *deleteNode = rightNode;
rightNode = rightNode->next;
delete deleteNode;
}

leftNode->next = rightNode;
list_size -= (r - s);

if (s == 0)
{
delete leftNode;
firstNode = rightNode;
}
}

template <typename T>//O(N)
int CppLinkedList<T>::indexOf(const T &e) const
{
LNode<T> *currenetNode = firstNode;

for (int i = 0; i < list_size; ++i)
{
if (currenetNode->element == e)
return i;
currenetNode = currenetNode->next;
}
return -1;
}

template <typename T>//O(N)
void CppLinkedList<T>::print_list() const
{
LNode<T> *currentNode = firstNode;
while (currentNode != nullptr)
{
cout << currentNode->element << " ";
currentNode = currentNode->next;
}
cout << endl;
}

int main()
{
CppLinkedList<int> c;
for (int i = 0; i < 100; ++i)
c.add_back(i);
CppLinkedList<int> d = c;

d.removeRange(0,100);

d.print_list();

cout << d.indexOf(8899) << " " << d.indexOf(55) <<" " << d.size()<< endl;
system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: