双向循环链表的实现

双向循环链表的实现
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 = 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 = 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 == 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 = 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 = current2->data;

current2->data = 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 = 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;

}

双向循环链表的实现

时间: 2024-10-03 10:56:08

双向循环链表的实现的相关文章

第33课 双向循环链表的实现

1. DTLib中双向链表的设计思路 (1)数据结点之间在逻辑上构成双向循环,这有别于Linux内核链表的实现. (2)头结点仅用于结点的定位,而Linux内核链表是将头结点作为循环的一部分. 2. 实现思路 (1)通过模板定义DualCircleList类,继承自DualLinkList类 (2)在DualCircleList内部使用Linux内核链表进行实现(另类实现) (3)使用struct list_head定义DualCircleList的头结点 (4)特殊处理:循环遍历时忽略头结点

双向循环链表 初始化 插入 删除

#include <stdio.h> #include <stdlib.h> #define OK 1 #define ERROR -1 #define TRUE 1 #define FALSE -1 #define NULL 0 #define OVERFLOW -2 #define ElemType int #define Status int typedef int ElemType typedef int Status #define LEN sizeof(DuLNode)

双向循环链表

//双向循环链表 typedef int datatype; //方便修改 //当然也可以写成模板来适应更多的数据类型 struct dclink{ datatype data;//数据定义 struct dclink *pre; struct dclink *next;//前驱和后继指针 }; class DCLink { public: DCLink();//default constructor DCLink(datatype data);//单参constructor void add(

算法导论13:双向循环链表 2016.1.13

今天这个又打了很长时间,本来觉得数据结构就是那样,不过是一种思维,但是实际上真正自己打和想象中差距还是很大,需要考虑到各种细节. 今天这个问题有一个比较有意思的应用,就是“约瑟夫环问题”. 具体可以参见百度百科: http://baike.baidu.com/link?url=poA1Aanlptc6yzP1puYhSw_0RQjRAplhPfHwk6eoiqMNxw6WigCEbexxZ8a9SUbrMGokpPbKNzVYw308xjeEw_ 读完问题就可以发现,这个问题用链表就是一个很完美

C++__双向循环链表(练习)

双向循环链表 link.h #ifndef LINK_H_ #define LINK_H_ #define HEADER 0 #define TAIL -1 typedef int data_type; enum LINK_OP { LINK_ERR = -1, LINK_OK }; class LINK { private: LINK *last; data_type data; LINK *next; public: LINK(); LINK(data_type data); virtual

c语言编程之双向循环链表

双向循环链表就是形成两个环,注意每个环的首尾相连基本就可以了. 程序中采用尾插法进行添加节点. 1 #include<stdio.h> 2 #include<stdlib.h> 3 #define element int 4 typedef struct Node{ 5 element data; 6 struct Node *next; 7 struct Node *prior; 8 }*pNode; 9 10 //build a new double loop list 11

线性表.04.链式存储结构(双向循环链表)

以下是用双向循环链表实现的线性表 #include <stdio.h> #include <stdlib.h> #include <time.h> #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 typedef int ElemType;//ElemType这里假设为int,可以根据需要进行更改 typedef int Status;//Status是函数的类型,其值是函数结果状态代码,如OK等 t

小猪的数据结构辅助教程——2.7 线性表中的双向循环链表

小猪的数据结构辅助教程--2.7 线性表中的双向循环链表 标签(空格分隔): 数据结构 本节学习路线图与学习要点 学习要点: 1.了解引入双向循环链表的原因 2.熟悉双向循环链表的特点以及存储结构 3.掌握双向循环链表的一些基本操作的实现逻辑 4.掌握逆序输出双向循环链表元素逻辑 1.双向循环链表的引入 2.双向循环链表的存储结构 双向循环链表的特点: 上面也说了,空间换时间,比起循环链表只是多了一个指向前驱的指针 特点的话: 判断空表:L ->next = L -> prior = L; 存

C++双向循环链表实现

双向循环链表C++实现 1.单链表: 结构图: 2.双向链表: 3.双向循环链表: 对于本程序中,则是给定一个_head  头结点,而不是指针,因为这样更加方便避免一些空判断问题 /* 版权信息:狼 文件名称:BidCirList.h 文件标识: 文件摘要: 利用C++实现简单的双向链表功能.增,删,查,改 //太烦了..我直接给个 带头结点的 表 //swap 移花接木已经是个给力的方法..just try 当前版本:1.1 作 者:狼 完成时间:2015-12-13 */ #ifndef _

C++双向循环链表

DuLink: #include<iostream> using namespace std; typedef int elemType; typedef struct DulNode { elemType data; DulNode *prior; DulNode *next; }*DuList; void InitList(DuList *L) { *L = new DulNode; (*L)->next = (*L)->prior = *L; } int LengthList