算法导论 XOR双向循环链表——内存高效链表

来源:互联网 发布:淘宝亿次元 编辑:程序博客网 时间:2024/05/23 01:24

XOR双向循环链表——内存高效链表

1. 算法导论原题

10.2-8 ★(★代表题目略有难度)
Explain how to implement doubly linked lists using only one pointer value x.np per item instead of the usual two(next and pre). Assume that all pointer values can be interpreted as k-bit integers, and define x.np to be x.np = x.next XOR x.pre,the k-bit“exclusive-or” of x.next and x.pre.(The value NIL is represented by 0.) Be sure to describe what information you need to access the head of the list. Show how to implement the SEARCH, INSERT, and DELETE operations on such a list. Also show how to reverse such a list in O(1) time.
译:解释如何在每个结点里不用两个指针(next指针和pre指针),而是只使用一个指针x.np实现双链表(译者注:x指结点对象)。假设所有指针指都是k位二进制的整数,并且定义x.np为x.next XOR x.pre(即x.next和x.pre的k位按位异或)。确保描述你需要进入链表第一个结点的所有信息。展示在这样一个链表如何实现搜索、插入和删除操作。同时展示如何在O(1)的时间复杂度内反转链表。

2. XOR双向循环链表如何实现?

跟普通双向链表不同的是,指向前结点的指针pre和指向后结点的指针next都按位异或成一个指针np。
1. 第一个问题,如何通过这一个指针np来遍历链表呢?
按位异或有这样一个功能:已知A^B=C,那么有C^A=B,C^B=A。(注意的是顺序不影响按位异或的结果,A^B等价于B^A)(若不能理解按位异或的功能请看更详细的参考博文[1]《深入理解按位异或运算符》)。那么同理已知prev^next=NP,那么next^NP=preprev^NP=next。也就是说假设这里有链表已知两个结点A,B(且A的下一个结点就是B),那么要得到B的下一个结点C,只需要将结点A的地址(B.pre)和B.NP进行按位异或,就得到结点C的地址(B.next)。同理要得到结点A的前一个结点(A.pre),只需要将A.NP和结点B的地址(A.next)进行按位异或即可。(若不能理解这一点,请看更详细的参考博文[2]《XOR Linked List – A Memory Efficient Doubly Linked List》)。
2. 第二个问题,如何得到链表第一个结点?
因为要两个结点才能访问下一个结点,所以我们将链表定义为两个结点的结合(头结点和尾结点),而不是原来只有一个头节点。这样每次循环都可以通过当前两个结点来访问到下一个结点。
3. 第三个问题,如何在O(1)时间内反转链表?
因为在开始遍历的时候,我们将尾结点的地址和头结点的NP按位异或得到头节点的下一个结点。我们知道只要通过两个结点就可以访问上一个或下一个结点(即头节点的地址和尾结点的NP按位异或得到尾结点的上一个结点),那么只要我们将头节点和尾结点交换,是可以反转这个遍历的顺序的:这个时候尾结点的地址就是原来头节点的地址,头结点的NP就是原来尾结点的NP,所以链表会按照从原来头节点到原来尾结点的顺序进行遍历。

3. C++ 实现

