List-DuLinkedList-将单向循环链表改为双向的
python实现双向循环链表

python实现双向循环链表最近⾝边的朋友在研究⽤python来实现数据结构。
遇到⼀个问题就是双向循环链表的实现,改指向的时候总是发蒙。
我⾃⼰尝实现了⼀个python的双向循环链表。
附上代码,希望对⼤家有帮助。
如果不懂什么是双向循环链表的伙伴,需要补习⼀下数据结构的基础之后哦~~~在python当中⽤⼀个类Node 来实现链表的节点,节点数据有三个变量: prev:前驱指针:⽤于指向当前节点前⼀个节点 next: 后继指针⽤于指向当前节点后⼀个节点 item:值,⽤于存储该节点要存的数值 当前节点的前⼀个节点我们叫他前驱,后⼀个节点我们叫他后继。
在链表类当中,我们有⼀个变量head是链表的头指针我们拿着链表的头head,就可以对他进⾏⼀些列操作:(由于是双向循环链表,修改指针特别容易出错,我尽量说的细致,⽅便⼤家参考)判断空: is_empty() 如果头指针head没有指向则链表是空的否则不是空的在头部添加元素: add(item) 1 新建⼀个节点⾥⾯的值是item。
2 放⼊头部: 2.1 如果链表是空的,node的next和prev都指向⾃⼰,然后head再指向node在尾部添加元素: append(item) 1 创建⼀个新节点node ⾥⾯的值是item 2 放⼊尾部: 2.1 如果链表空,则执⾏头部添加add就可以 2.2 链表⾮空: 2.2.1 node的next指向head 2.2.2 node的prev指向head的prev 2.2.3 head的prev元素的next指向node 2.2.4 head的prev指向改为node 2.2.5 head指向node 更换了头部指定位置添加元素: insert( pos , item ) 1 新建⼀个节点node ⾥⾯的值是item 2 找到合适的位置插进去: 2.1 如果pos <= 0 还⼩,那就执⾏头插⽅法 add() 2.2 如果pos >= 链表长度, 那就执⾏尾部插⼊ append() 2.3 如果pos位置在链表的中间: 2.3.1 定义⼀个临时变量temp 按照传⼊的pos找到要插⼊的位置的前⼀个元素 2.3.2 node的prev设为temp,node的next设为temp的next 2.3.3 temp的next指向的节点的prev改为node 2.3.4 temp的next改为node得到链表长度: length() 1 我们设置⼀个临时变量temp初始设为head ,设置⼀个计数器count 初始为 0 2 令count⾃增1 然后temp改指向⾃⼰的下⼀个元素⼀直到temp遇到None 为⽌,temp到了链表的最后⼀个元素 通过这样的⽅式,统计出⼀共有多少个节点返回遍历链表数据: travelji() 1 设置⼀个临时变量temp初始化设为head 2 temp 每次输出⾃⼰指向元素的值,然后在指向⾃⼰的下⼀个元素,⼀直temp为None 说明到了列表的尾部删除链表元素: remove( item ) 1 开启temp临时变量初始化为head , 2 temp不断指向⾃⼰的下⼀个元素,每次指向⼀个元素都检查当前值是不是item,如果找到item则删除它返回True,如果没找到就到尾部了就返回False 2.1 删除过程: 2.1.1 temp的前⼀个元素的next改为temp的后⼀个元素 2.1.2 temp的后⼀个元素的prev改为前⼀个元素查询是否有元素:search() 设置⼀个临时变量temp从head开始,不断指向⾃⼰下⼀个,每次都检查⼀下⾃⼰的值如果和item相同返回True结束 如果temp变成None 则到尾部了都没找到返回False上代码!1#链表的节点2class Node(object):3def__init__(self , item ):4 self.item = item #节点数值5 self.prev = None #⽤于指向前⼀个元素6 self.next = None #⽤于指向后⼀个元素7#双向循环链表8class DoubleCircleLinkList(object):9def__init__(self):10 self.__head = None #初始化的时候头节点设为空、11#判断链表是否为空,head为None 的话则链表是空的12def is_empty(self):13return self.__head is None14#头部添加元素的⽅法15def add(self,item):16 node = Node(item) #新建⼀个节点node ⾥⾯的值是item17# 如果链表是空的,则node的next和prev都指向⾃⼰(因为是双向循环),head指向node18if self.is_empty():19 self.__head = node20 node.next = node21 node.prev = node22# 否则链表不空23else:24 node.next = self.__head#node的next设为现在的head25 node.prev = self.__head.prev #node的prev 设为现在head的prev26 self.__head.prev.next = node #现在head的前⼀个元素的next设为node27 self.__head.prev = node #现在head的前驱改为node28 self.__head = node #更改头部指针29#尾部添加元素⽅法30def append(self , item):31#如果当前链表是空的那就调⽤头部插⼊⽅法32if self.is_empty():33 self.add(item)34#否则链表不为空35else :36 node = Node(item) #新建⼀个节点node37#因为是双向循环链表,所以head的prev其实就是链表的尾部38 node.next = self.__head#node的下⼀个设为头39 node.prev = self.__head.prev #node的前驱设为现在头部的前驱40 self.__head.prev.next = node #头部前驱的后继设为node41 self.__head.prev = node #头部⾃⼰的前驱改为node42#获得链表长度节点个数43def length(self):44#如果链表是空的就返回045if self.is_empty():46return 047#如果不是空的48else:49 cur = self.__head#临时变量cur表⽰当前位置初始化设为头head50 count = 1 #设⼀个计数器count,cur每指向⼀个节点,count就⾃增1 ⽬前cur指向头,所以count初始化为1 51#如果cur.next不是head,说明cur⽬前不是最后⼀个元素,那么count就1,再让cur后移⼀位52while cur.next is not self.__head:53 count += 154 cur = cur.next55#跳出循环说明所有元素都被累加了⼀次返回count就是⼀共有多少个元素56return count57#遍历链表的功能58def travel(self):59#如果当前⾃⼰是空的,那就不遍历60if self.is_empty():61return62#链表不空63else :64 cur = self.__head#临时变量cur表⽰当前位置,初始化为链表的头部65#只要cur的后继不是头说明cur不是最后⼀个节点,我们就输出当前值,并让cur后移⼀个节点66while cur.next is not self.__head:67print( cur.item,end="" )68 cur = cur.next69#当cur的后继是head的时候跳出循环了,最后⼀个节点还没有打印值在这⾥打印出来70print( cur.item )7172#置顶位置插⼊节点73def insert(self, pos , item ):74#如果位置<=0 则调⽤头部插⼊⽅法75if pos <= 0:76 self.add(item)77#如果位置是最后⼀个或者更⼤就调⽤尾部插⼊⽅法78elif pos > self.length() - 1 :79 self.append(item)80#否则插⼊位置就是链表中间81else :82 index = 0 #设置计数器,⽤于标记我们后移了多少步83 cur = self.__head#cur标记当前所在位置84#让index每次⾃增1 ,cur后移,当index=pos-1的时候说明cur在要插⼊位置的前⼀个元素,这时候停下 85while index < pos - 1 :86 index += 187 cur = cur.next88#跳出循环,cur在要插⼊位置的前⼀个元素,将node插⼊到cur的后⾯89 node = Node(item) #新建⼀个节点90 node.next = cur.next #node的后继设为cur的后继91 node.prev = cur #node的前驱设为cur92 cur.next.prev = node #cur后继的前驱改为node93 cur.next = node #cur后继改为node94#删除节点操作95def remove(self,item):96#如果链表为空直接不操作97if self.is_empty():98return99#链表不为空100else:101 cur = self.__head#临时变量标记位置,从头开始102#如果头结点就是要删除的元素103if cur.item == item:104#如果只有⼀个节点链表就空了 head设为None105if self.length() == 1:106 self.__head = None107#如果多个元素108else:109 self.__head = cur.next #头指针指向cur的下⼀个110 cur.next.prev= cur.prev #cur后继的前驱改为cur的前驱111 cur.prev.next = cur.next #cur前驱的后继改为cur的后继112#否则头节点不是要删除的节点我们要向下遍历113else:114 cur = cur.next #把cur后移⼀个节点115#循环让cur后移⼀直到链表尾元素位置,期间如果找得到就删除节点,找不到就跳出循环,116while cur is not self.__head:117#找到了元素cur就是要删除的118if cur.item == item:119 cur.prev.next = cur.next #cur的前驱的后继改为cur的后继120 cur.next.prev = cur.prev #cur的后继的前驱改为cur的前驱121 cur = cur.next122#搜索节点是否存在123def search(self , item):124#如果链表是空的⼀定不存在125if self.is_empty():126return False127#否则链表不空128else:129 cur = self.__head#设置临时cur从头开始130# cur不断后移,⼀直到尾节点为⽌131while cur.next is not self.__head:132#如果期间找到了就返回⼀个True 结束运⾏133if cur.item == item:134return True135 cur = cur.next136# 从循环跳出来cur就指向了尾元素看⼀下为元素是不是要找的是就返回True137if cur.item ==item:138return True139#所有元素都不是就返回False 没找到140return False141142143if__name__ == "__main__":144 dlcl = DoubleCircleLinkList()145print(dlcl.search(7))146 dlcl.travel()147 dlcl.remove(1)148print(dlcl.length())149print(dlcl.is_empty())150 dlcl.append(55)151print(dlcl.search(55))152 dlcl.travel()153 dlcl.remove(55)154 dlcl.travel()155print(dlcl.length())156 dlcl.add(3)157print(dlcl.is_empty())158 dlcl.travel()159 dlcl.add(4)160 dlcl.add(5)161 dlcl.append(6)162 dlcl.insert(-10,1)163 dlcl.travel()164print(dlcl.length())165 dlcl.remove(6)166 dlcl.travel()167168print(dlcl.search(7) )169 dlcl.append(55)170 dlcl.travel()各种数据结构主要是思想,不同的⼈实现⽅式都不⼀定⼀样,同⼀个⼈多次实现也不⼀定⼀样。
详解Linux内核之双向循环链表

