使用单指针实现双链表(C++语言)
来源:互联网 发布:淘宝怎么开通电子面单 编辑:程序博客网 时间:2024/06/03 16:54
本文是Clifford A. Shaffer所著《数据结构与算法分析》(C++版)习题4.4的解答。
链表是常见的数据结构,链表中的结点通常定义如下。
template <typename E> class Link {public: E element; Link<E> *next; Link(const E& it, Link<E>* next) { }};
结点是一个定义为Link的模板类,其元素element的类型E可以代入不同的具体类型,指针成员nex指向下一个结点。只有一个指针的结点只能用于单链表,在使用时需要保存一个头指针head,搜索链表的时候,每次都要从head开始,而且只能向后搜索,不能向前搜索。
双链表中的结点含有两个指针域,分别为prev和next,如下所示。
template <typename E> class Link {public: E element; Link<E> *prev, *next; Link(const E& it, Link<E>* prev, Link<E>* next) { }};双链表在使用时可以保存一个头指针head,一个尾指针next。既可以从head出发向后搜索,也可以从tail出发向前搜索。如果再增加一个当前指针curr,那么在单链表中,只能从curr出发向后搜索,而在双链表中,可以从curr出发向后或者向前搜索。
基于结点类,可以设计链表类,下面的抽象数据类型给出了链表类所需要支持的基本操作。
template <typename E> class List { // List ADTprivate: void operator =(const List&) {} List(const List&) {} public: List() {} virtual ~List() {} virtual void clear() = 0; virtual void insert(const E& item) = 0; virtual void append(const E& item) = 0; virtual E remove() = 0; virtual void moveToStart() = 0; virtual void moveToEnd() = 0; virtual void prev() = 0; virtual void next() = 0; virtual int length() const = 0; virtual int currPos() = 0; virtual void moveToPos(int pos) = 0; virtual const E& getValue() const = 0;};基于带有prev和next指针的结点类Link来说,通过在链表中增加head、tail或者curr成员变量,很容易写出一个双向链表的实现,支持上述抽象类List中的操作。但是,也可以在Link类中只使用一个指针pt,而实现双向链表。主要思想是从这一个指针中,既可以获取prev的内容,也可以获取next的内容。其实现依赖于异或操作的一个重要性质:
(L^R)^R = L, (L^R)^L = R。
可以定义指针pt的值为
pt = prev ^ next。
也就是说,pt是其后向指针next和前向指针prev的异或。那么,当前结点的pt和指向其之前结点的指针在做异或操作,就可以得到指向当前结点之后的结点的指针。当前结点的pt和指向其之后结点的指针做异或操作,就可以得到指向当前结点之前的结点的指针。换言之,在这种形式的双链表中,除了保存head,tail和curr指针指向链表中的不同结点之外,还需要使用两个指针prevp和nextp,分别指向curr结点之前和之后的结点。从当前结点向后移动一步时,可以通过如下语句序列实现。
prevp = curr;curr = nextp;nextp = prevp ^ curr->pt;从当前结点向前一步所对应的语句序列如下。
nextp = curr;curr = prevp;prevp = curr->pt ^ nextp;
当然,链表中多了两个变量prevp和nextp,但是每个结点都节省了一个指针,所以总体而言,这种双链表的实现能够大幅度节省空间。当然这是以搜索时计算步骤增多、时间变长为代价的。
双向链表的具体实现代码如下。
template <typename E> class LList: public List<E> {private: Link<E>* head, *tail, *curr; Link<E> *prevp, *nextp; int cnt; void init() { curr = head = new Link<E>; head->pt = tail = new Link<E>(head, NULL); prevp = NULL; nextp = tail; cnt = 0; } void removeall() { prevp = NULL; while(head != NULL) { curr = head; head = xor_op(prevp, head->pt); prevp = curr; delete curr; } } Link<E>* xor_op(Link<E>* pt1, Link<E>* pt2) { unsigned long op1 = (unsigned long)pt1; unsigned long op2 = (unsigned long)pt2; return (Link<E>*)(op1 xor op2); }public: LList(int size=defaultSize) { init(); } ~LList() { removeall(); } void clear() { removeall(); init(); } void moveToStart() // Place curr at list start { curr = head; prevp = NULL; nextp = head->pt; } void moveToEnd() // Place curr at list end { curr = tail->pt; nextp = tail; prevp = xor_op(tail, curr->pt); } void next() { if (curr != tail->pt) { prevp = curr; curr = nextp; nextp = xor_op(prevp, curr->pt); } } int length() const { return cnt; } // Return the position of the current element int currPos() { Link<E>* temp = head; int i; prevp = NULL; nextp = head->pt; for (i=0; curr != temp; i++){ prevp = temp; temp = nextp; nextp = xor_op(prevp, temp->pt); } return i; } // Move down list to "pos" position void moveToPos(int pos) { Assert ((pos>=0)&&(pos<=cnt), "Position out of range"); curr = head; prevp = NULL; nextp = head->pt; for(int i=0; i<pos; i++) { prevp = curr; curr = nextp; nextp = xor_op(prevp, curr->pt); } } const E& getValue() const { // Return current element if(nextp == tail) return NULL; return nextp->element; } void insert(const E& it) { Link<E> *tmp; tmp = new Link<E>(it, curr, nextp); curr->pt = xor_op(xor_op(curr->pt, nextp), tmp); nextp->pt = xor_op(xor_op(nextp->pt, curr), tmp); nextp = tmp; cnt++; } void append(const E& it) { Link<E> *tmp; tmp = new Link<E>(it, tail->pt, tail); tail->pt->pt = xor_op(xor_op(tail->pt->pt, tail), tmp); tail->pt = tmp; if(nextp == tail) nextp = tmp; cnt++; } E remove() { if(nextp == tail) return NULL; Link<E> *new_next; E it = nextp->element; new_next = xor_op(nextp->pt, curr); curr->pt = xor_op(prevp, new_next); new_next->pt = xor_op(xor_op(nextp, new_next->pt), curr); delete nextp; nextp = new_next; cnt--; return it; } void prev() { if (curr != head) { nextp = curr; curr = prevp; prevp = xor_op(nextp, curr->pt); } }};
0 0
- 使用单指针实现双链表(C++语言)
- c语言指针使用
- 单例模式 (C语言实现)
- C语言矩阵乘法(指针实现)
- 配置文件读写(c语言指针实现)
- C 语言指针,单指针和双指针的学习
- 单/双链表(C和指针P250)
- 单例模式 c语言的实现和使用
- 使用c语言指针和递归方法实现二分查找
- C语言中使用指针实现数组排序
- C语言中使用函数指针实现回调
- 【C语言】使用指针实现交换变量值
- C 语言实现智能指针
- 使用结构和指针(单/双链表)
- C语言 指针的使用
- C语言指针使用陷阱
- C语言指针使用总结
- C语言指针使用小结
- Win10开发:OneDrive SDK 的使用
- C#实现字符串RSA加密与解密算法
- Cheapest Palindrome(DP)
- JAVA 中文乱码的问题
- Python 2.7.x 和 3.x 版本的重要区别小结
- 使用单指针实现双链表(C++语言)
- swift常用字符串处理
- 浏览器环境下JavaScript脚本加载与执行探析之defer与async特性
- Javascript图片预加载详解
- 全面解析Linux 内核 3.10.x - initramfs 启动流程
- Coursea Hadoop课堂笔记——Lesson 1: Big Data Hadoop Stack
- android 获取apk md5值
- android初接触之service1
- EditText 的inputType属性