首页 > 代码库 > 双向循环链表的实现
双向循环链表的实现
- 双向循环链表的实现
- 2013-01-11 09:29:04 我来说两句 作者:坚持理想_面对现实
- 收藏 我要投稿
- 在使用链表来解决约瑟夫问题的时候,用到了循环链表。循环链表又分为单向循环链表与双向循环链表,约瑟夫问题采用单项循环链表可以得到很好的而解决了,但是单向链表的很大的缺陷仍然存在,那就是在删除的时候需要两个并排指针同步移动。双向链表就可以解决这个问题,因为在双向链表中的每一个结点都有两个指针域来分别指向其前驱和后继。这样子在遍历链表时不用两个指针,直接使用一个就好,当锁定位置后,取出其前驱然后再保存当前位置最后做删除操作就好了。结点类型不变,存在两个指针:[cpp]#pragma once#include<iostream>using namespace std;template<class T>class LinkNode //节点类{public: //全为公共的方便操作T data; //模板类型的一个数据LinkNode<T> *next; //该结点的一个指针,用于指向后继LinkNode<T> *prior;//用于指向前驱public:LinkNode(LinkNode<T> *ptr = NULL)//只初始化指针的构造函数,并使指针域为空{ next = ptr; prior = ptr; }LinkNode(const T& item,LinkNode<T> *ptr = NULL)//数据与指针一同初始化的构造函数,依旧指针域默认参数为空{ data = http://www.mamicode.com/item; next = ptr; prior = ptr; }~LinkNode(){}};循环链表的关键是环的形成,而最好的方式就是在创建链表的时候就形成环状,笔者采用的是带有头结点的链表,所以在构造函数中就可以创建一个环出来:[cpp]template<class T>List<T>::List(){first = new LinkNode<T>;//构造函数中开辟头结点first->prior = first;//头结点的前后指针均指向其本身 逻辑循环first->next = first;}在每一次的插入和删除之后需要把首尾连接起来,其余操作可看做是普通链表。#pragma once#include"LinkNode.h"#include<iostream>using namespace std;template<class T>//继承的过程中,加上此句派生类依然为类模板class List{protected:LinkNode<T>* first;//封装public:List();List(List<T>& L);~List();void makeEmpty();//依次销毁每个结点的空间int Length() const;//搜索当前表节点数LinkNode<T>* getHead() const;//返回头指针LinkNode<T>* Search(T x) const;//搜索并返回指针LinkNode<T>* Locate(int i) const;//定位并返回指针bool GetData(int i,T& x) const;//返回第i个结点的元素值以引用的形式bool SetData(int i,T& x);//修改第i个结点的元素值bool Insert(int i,T& x);//在第i个节点后面插入新节点元素值LinkNode<T>* Remove(int i,T& x);//删除第i个结点bool isEmpty() const;//判表空void Sort(); //排序void input(T endTag);//建立表并输入void output();//输出表void operator = (List<T>& L);//复制重载};template<class T>List<T>::List(){first = new LinkNode<T>;//构造函数中开辟头结点first->prior = first;//头结点的前后指针均指向其本身 逻辑循环first->next = first;}template<class T>List<T>::List(List<T>& L){LinkNode<T> *L_HEAD = L.getHead();LinkNode<T> *srcptr = L_HEAD->next; //获取头指针 用于遍历LinkNode<T> *destptr = first = new LinkNode<T>;//建立头结点 初始化LinkNode<T> *newNode;T value;while(srcptr != L_HEAD)//直到循环到首指针w为结束{value = http://www.mamicode.com/srcptr->data;newNode = new LinkNode<T>(value);newNode->prior = destptr;//往新链表的后面插入destptr->next = newNode;srcptr = srcptr->next;//后移destptr = destptr->next;}destptr->next = first;//首尾相接 建立循环first->prior = destptr;}template<class T>List<T>::~List(){makeEmpty();}template<class T>void List<T>::makeEmpty() //全部销毁指针资源{LinkNode<T> *current = first->next;LinkNode<T> *del;while(current != first){del = current;current = current->next;delete del;}}template<class T>int List<T>::Length() const{int count = 0;LinkNode<T> *current = first;//头指针副本用于遍历while(current->next != first)//与单链表的遍历控制条件相同,当前结点后后继是否为空{current = current->next;count++ ;}return count;}template<class T>LinkNode<T>* List<T>::getHead() const{return first;}template<class T>LinkNode<T>* List<T>::Search(T x) const{LinkNode<T> *current = first->next;while(current != NULL)//此时的控制条件为某个结点的next知否为空{if(current->data =http://www.mamicode.com/= x)return current;//如果查询到直接函数返回,不用无用操作(如果链表中有多个x元素值,则以第一个为准返回)current = current->next;}return NULL;}template<class T>LinkNode<T>* List<T>::Locate(int i) const{if(i < 0) //定位可以是第0个,也就是头结点指针return NULL;LinkNode<T> *current = first;int k=0;while(current != NULL && k < i)//双条件控制后者其更多的作用{current = current->next;k++;}return current;//指向第i个元素的指针}template<class T>bool List<T>::GetData(int i,T& x) const //参数中有下标值的一般先判断其下标值是否合法{if(i <= 0)return false;LinkNode<T> *current = Locate(i);if(current == NULL)return false;x = current->data;retrun true;}template<class T>bool List<T>::SetData(int i,T& x){if(i <= 0)return false;LinkNode<T> *current = Locate(i);if(current == NULL)return false;current->data = http://www.mamicode.com/x;return true;}template<class T>bool List<T>::Insert(int i,T& x){if(i < 0 )//可以插入在第一个结点之前,有头结点的好处代码一致return false;LinkNode<T> *current = Locate(i);return false;LinkNode<T> *newNode = new LinkNode<T>(x);if(newNode == NULL)return false;newNode->prior = current; //双向链表插入的关键四步,顺序不能变,最后一句必须最后执行newNode->next = current->next;current->next->prior = newNode;current->next = newNode;return true;}template<class T>LinkNode<T>* List<T>::Remove(int i,T& x){if(i <= 0)return NULL;LinkNode<T> *current = Locate(i);//和单链表不同的是,双向链表有前指针可以指向前驱,所以定位到第i个就好if(current ==NULL)return NULL;current->next->prior = current->prior;//双向链表删除操作较为简单明了current->prior->next = current->next;//重新搭链x = current->data;delete current;//销毁指针资源}template<class T>bool List<T>::isEmpty() const{return ((first->next == NULL) ? true : false);}template<class T>void List<T>::input(T endTag){makeEmpty();//在输入前先清空链表LinkNode<T> *newNode,*last = first;T value;cin>>value;while(value != endTag){newNode = new LinkNode<T>(value);newNode->prior = last;last->next = newNode;last = newNode;cin>>value;}last->next = first; //重新首尾连接first->prior = last;}template<class T>void List<T>::output()//输出{cout<<"双向链表输出如下:"<<endl;LinkNode<T> *current = first->next;int count = 0;while(current != first){cout<<"#"<<count+1<<":"<<current->data<<endl;current = current->next;count++;}}template<class T>void List<T>::Sort()//最小选择 排序{LinkNode<T> *current1,*current2;//下面连续取后继指针把外层循环控制在倒数第二个结点for(current1 = first->next ; current1->next != first ; current1 = current1->next){for(current2 = current1->next ; current2 != first ; current2 = current2->next){if(current1->data > current2->data){T temp;temp = current1->data;current1->data = http://www.mamicode.com/current2->data;current2->data = http://www.mamicode.com/temp;}}}}template<class T>void List<T>::operator= (List<T> &L){makeEmpty();//先全部销毁指针资源LinkNode<T> *L_HEAD = L.getHead(); //获取首指针 遍历终止条件LinkNode<T> *srcptr = L_HEAD->next; //获取头指针 用于遍历LinkNode<T> *destptr = first; //= new LinkNode<T>;//不用于赋值初始化,只用于复制,不用建立新头结点LinkNode<T> *newNode;T value;while(srcptr != L_HEAD)//直到最后一个结点的尾指针为空结束{value = http://www.mamicode.com/srcptr->data;newNode = new LinkNode<T>(value);newNode->prior = destptr;//往新链表的后面插入destptr->next = newNode;srcptr = srcptr->next;//后移destptr = destptr->next;}destptr->next = first;//首尾相接 循环first->prior = destptr;}
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。