详解Linux内核之双向循环链表本文详解了内核中面向对象的list结构的原理,以及如何以list为内嵌对象来构造自己的链表结构,如何从内嵌list对象获得自定义的对象指针;探讨了各种宏或者函数的详细使用方法及怎样以通用list结构来操作自定义对象。
【关键字】双向循环链表,list,list_entry,typeof,containerof,list_for_each, list_for_each_entry1、双循环链表传统实现2、Linux内核中双循环链表实现3、定义和初始化4、通用链表操作接口4.1添加节点4.2删除节点4.3移动节点4.4链表判空4.5链表合并5、获取宿主对象指针6、遍历6.1 List-head链表遍历6.2遍历宿主对象7、如何使用Linux中的双循环链表、双循环链表传统实现在传统的双循环链表实现中,如果创建某种数据结构的双循环链表,通常采用的办法是在这个数据结构的类型定义中加入两个(指向该类型对象的)指针next 和prev。
例如:typedef struct foo {…struct foo *prev;struct foo *next;…} foo_t;这里给出了对应的节点结构、空的双循环链表和非空的双循环链表示意图。
、Linux内核中双循环链表实现在linux内核中,有大量的数据结构需要用到双循环链表,例如进程、文件、模块、页面等。
若采用双循环链表的传统实现方式,需要为这些数据结构维护各自的链表,并且为每个链表都要设计插入、删除等操作函数。
因为用来维持链表的next和prev指针指向对应类型的对象,因此一种数据结构的链表操作函数不能用于操作其它数据结构的链表。
在Linux源代码树的include/linux/list.h文件中,采用了一种类型无关的双循环链表实现方式。
其思想是将指针prev和next从具体的数据结构中提取出来构成一种通用的"双链表"数据结构list_head。
Java基础之:List——LinkedList

