C++数据结构: 链表
2015-11-14 21:15
423 查看
我用Java写的链表是带头尾节点的双向链表,这次用C++透彻一点,不带头尾节点的单向链表。
实现了一些常用方法,没顺序表详细。
链表的查找、插入、删除的时间复杂度都是O(N)。因为它要遍历到指定位置,如果在原地进行上述操作的话,时间复杂度为O(1)。
但总归是比不过顺序表,这大概就是为什么我们总是被教导:大部分时间都只需要vector(ArrayList)!
但链表还是有它自己的优势的,以它为基础的高级数据结构能有更好地性能。
实现了一些常用方法,没顺序表详细。
链表的查找、插入、删除的时间复杂度都是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; }
相关文章推荐
- SDUT OJ数据结构实验之二叉树三:统计叶子数
- SDUT OJ 数据结构实验之二叉树二:遍历二叉树
- SDUT OJ 数据结构实验之二叉树五:层序遍历
- SDUT OJ 数据结构实验之二叉树七:叶子问题
- 第126讲:Hadoop集群管理之Datanode目录元数据结构详解学习笔记
- Java中常用数据结构的实现类 Collection和Map
- 【数据结构】【输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果】
- 第125讲:Hadoop集群管理之SecondaryNamenode目录元数据结构详解及其内幕机制学习笔记
- 数据结构(Java)——栈的实现总结
- android hal 学习——数据结构整理
- 旭说数据结构之散列表(哈希表)
- 数据结构 (3.3) 栈
- 2015年大二上-数据结构-栈(5)- 后缀表达式
- 【数据结构实验】二叉树的遍历(栈版)
- 旭说数据结构之用两个栈实现队列
- 【数据结构】二叉排序树BST
- 【数据结构】二叉排序树BST
- 将python数据结构导出成字符串并自动缩进格式化
- 旭说数据结构之队列
- 【数据结构】顺序线性表的插入、删除、合并实现