单向链表的节点类模板和链表类模板
2015-06-16 11:55
447 查看
1.定义结点类模板:CNode.h
插入操作算法:
删除操作算法:
2.链表类模板的定义:
3.测试代码:
测试结果:
来自清华大学MOOC课件
插入操作算法:
删除操作算法:
#ifndef CNODE_INCLUDE_H #define CNODE_INCLUDE_H //结点类模板的定义 template <class T> class CNode{ private: CNode<T> *next; //指向后继结点的指针(指针域) public: T data; //数据域 CNode(const T& data, CNode<T> *next = 0); //构造函数 void InsertAfter(CNode<T> *p); //在本节点之后插入一个同类结点p CNode<T>* DeleteAfter(); //删除本节点的后继结点,并返回其地址 CNode<T>* NextNode(); //获取后继结点的地址 const CNode<T> *NextNode()const; //获取后继结点的地址(常函数) }; /*构造函数*/ template <class T> CNode<T>::CNode(const T& data, CNode<T> *next = 0) :data(data), next(next){} /*返回后继结点的指针*/ template <class T> CNode<T>* CNode<T>::NextNode() { return next; } /*在当前结点之后插入一个结点p*/ template <class T> void CNode<T>::InsertAfter(CNode<T> *p) { p->next = next; //p结点指针域指向当前节点的后继结点 next = p; //当前节点的指针域指向p } /*删除当前结点的后继结点,并返回其地址*/ template <class T> CNode<T>* CNode<T>::DeleteAfter() { CNode<T> *tempPtr = next; //将欲删除的节点地址存储到tempPtr if (next == 0) //如果当前节点没有后继结点,则返回空指针 return 0; next = tempPtr->next; //使当前节点的指针域指向tempPtr的后继结点 return tempPtr; } #endif
2.链表类模板的定义:
#ifndef LINKEDLIST_INCLUDE_H #define LINKEDLIST_INCLUDE_H #include "CNode.h" //链表类模板 template <class T> class LinkedList{ private: //私有数据成员 CNode<T> *front, *rear; //表头和表尾指针 CNode<T> *prevPtr, *currPtr; //记录当前遍历位置的指针,由插入和删除操作更新 int size; //表中的元素个数 int position; //当前元素在表中的位置序号,由函数reset使用 //私有函数成员,用于本类的内部函数调用 CNode<T>* NewNode(const T& item, CNode<T>* ptrNext = NULL); //生成新节点,数据域为item,指针域为ptrNext void FreeNode(CNode<T>* p); //释放节点 void Copy(const LinkedList<T>& L); //将链表L拷贝到当前表(假设当前表为空),被拷贝构造函数,operator=调用 public: //共有成员函数 LinkedList(); //构造函数 LinkedList(const LinkedList<T> &L); //拷贝构造函数 ~LinkedList(); //析构函数 LinkedList<T>& operator=(const LinkedList<T>& L); //重载赋值运算符 int GetSize()const; //返回链表中的元素个数 bool IsEmpty()const; //链表是否为空 void ReSet(int pos = 0); //初始化游标的位置 void Next(); //使游标移动到下一个节点 bool EndOfList()const; //游标是否到了链尾 int CurrentPosition()const; //返回游标当前的位置 void InsertFront(const T& item); //在表头插入结点 void InsertRear(const T& item); //在表尾插入结点 void InsertAt(const T& item); //在当前结点之前插入结点 void InsertAfter(const T& item); //在当前结点之后插入结点 T DeleteFront(); //删除头结点 void DeleteCurrent(); //删除当前结点 T& data(); //返回当前节点成员数据的引用 const T& data()const; //返回当前节点的数据应用(常函数) void Clear(); //清空链表:释放所有结点的内存空间。被析构函数调用 }; /*生成新节点*/ template <class T> CNode<T>* LinkedList<T>::NewNode(const T& item, CNode<T>* ptrNext) { CNode<T>* p; p = new CNode<T>(item, ptrNext); if (p == NULL) { cout << "Memory allocation failure!" << endl; exit(1); } return p; } /*释放节点*/ template <class T> void LinkedList<T>::FreeNode(CNode<T>* p) { delete p; } /*复制链表*/ template <class T> void LinkedList<T>::Copy(const LinkedList<T>& L) { CNode<T> *p = L.front; //p用来遍历L int pos; while (p != NULL) //将L中的每一个元素插入到当前连接表最后 { InsertRear(p->data); p = p->NextNode(); } if (position == -1) //如果链表为空,则返回 return; //在新链表中重新设置prevPtr和currptr prevPtr = NULL; currPtr = front; for (pos = 0; pos != position; pos++) { prevPtr = currPtr; currPtr = currPtr->NextNode(); } } /*构造函数,构造新链表,size为0,positon为-1*/ template <class T> LinkedList<T>::LinkedList() :front(NULL), rear(NULL), prevPtr(NULL), currPtr(NULL), size(0), position(-1){} /*拷贝构造函数*/ template <class T>LinkedList<T>::LinkedList(const LinkedList<T>& L) { front = rear = NULL; prevPtr = currPtr = NULL; size = 0; position = -1; Copy(L); } /*析构函数*/ template <class T> LinkedList<T>::~LinkedList() { Clear(); } /*重载赋值运算符*/ template <class T> LinkedList<T>& LinkedList<T>::operator=(const LinkedList<T>& L) { if (this == &L) //不能将链表赋值给它自身 return *this; Clear(); Copy(L); return *this; } /*获取链表的大小*/ template <class T> int LinkedList<T>::GetSize()const { return size; } /*判断链表是否为空*/ template <class T> bool LinkedList<T>::IsEmpty()const { return size == 0; } /*将链表当前位置设置为pos*/ template <class T>void LinkedList<T>::ReSet(int pos) { int startPos; if (front == NULL) //如果链表为空 return; if (pos<0 || pos>size - 1) //如果指定位置不合法,返回 { cerr << "ReSet:Invalid list position: " << pos << endl; return; } //设置与链表有关的成员 if (pos == 0) //如果pos为0,将指针重新设置到表头 { prevPtr = NULL; currPtr = front; position = 0; } else //否则重新设置currPtr,prevPtr,position { currPtr = front->NextNode(); prevPtr = front; startPos = 1; for (position = startPos; position!=pos; position++) { prevPtr = currPtr; currPtr = currPtr->NextNode(); } } } /*将prevPtr和currPtr先前移动一个结点*/ template <class T>void LinkedList<T>::Next() { if (currPtr != NULL) { prevPtr = currPtr; currPtr = currPtr->NextNode(); position++; } } /*判断是否已到达链表尾*/ template <class T> bool LinkedList<T>::EndOfList()const { return currPtr == NULL; } /*返回当前节点的位置*/ template <class T> int LinkedList<T>::CurrentPosition()const { return position; } /*将item插入在表头*/ template <class T> void LinkedList<T>::InsertFront(const T& item) { if (front != NULL) //如果链表不为空,则调用ReSet() ReSet(); InsertAt(item); //在表头插入 } /*在表尾插入结点*/ template <class T> void LinkedList<T>::InsertRear(const T& item) { CNode<T> *nNode; prevPtr = rear; nNode = NewNode(item); //创建新节点 if (rear == NULL) //如果表为空,则插入在表头 front = rear = nNode; else { rear->InsertAfter(nNode); rear = nNode; } currPtr = rear; position = size; size++; } /*将item插入在当前位置*/ template <class T> void LinkedList<T>::InsertAt(const T& item) { CNode<T> *nNode; if (prevPtr == NULL) //插入在链表头,包括将结点插入到空表中 { nNode = NewNode(item, front); front = nNode; } else //插入到链表之中,将结点置于prevPtr之后 { nNode = NewNode(item); prevPtr->InsertAfter(nNode); } if (prevPtr == rear)//正在向空表中插入,或者是插入到非空表的表尾 { rear = nNode; //更新rear position = size; //更新position } currPtr = nNode; //更新currPtr size++; //更新szie } /*将item插入到当前位置之后*/ template <class T>void LinkedList<T>::InsertAfter(const T& item) { CNode<T> *p; p = NewNode(item); if (front == NULL) //向空链表中插入 { front = currPtr = rear = p; position = 0; } else //插入到 { if (currPtr == NULL) currPtr = prevPtr; currPtr->InsertAfter(p); if (currPtr == rear) { rear = p; position = szie; } else position++; prevPtr = currPtr; currPtr = p; } size++; //更新链表长度 } /*删除表头结点*/ template <class T> T LinkedList<T>::DeleteFront() { T item; ReSet(); if (front == NULL) { cerr << "Invalid deletion!" << endl; exit(1); } item = currPtr->data; DeleteCurrent(); return item; } /*删除链表当前位置的结点*/ template <class T> void LinkedList<T>::DeleteCurrent() { CNode<T> *p; if (currPtr == NULL)//如果链表为空或者到达表尾 { cerr << "Invalid deletion!" << endl; exit(1); } if (prevPtr == NULL) //删除操作发生在表头或者表中 { p = front; //保存头结点地址 front = front->NextNode(); //将其从链表分离 } else //分离prevPtr之后的一个内部结点,保存其地址 { p = prevPtr->DeleteAfter(); } if (p == rear) //如果尾节点被删除 { rear = prevPtr; //新的表尾是prevPtr position--; //position回退一步 } currPtr = p->NextNode(); //使currPtr越过被删除的结点 FreeNode(p); //释放节点,并使链表长度减- size--; } //返回一个当前节点的数值引用 template <class T>T& LinkedList<T>::data() { if (size == 0 || currPtr == NULL) //如果链表为空,或者到达链表尾 { cerr << "Data:invalid reference!" << endl; exit(1); } return currPtr->data; } /*清空链表*/ template <class T> void LinkedList<T>::Clear() { CNode<T> *currPosition, *nextPosition; currPosition = front; while (currPosition != NULL) { nextPosition = currPosition->NextNode(); //取得下一个结点的地址 FreeNode(currPosition);//删除当前节点 currPosition = nextPosition; //当前指针移到下一个结点 } front = rear = NULL; prevPtr = currPtr = NULL; size = 0; position = -1; } #endif
3.测试代码:
#include <iostream> #include "LinkedList.h" using namespace std; int main() { LinkedList<int> list; for (int i = 0; i < 10; i++) { int item; cin >> item; list.InsertFront(item); //在表头插入 } cout << "list:"; list.ReSet(); while (!list.EndOfList()) { cout << list.data() << " "; list.Next(); //指针下移 } cout << endl; int key; //词条,用于删除 cout << "Please enter some integer needed to be deleted:"; cin >> key; list.ReSet(); while (!list.EndOfList()) { if (list.data() == key) list.DeleteCurrent(); list.Next(); //指针下移 } cout << "list:"; list.ReSet(); while (!list.EndOfList()) { cout << list.data() << " "; list.Next(); } cout << endl; return 0; }
测试结果:
来自清华大学MOOC课件
相关文章推荐
- C#WinForm控件使用
- Intelj IDEA + Jrebel
- sqlldr加载 数据文件的字段超出最大长度
- jQuery查找事件
- 118删除单元格(扩展知识:添加单元格和移动单元格的位置)
- n个骰子的点数
- 整理AngularJS中的一些常用指令
- Express.js 中文入门指引手册
- PowerShell批量分离SMTP邮箱,并以此创建新用户邮箱
- PowerShell批量分离SMTP邮箱,并以此创建新用户邮箱
- C primer plus(第五版)第十七章链表list.h,list.c,films3.c编译警告原因
- MFC基于对话框的菜单栏,工具栏和状态栏的创建
- ruby实现网页图片抓取
- 项目中发现Element类下无getTextContent函数
- POJ 1860 Bellman-Ford算法
- 12-1路径初识
- 逆向思维 PMC云化数据中心的“技术”革命
- Android日志打印命令
- hive到hbase创建映射表以及添加数据
- IOS三方开源框架总结