Java基础之:List——LinkedListLinkedList简单介绍LinkedList实现了双向链表(数据结构)和双端队列特点。
实现了List接口,可以添加任意元素(即可以重复和null),线程不安全。
LinkedList底层实现分析1.LinkedList底层维护了一个双向链表2.LinkedList中维护了两个属性first和last,分别指向首节点和尾节点3.每个节点(数据结构中将节点都称作Node对象),里面又维护了prev、next、item三个属性。
其中prev指向前一个Node,next指向后一个Node,最终实现双向链表。
4.所以LinkedList的元素添加与删除不是通过数组完成的,效率较高。
模拟最简单的双向链表:package class_LinkedList;public class ClassT est01_DoubleLinkedList {public static void main(String[] args) {Node first = null;//首先定义一个first节点,作为标记位置存在//当添加一个节点时,让first节点指向此节点Node node1 = new Node(first, null, "小范");first = node1;//添加第二个节点,在构造时,让第二个节点的prev属性指向前一个节点node1Node node2 = new Node(node1, null, "小黄");node1.next = node2; //让node1的next指向node2,实现双向连接//添加第三个节点Node node3 = new Node(node2, null, "小雨");node2.next = node3;//结尾,使用last节点,让last节点指向node3,因为node3的next为null代表链表结束Node last = node3;//链表遍历,通常都使用一个临时temp节点来用于遍历链表,不要使用first!Node temp = first;//链表从前向后遍历System.out.println("==========从前向后============");while(true) {System.out.println(temp);if(temp.next == null) { //last节点的next属性为nullbreak;temp = temp.next; //将temp向后移}//链表从后向前遍历System.out.println("==========从后向前============");temp = last;while(true) {System.out.println(temp);if(temp.prev == null) { //first节点的prev属性为nullbreak;}temp = temp.prev; //将temp向前移}//添加节点,让需要添加位置的前后节点分别指向要添加的节点即可。
数据结构线性表答案 (1)

第一章线性表2.1 描述以下三个概念的区别:头指针,头结点,首元结点(第一个元素结点)。
解:头指针是指向链表中第一个结点的指针。
首元结点是指链表中存储第一个数据元素的结点。
头结点是在首元结点之前附设的一个结点,该结点不存储数据元素,其指针域指向首元结点,其作用主要是为了方便对链表的操作。
它可以对空表、非空表以及首元结点的操作进行统一处理。
2.2 填空题。
解:(1) 在顺序表中插入或删除一个元素,需要平均移动表中一半元素,具体移动的元素个数与元素在表中的位置有关。
(2) 顺序表中逻辑上相邻的元素的物理位置必定紧邻。
单链表中逻辑上相邻的元素的物理位置不一定紧邻。
(3) 在单链表中,除了首元结点外,任一结点的存储位置由其前驱结点的链域的值指示。
(4) 在单链表中设置头结点的作用是插入和删除首元结点时不用进行特殊处理。
2.3 在什么情况下用顺序表比链表好?解:当线性表的数据元素在物理位置上是连续存储的时候,用顺序表比用链表好,其特点是可以进行随机存取。
2.4 对以下单链表分别执行下列各程序段,并画出结果示意图。
解:2.5 画出执行下列各行语句后各指针及链表的示意图。
L=(LinkList)malloc(sizeof(LNode)); P=L; for(i=1;i<=4;i++){P->next=(LinkList)malloc(sizeof(LNode)); P=P->next; P->data=i*2-1;}P->next=NULL;for(i=4;i>=1;i--) Ins_LinkList(L,i+1,i*2); for(i=1;i<=3;i++) Del_LinkList(L,i);解:2.6 已知L是无表头结点的单链表,且P结点既不是首元结点,也不是尾元结点,试从下列提供的答案中选择合适的语句序列。
a. 在P结点后插入S结点的语句序列是__________________。
严蔚敏数据结构题集(C语言版)完整与答案

严蔚敏 数据结构C 语言版答案详解第1章 绪论1.1 简述下列术语:数据,数据元素、数据对象、数据结构、存储结构、数据类型和抽象数据类型。
解:数据是对客观事物的符号表示。
在计算机科学中是指所有能输入到计算机中并被计算机程序处理的符号的总称。
数据元素是数据的基本单位,在计算机程序中通常作为一个整体进行考虑和处理。
数据对象是性质相同的数据元素的集合,是数据的一个子集。
数据结构是相互之间存在一种或多种特定关系的数据元素的集合。
存储结构是数据结构在计算机中的表示。
数据类型是一个值的集合和定义在这个值集上的一组操作的总称。
抽象数据类型是指一个数学模型以及定义在该模型上的一组操作。
是对一般数据类型的扩展。
1.2 试描述数据结构和抽象数据类型的概念与程序设计语言中数据类型概念的区别。
解:抽象数据类型包含一般数据类型的概念,但含义比一般数据类型更广、更抽象。
一般数据类型由具体语言系统内部定义,直接提供给编程者定义用户数据,因此称它们为预定义数据类型。
抽象数据类型通常由编程者定义,包括定义它所使用的数据和在这些数据上所进行的操作。
在定义抽象数据类型中的数据部分和操作部分时,要求只定义到数据的逻辑结构和操作说明,不考虑数据的存储结构和操作的具体实现,这样抽象层次更高,更能为其他用户提供良好的使用接口。
1.3 设有数据结构(D,R),其中{}4,3,2,1d d d d D =,{}r R =,()()(){}4,3,3,2,2,1d d d d d d r =试按图论中图的画法惯例画出其逻辑结构图。
解:1.4 试仿照三元组的抽象数据类型分别写出抽象数据类型复数和有理数的定义(有理数是其分子、分母均为自然数且分母不为零的分数)。
解:ADT Complex{ 数据对象:D={r,i|r,i 为实数} 数据关系:R={<r,i>} 基本操作: InitComplex(&C,re,im)操作结果:构造一个复数C ,其实部和虚部分别为re 和im DestroyCmoplex(&C)操作结果:销毁复数C Get(C,k,&e)操作结果:用e 返回复数C 的第k 元的值Put(&C,k,e)操作结果:改变复数C的第k元的值为eIsAscending(C)操作结果:如果复数C的两个元素按升序排列,则返回1,否则返回0 IsDescending(C)操作结果:如果复数C的两个元素按降序排列,则返回1,否则返回0 Max(C,&e)操作结果:用e返回复数C的两个元素中值较大的一个Min(C,&e)操作结果:用e返回复数C的两个元素中值较小的一个}ADT ComplexADT RationalNumber{数据对象:D={s,m|s,m为自然数,且m不为0}数据关系:R={<s,m>}基本操作:InitRationalNumber(&R,s,m)操作结果:构造一个有理数R,其分子和分母分别为s和mDestroyRationalNumber(&R)操作结果:销毁有理数RGet(R,k,&e)操作结果:用e返回有理数R的第k元的值Put(&R,k,e)操作结果:改变有理数R的第k元的值为eIsAscending(R)操作结果:若有理数R的两个元素按升序排列,则返回1,否则返回0 IsDescending(R)操作结果:若有理数R的两个元素按降序排列,则返回1,否则返回0 Max(R,&e)操作结果:用e返回有理数R的两个元素中值较大的一个Min(R,&e)操作结果:用e返回有理数R的两个元素中值较小的一个}ADT RationalNumber1.5 试画出与下列程序段等价的框图。
C++双向循环链表实现

BidCirList& operator = (BidCirList& list)
{ if (this != &list) { BidCirList S(list);
Swap(S); } return *this; }
//反向打印 void PrintPrev() {
ListNode* cur = _head._prev; while (cur) {
if (cur == &_head) break;
cout << cur->_data << " -> "; cur = cur->_prev; } cout << " Over! " << endl; } //正向打印 void PrintLate() { ListNode* cur = _head._late;
if (del == NULL) {
//删除头之前 _head._prev = _head._prev->_prev; delete _head._prev->_late;
_head._prev->_late = &_head; } else {
del->_prev = del->_prev->_prev; delete del->_prev->_late;
while (cur) {
if (cur == &_head) break;
cout << cur->_data << " -> "; cur = cur->_late; } cout << " Over! " << endl; }
【数据结构】单向链表,单向循环链表,双向循环链表

【数据结构】单向链表,单向循环链表,双向循环链表单向链表头⽂件1//@ author 成鹏致远2//@ net 3//@ qq 5521585094//@ blog 56 #ifndef _LINKLIST_H7#define _LINKLIST_H89 #include <stdio.h>10 #include <stdlib.h>11 #include <stdbool.h>1213 typedef int datatype;1415 typedef struct node16 {17 datatype data;18struct node *next;19 }linklist,*plinklist;2021extern void linklist_init(plinklist *plist);//初始化链表22extern void linklist_create(plinklist plist, int len);//从头结点创建链表23extern void linklist_create_tail(plinklist plist, int len);//从链表尾创建链表24extern void linklist_sort(plinklist plist);//实现链表的逆转25extern void linklist_show(plinklist plist);//显⽰链表2627#endifView Code单向链表1//@ author 成鹏致远2//@ net 3//@ qq 5521585094//@ blog 56 #include "linklist.h"78void linklist_init(plinklist *plist)//初始化链表9 {10 *plist = (plinklist)malloc(sizeof(linklist));//申请空间11if(*plist == NULL)12 {13 perror("malloc");14 exit(1);15 }16 (*plist)->next = NULL;//初始化为空17 }1819void linklist_create(plinklist plist, int len)//从头结点创建链表20 {21 plinklist new;2223while(len--)//创建len个结点24 {25new = (plinklist)malloc(sizeof(linklist));//申请新空间26if(new == NULL)27 {28 perror("malloc");29 exit(1);30 }31new->data = len+1;//完成新结点的赋值3233//现在需要将新申请的结点和已有的结点链接在⼀起34//注意是在头部插⼊35new->next = plist->next;//将新申请的new结点插⼊到链表的最前⾯36 plist->next = new;37 }38 }3940void linklist_create_tail(plinklist plist, int len)//从链表尾创建链表41 {42 plinklist new;43 plinklist tail = plist;//tail表⽰链表的最后⼀个结点,在整个过程中,必须保证头结点(plist)的值不变44int i;4546for(i=0; i<len; i++)47 {48new = (plinklist)malloc(sizeof(linklist));//申请新空间49if(new == NULL)50 {51 perror("malloc");52 exit(1);53 }54new->data = i+1;5556//现在需要将新申请的结点和已有的结点链接在⼀起57//注意是在尾部插⼊58new->next = tail->next;//tail->next为空,new将成为新的尾结点59 tail->next = new;//将new结点插⼊到tail的后⾯60 tail = new;//tail后移,new成为新的尾结点6162 }63 }6465void linklist_sort(plinklist plist)//实现链表的逆转66 {67//思想68//在创建时把最早申请的结点放到了最后⾯,最后申请的结点放到了最前⾯69//所以逆转的过程就相当于创建时过程的重复执⾏,把最前⾯的⼜放到最后⾯70//逆转过程和⼊栈|出栈是⼀样的71//出栈|⼊栈只是为了⽅便理解7273 plinklist p = plist->next;//所有的操作必须保证头结点不变,⽤p指向链表的第⼀个元素,负责逆转过程中原链表的的移位74 plinklist tem = NULL;//临时变量,负责将原链表元素转移到逆转后的链表(相当于:出栈后⼊栈)7576 plist->next = NULL;//切断头结点与原链表的联系,以便重新建⽴链表7778while(p != NULL)//p辅助移位,相当于依次出栈79 {80 tem = p;//标记出栈的元素,即将⼊栈81 p = p->next;//移位,依次出栈8283//将出栈的元素加⼊到逆转后的链表,相当于再次⼊栈84//插⼊过程和从头部创建链表过程⼀样85 tem->next = plist->next;86 plist->next = tem;//tem作为链表的第⼀个元素8788 }89 }9091void linklist_show(plinklist plist)//显⽰链表92 {93 plinklist tem = plist->next;//同样是为了不改变头结点,所以需要临时结点指针9495while(tem != NULL)96 {97 printf("%d\t",tem->data);98 tem = tem->next;99 }100 printf("\n");101 }View Code主⽂件1//@ author 成鹏致远2//@ net 3//@ qq 5521585094//@ blog 56//⽤单向链表实现数据逆转7//⾸先建⽴⼀个包含若⼲整数的单向链表,然后实现逆转89 #include "linklist.h"1011int main()12 {13 plinklist plist;14int length;1516 linklist_init(&plist);//完成初始化_1718 printf("Pls input the length of linklist:");19 scanf("%d",&length);20#if 021 linklist_create(plist,length);//从头结点创建链表22 linklist_show(plist);//显⽰链表23 linklist_sort(plist);//逆转链表24 linklist_show(plist);2526#else27 printf("******************************************\n");28 linklist_create_tail(plist,length);//从尾结点创建链表29 linklist_show(plist);//显⽰链表30 linklist_sort(plist);//逆转链表31 linklist_show(plist);3233#endif3435return0;36 }View Code单向循环链表(josephu问题)头⽂件1//@ author 成鹏致远2//@ net 3//@ qq 5521585094//@ blog 56 #ifndef _LINKLIST_H7#define _LINKLIST_H89 #include <stdio.h>10 #include <stdlib.h>11 #include <stdbool.h>1213 typedef int datatype;1415 typedef struct node16 {17 datatype data;18struct node *next;19 }linklist,*plinklist;202122extern void josephu_init(plinklist *plist);//完成初始化23extern void josephu_create(plinklist *plist, int len);//创建链表24extern datatype josephu(plinklist plist);//完成数3出局25extern void josephu_show(plinklist plist);//显⽰链表262728#endifView Codejosephu1//@ author 成鹏致远2//@ net 3//@ qq 5521585094//@ blog 56//⽤单向循环链表现实"数3出局"游戏(Josephu问题)7//⾸先建⽴⼀个包含若⼲整数的单向循环链表,然后从第⼀个节点开始数,把数到3的那个节点删除 8//接着下⼀个节点开始数,数到3继续删除,以此类推,打印出最后剩余的那个节点910 #include "linklist.h"1112void josephu_init(plinklist *plist)//完成初始化13 {14#if 1//⽆头结点的初始化15 *plist = NULL;16#else//有头结点的初始化17 *plist = (plinklist)malloc(sizeof(linklist));18if(*plist == NULL)19 {20 perror("malloc");21 exit(1);22 }23 (*plist)->next = *plist;24#endif25 }2627void josephu_create(plinklist *plist, int len)//创建链表,因为初始化时没有头结点,所以参数需要传*plist28 {29 plinklist new;30 plinklist tail;//尾指针,从链表尾部插⼊新结点31int i;3233for(i=0; i<len; i++)34 {35if(0 == i)//因为⽆头结点,所以第⼀次也需要申请空间,并指向⾃⼰36 {37 *plist = (plinklist)malloc(sizeof(linklist));38if(*plist == NULL)39 {40 perror("malloc");41 exit(1);42 }43 (*plist)->data = i+1;44 (*plist)->next = *plist;//只有⼀个结点,指向⾃⼰4546 tail = *plist;//初始化尾指针47 }48else49 {50new = (plinklist)malloc(sizeof(linklist));51if(new == NULL)52 {53 perror("malloc");54 exit(1);55 }56new->data = i+1;57//将新结点new和已有结点连在⼀起58//注意是在尾部插⼊59new->next = tail->next;60 tail->next = new;//将new结点插⼊到tail后⾯61 tail = new;//new变成新的尾结点62 }63 }64 }6566 datatype josephu(plinklist plist)//完成数3出局67 {68 plinklist head = plist;//指向每次变化的"头结点",每出局⼀个⼈,下⼀个⼈将变成头结点69 plinklist tem;//临时指针,指向每次出局的⼈7071while(head != head->next)//只剩下⼀⼈时退出循环72 {73 tem = head->next->next;//tem将出局74 head->next->next = tem->next;//tem->next将是下⼀个"头结点"75 head = tem->next;//新"头结点"7677 printf("%d\t",tem->data);78 free(tem);//tem出局79 }80return head->data;81 }8283void josephu_show(plinklist plist)//显⽰链表84 {85 plinklist tem = plist;//保证头结点不变86while(tem != NULL && tem->next != plist)//循环遍历87 {88 printf("%d\t",tem->data);89 tem = tem->next;90 }91//注意最后⼀次循环是tem->next = plist,所以最后⼀个结点并没有输出92 printf("%d\n",tem->data);9394 }View Code主⽂件1//@ author 成鹏致远2//@ net 3//@ qq 5521585094//@ blog 56//⽤单向循环链表现实"数3出局"游戏(Josephu问题)7//⾸先建⽴⼀个包含若⼲整数的单向循环链表,然后从第⼀个节点开始数,把数到3的那个节点删除 8//接着下⼀个节点开始数,数到3继续删除,以此类推,打印出最后剩余的那个节点910 #include "linklist.h"1112int main()13 {14 plinklist plist;15 datatype result;16int len;1718 josephu_init(&plist);//完成初始化1920 printf("Pls input the length of josephu:");21 scanf("%d",&len);2223 josephu_create(&plist,len);//创建josephu链表24 josephu_show(plist);//显⽰josephu链表2526 result = josephu(plist);//解决⽅案27 printf("\nThe last is %d\n",result);2829return0;30 }View Code双向循环链表头⽂件1//@ author 成鹏致远2//@ net 3//@ qq 5521585094//@ blog 56 #ifndef _DOUBLELIST_H7#define _DOUBLELIST_H89 #include <stdio.h>10 #include <stdlib.h>11 #include <stdbool.h>1213 typedef int datatype;1415 typedef struct node16 {17 datatype data;18struct node *next,*prior;19 }double_list,*double_plist;2021extern void double_init(double_plist *plist);//双向链表的初始化22extern void double_sort(double_plist plist);//完成双向链表的奇数升序偶数降序排列23extern void double_create(double_plist plist, int len);//头插法创建双向链表24extern void double_show(double_plist plist);//显⽰双向链表2526#endifView Code双向循环链表1//@ author 成鹏致远2//@ net 3//@ qq 5521585094//@ blog 56//⽤双向循环链表实现顺序递增存储若⼲个⾃然数7//⽐如输⼊⼀个整数10,则建⽴⼀个双向循环链表,⾥⾯的每个节点分别存放1,2,3,4,5,6,7,8,9,108//然后通过某些操作,将其重新排列成1,3,5,7,9,10,8,6,4,2,即奇数升序偶数降序,并在屏幕上打印出来 910 #include "double_list.h"1112void double_init(double_plist *plist)//双向链表的初始化13 {14 *plist = (double_plist)malloc(sizeof(double_list));15if(*plist == NULL)16 {17 perror("malloc");18 exit(1);19 }2021 (*plist)->next = (*plist)->prior = *plist;//双向链表的前后指针都指向⾃⼰2223 }2425void double_sort(double_plist plist)//完成双向链表的奇数升序偶数降序排列26 {27 double_plist pnext = plist->next;//指向链表的第⼀个节点28 double_plist prior = plist->prior;//指向链表的最后⼀个节点29 double_plist tem = NULL;//临时指针,⽤于辅助定位将被移动的节点3031while(pnext != prior)//没有到达链表尾32 {33if(pnext->data%2 !=0)//为奇数,直接跳过34 pnext = pnext->next;35else//为偶数,将pnext移动到偶数后⾯⼀位奇数位置,⽤tem指向回去辅助移动偶数链表节点36 {37 pnext = pnext->next;3839//将pnext前⾯的节点剪切出来40 tem = pnext->prior;//tem指向要被移动的节点41 pnext->prior = tem->prior;//将奇数节点前向指针连接起来42 tem->prior->next = pnext;//将奇数节点后向指针连接起来4344//将偶数节点(tem)插⼊到链表尾(prior)45 tem->next = prior->next;//tem将成为新的尾结点46 prior->next->prior = tem;//链表⾸尾相连47//prior和新的尾结点tem相连48 tem->prior = prior;49 prior->next = tem;50 }51 }52 }5354void double_create(double_plist plist, int len)//头插法创建双向链表55 {56 double_plist new;57while(len--)//创建len个节点58 {59new = (double_plist)malloc(sizeof(double_list));60if(new == NULL)61 {62 perror("malloc");63 exit(1);64 }65new->data = len+1;6667//向plist后⾯插⼊⼀个新的节点68//双向链表的头插法69new->next = plist->next;70 plist->next->prior = new;71new->prior = plist;72 plist->next = new;73 }74 }7576void double_show(double_plist plist)//显⽰双向链表77 {78 double_plist tem = plist->next;//保证头结点不变7980while(tem != plist)//遍历⼀个循环81 {82 printf("%d\t",tem->data);83 tem = tem->next;84 }85 printf("\n");86 }View Code主⽂件1//@ author 成鹏致远2//@ net 3//@ qq 5521585094//@ blog 56//⽤双向循环链表实现顺序递增存储若⼲个⾃然数7//⽐如输⼊⼀个整数10,则建⽴⼀个双向循环链表,⾥⾯的每个节点分别存放1,2,3,4,5,6,7,8,9,108//然后通过某些操作,将其重新排列成1,3,5,7,9,10,8,6,4,2,即奇数升序偶数降序,并在屏幕上打印出来 910 #include "double_list.h"1112int main()13 {14 double_plist plist;15int len;1617 double_init(&plist);//双向链表初始化1819 printf("Pls input the length of double list:");20 scanf("%d",&len);2122 double_create(plist,len);//创建双向链表23 double_show(plist);//显⽰双向链表2425 double_sort(plist);//完成奇数升序偶数降序排序26 double_show(plist);2728return0;29 }View Code。
java实现双向循环链表

java实现双向循环链表java实现循环链表:在单链表中,查询下⼀个元素的时间是O(1)。
查询上⼀个元素的时间却是O(n)。
为了克服这种缺点,我们开始学习双向链表。
双向链表类的代码:package doublelinkedlist;public class DoubleLinkedList {class Element{private Element prior=null;public Object value=null;private Element next=null;}private Element header = null;//头结点/*** 初始化链表* */void initList(){header = new Element();header.prior=header;header.value=null;header.next=header;}/*** 向链表中第i个位置插⼊元素o* */void insertList(Object o,int i){if(i<=0||i>size()){System.out.println("插⼊位置不合法!链表长度为:"+size());}else{Element e = new Element();e.value=o;if(header.prior==header)//第⼀次插⼊元素{e.prior=header;e.next=header;header.next=e;header.prior=e;}else if(i==size())//在最后插⼊{System.out.println("在链表尾部插⼊");e.next=header;e.prior=header.prior;header.prior.next=e;header.prior=e;}else{Element temp = header;int count=0;while(temp.next!=header){count++;if(count == i){e.prior=temp;e.next=temp.next;temp.next.prior=e;temp.next=e;}temp=temp.next;}}}}/*** 删除链表中的某个元素* */void deleteList(int i){if(i<=0||i>size()){System.out.println("插⼊位置不合法!链表长度为:"+size()); }else{int count=0;Element temp = header;while(temp.next!=header){temp=temp.next;count++;if(i==count){//删除第i个元素temp.next.prior=temp.prior;temp.prior.next=temp.next;}}}}/*** 打印链表* */void print(){System.out.print("打印双向循环链表:");Element temp = header;while(temp.next!=header){System.out.print(temp.next.value+"\t");temp=temp.next;}System.out.println();}/*** 获取链表的⼤⼩* */int size(){int count=1;Element temp = header;while(temp.next!=header){count++;temp=temp.next;}return count;}}双向链表的测试类package doublelinkedlist;public class DoubleLinkedListMain {public static void main(String[] args) {DoubleLinkedList dlList = new DoubleLinkedList();//有头结点 dlList.initList();dlList.insertList(1, 1);dlList.insertList(2, 2);dlList.insertList(3, 1);dlList.insertList(4, 1);dlList.insertList(5, 1);dlList.insertList(6, 6);dlList.print();dlList.deleteList(3);dlList.print();}}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
List-DuLinkedList-将单向循环链表改为双向的
2.32 已知有一个单向循环链表,其每个结点中含有三个域:prior,data和next,
其中data为数据域,next为指向后继结点的指针域,prior也为指针域,但它的值为NULL。
试编写算法将此单向循环链表改写为双向循环链表,即使prior成为指向前驱结点的指针域#include <stdio.h> #include <malloc.h>
#define N 6
typedef struct DuLNode { //双向循环链表结点
char data;
struct DuLNode *prior;
struct DuLNode *next;
} DuLNode, *DuLinkedList;
void createLinkedList(DuLinkedList &L) { //创建双向循环链表(暂时只设NEXT指针)DuLinkedList p; int i;
L = (DuLinkedList)malloc(sizeof(DuLNode));
L->data = NULL;
L->next = L;
L->prior = NULL;
for(i=N; i>0; i--) {
p = (DuLinkedList)malloc(sizeof(DuLNode));
p->data = getchar(); p->next = L->next; L->next = p;
}
}
void singleToDu(DuLinkedList &L) { //将Prior指针添加上
DuLinkedList p, q;
p = L;
q = p->next;
while(q != L) {
q->prior = p; p = q; q = q->next;
}
q->prior = p;
}
void printList(DuLinkedList L) { //打印双向循环链表
DuLinkedList p;
if(L->prior) {
printf("链表的前驱指针存在,现采用反向遍历\n");
p = L->prior;
while(p != L) {printf("%c ", p->data); p = p->prior;}
} else {
printf("链表的前驱指针不存在,将采用正向遍历\n");
p = L->next;
while(p != L) {printf("%c ", p->data); p = p->next;}
}
}
void main() {
DuLinkedList L;
printf("请输入%d个结点的值:\n", N); createLinkedList(L);
printList(L);
singleToDu(L); printf("\n");
printList(L); printf("\n");
}。