//XORCircularDoubleLink.h#pragma once#include <assert.h>#include <stdio.h>#include "Util.h"template<typename ElemType>class Node{public:    Node(ElemType* pData = NULL, Node<ElemType>* pNext = NULL, Node<ElemType>* pPrev = NULL);    ElemType* const& GetData() const;    void SetData(ElemType* val);    ElemType* HavaData();    Node<ElemType>* GetNext(Node<ElemType>* prevNode) const;    Node<ElemType>* GetPrev(Node<ElemType>* nextNode) const;    Node<ElemType>* const& GetNP() const ;    void SetNP(Node<ElemType>* prevNode, Node<ElemType>* nextNode);private:    ElemType* m_pData;    Node<ElemType>* m_pNP;};template<typename ElemType>class XORCircularDoubleLink{public:    XORCircularDoubleLink();    unsigned int const& GetLength() const;    bool Insert(ElemType elem, unsigned int pos);    bool Delete(unsigned int pos, ElemType* elem);    bool Search(unsigned int pos, ElemType* elem) const;    bool Visit(ElemType* elem, const unsigned int& pos) const;    bool Empty();    bool Reverse();    Node<ElemType>* HavaHeadNode();    Node<ElemType>* const& GetHeadNode() const;private:    //移动Prev、Current、Next指针    void MoveNCP(int offset, Node<ElemType>** pPrev, Node<ElemType>** pCurrent, Node<ElemType>** pNext) const;    //检测位置是否超出范围    bool OutOfRangeDectection(unsigned int pos, bool canEuqalLength = false) const;private:    Node<ElemType>* m_pHeadNode;    Node<ElemType>* m_pTailNode;    unsigned int m_length;};//————————————————————————————————//Node类的实现template<typename ElemType>inline Node<ElemType>::Node(ElemType* pData /* = NULL */, Node<ElemType>* pNext /* = NULL */,     Node<ElemType>* pPrev /* = NULL */)    :m_pData(pData),m_pNP(Util::XOR(pPrev,pNext)){}template<typename ElemType>inline void Node<ElemType>::SetNP(Node<ElemType>* prevNode , Node<ElemType>* nextNode){    m_pNP = Util::XOR<Node<ElemType>*>(prevNode,nextNode);}template<typename ElemType>inline Node<ElemType>* const& Node<ElemType>::GetNP() const{    return m_pNP;}template<typename ElemType>inline Node<ElemType>* Node<ElemType>::GetNext(Node<ElemType>* prevNode) const{    return Util::XOR<Node<ElemType>*>(prevNode,m_pNP);}template<typename ElemType>inline ElemType* const& Node<ElemType>::GetData() const {    return m_pData;}template<typename ElemType>inline void Node<ElemType>::SetData(ElemType* val){    m_pData = val; }template<typename ElemType>inline ElemType* Node<ElemType>::HavaData() {    return m_pData; }template<typename ElemType>inline Node<ElemType>* Node<ElemType>::GetPrev(Node<ElemType>* nextNode) const{    return Util::XOR<Node<ElemType>*>(nextNode,m_pNP);}//————————————————————————————————//XORCircularDoubleLink类实现template<typename ElemType>inline XORCircularDoubleLink<ElemType>::XORCircularDoubleLink()    :m_pHeadNode(new Node<ElemType>()),m_length(0),m_pTailNode(new Node<ElemType>()){    m_pHeadNode->SetNP(m_pTailNode,m_pTailNode);    m_pTailNode->SetNP(m_pHeadNode,m_pHeadNode);}template<typename ElemType>inline bool XORCircularDoubleLink<ElemType>::Insert(ElemType elem, unsigned int pos){    OutOfRangeDectection(pos,true);    Node<ElemType> *pCurrentNode = NULL, *pPrevNode = NULL, *pNextNode = NULL;    MoveNCP(pos,&pPrevNode,&pCurrentNode,&pNextNode);    Node<ElemType>* insertNode = new Node<ElemType>(new ElemType(elem),pCurrentNode,pNextNode);    pCurrentNode->SetNP(pPrevNode,insertNode);    pNextNode->SetNP(insertNode,pNextNode->GetNext(pCurrentNode));    ++m_length;    return true;}template<typename ElemType>inline bool XORCircularDoubleLink<ElemType>::Delete(unsigned int pos, ElemType* elem){    OutOfRangeDectection(pos);    Node<ElemType> *pCurrentNode = NULL, *pPrevNode = NULL, *pNextNode = NULL;    MoveNCP(pos+1,&pPrevNode,&pCurrentNode,&pNextNode);    *elem = *pCurrentNode->GetData();    pPrevNode->SetNP(pPrevNode->GetPrev(pCurrentNode),pNextNode);    pNextNode->SetNP(pPrevNode,pNextNode->GetNext(pCurrentNode));    --m_length;    delete pCurrentNode;    return true;}template<typename ElemType>inline unsigned int const& XORCircularDoubleLink<ElemType>::GetLength() const{    return m_length;}template<typename ElemType>inline bool XORCircularDoubleLink<ElemType>::Search(unsigned int pos, ElemType* elem) const{    OutOfRangeDectection(pos);    Node<ElemType> *pCurrentNode = NULL, *pPrevNode = NULL, *pNextNode = NULL;    MoveNCP(pos,&pPrevNode,&pCurrentNode,&pNextNode);    *elem = *pNextNode->GetData();    return true;}template<typename ElemType>inline bool XORCircularDoubleLink<ElemType>::Visit(ElemType* elem, const unsigned int& pos) const{    OutOfRangeDectection(pos);    return Search(pos,elem);}template<typename ElemType>inline bool XORCircularDoubleLink<ElemType>::Empty(){    return !m_length;}template<typename ElemType>inline Node<ElemType>* XORCircularDoubleLink<ElemType>::HavaHeadNode(){    return m_pHeadNode;}template<typename ElemType>inline Node<ElemType>* const& XORCircularDoubleLink<ElemType>::GetHeadNode() const{    return m_pHeadNode;}template<typename ElemType>inline bool XORCircularDoubleLink<ElemType>::Reverse(){    Util::Swap(&m_pHeadNode,&m_pTailNode);    return true;}template<typename ElemType>void XORCircularDoubleLink<ElemType>::MoveNCP(int offset, Node<ElemType>** pPrev, Node<ElemType>** pCurrent, Node<ElemType>** pNext) const{    *pPrev = m_pTailNode;    *pCurrent = m_pHeadNode;    *pNext = (*pCurrent)->GetNext(*pPrev);    while(offset-- != 0)    {        *pPrev = *pCurrent;        *pCurrent = *pNext;        *pNext = (*pCurrent)->GetNext(*pPrev);    }}template<typename ElemType>inline bool XORCircularDoubleLink<ElemType>::OutOfRangeDectection(unsigned int pos, bool canEqualLength) const{    if ( (pos > GetLength() || pos < 0)        || (!canEqualLength && pos == GetLength()) )    {        assert(false && "Error: SinglyLink's search pos is out of range!\n");        return true;    }    return false;}
//Util.h#pragma oncenamespace Util{    template<typename T>    void PrintMemory(const T& dateStruct, unsigned int size)    {        cout << "PrintMemory: ";        for (int i = 0; i != size; i++)        {            ElemType tempElem;            if (!dateStruct.Visit(&tempElem,i))            {                printf("\n");                return;            }            printf("%d ",tempElem);        }        printf("\n");    }    template<typename T>    T XOR(T const& lhs, T const& rhs)    {        return (T)(((unsigned long)lhs)^((unsigned long)rhs));    }    template<typename T>    void Swap(T* lhs, T* rhs)    {        *rhs = XOR(*lhs,*rhs);        *lhs = XOR(*lhs,*rhs);        *rhs = XOR(*lhs,*rhs);    }}
//main.cpp#include "Util.h"#include "XORCircularDoubleLink.h"#include <iostream>using namespace std;typedef int ElemType;int main(){    XORCircularDoubleLink<int> testXORCircularDoubleLink;    cout << "testXORCircularDoubleLink is " << (testXORCircularDoubleLink.Empty() ? "Empty." : "Not Empty.") << endl;    Util::PrintMemory(testXORCircularDoubleLink,testXORCircularDoubleLink.GetLength());    for (int i = 0; i != 5; i++)    {        testXORCircularDoubleLink.Insert(i+1,i);        cout << "\nInsert:" << i+1 << endl;        cout << "testXORCircularDoubleLink is " << (testXORCircularDoubleLink.Empty() ? "Empty." : "Not Empty.") << endl;        Util::PrintMemory(testXORCircularDoubleLink,testXORCircularDoubleLink.GetLength());    }    testXORCircularDoubleLink.Reverse();    cout << "\nReverse testXORCircularDoubleLink..." << endl;    Util::PrintMemory(testXORCircularDoubleLink,testXORCircularDoubleLink.GetLength());    for (int i = 0; i != 2; i++)    {        ElemType tempElem;        testXORCircularDoubleLink.Delete(i,&tempElem);        cout << "\nDelete:" << tempElem << endl;        cout << "testXORCircularDoubleLink is " << (testXORCircularDoubleLink.Empty() ? "Empty." : "Not Empty.") << endl;        Util::PrintMemory(testXORCircularDoubleLink,testXORCircularDoubleLink.GetLength());    }    return 0;}

4. 程序运行结果

testXORCircularDoubleLink is Empty.
PrintMemory:

Insert:1
testXORCircularDoubleLink is Not Empty.
PrintMemory: 1

Insert:2
testXORCircularDoubleLink is Not Empty.
PrintMemory: 1 2

Insert:3
testXORCircularDoubleLink is Not Empty.
PrintMemory: 1 2 3

Insert:4
testXORCircularDoubleLink is Not Empty.
PrintMemory: 1 2 3 4

Insert:5
testXORCircularDoubleLink is Not Empty.
PrintMemory: 1 2 3 4 5

Reverse testXORCircularDoubleLink…
PrintMemory: 5 4 3 2 1

Delete:5
testXORCircularDoubleLink is Not Empty.
PrintMemory: 4 3 2 1

Delete:3
testXORCircularDoubleLink is Not Empty.
PrintMemory: 4 2 1

5. 参考博文

1. 《深入理解按位异或运算符》:http://blog.csdn.net/sinat_24229853/article/details/48573065
2. 《XOR Linked List – A Memory Efficient Doubly Linked List》:http://blog.csdn.net/sinat_24229853/article/details/48573557(虽然全文英语,但单词都是很简单的,所以本人不作翻译)

1 0
原创粉丝点击