(三)循环链表以及循环链表应用
2013-10-04 23:05
260 查看
单向循环链表
单向循环链表是单链表的另一种形式,其结构特点是链表中最后一个结点的指针不再是结束标记,而是指向整个链表的第一个结点,从而使单链表形成一个环。和单链表相比,循环单链表的长处是从链尾到链头比较方便。当要处理的数据元素序列具有环型结构特点时,适合于采用循环单链表。
与单链表相同,循环单链表也有带头结点结构和不带头结点结构两种,带头结点的循环单链表实现插入和删除操作时,算法实现较为方便。
带头结点的循环单链表结构如下:
带头结点的循环单链表的操作实现方法和带头结点的单链表的操作实现方法类同,差别仅在于:
(1)在构造函数中,要加一条head.next = head 语句,把初始时的带头结点的循环单链表设计成图2-11 (a)所示的状态。
(2)在index(i)成员函数中,把循环结束判断条件current != null改为current != head。(见上篇博客)
双向循环链表
双向链表是每个结点除后继指针外还有一个前驱指针。和单链表类同,双向链表也有带头结点结构和不带头结点结构两种,带头结点的双向链表更为常用;另外,双向链表也可以有循环和非循环两种结构,循环结构的双向链表更为常用。
在双向链表中,每个结点包括三个域,分别是element域、next域和prior域,其中element域为数据元素域,next域为指向后继结点的对象引用,prior域为指向前驱结点的对象引用。下图为双向链表结点的图示结构。
如下图是带头结点的循环双向链表的图示结构。循环双向链表的next和prior各自构成自己的循环单链表。
在双向链表中,有如下关系:设对象引用p表示双向链表中的第i个结点,则p.next表示第i+1个结点,p.next.prior仍表示第i个结点,即p.next.prior== p;同样地,p.prior表示第i-1个结点,p.prior.next仍表示第i个结点,即p.prior.next ==p。下图是双向链表上述关系的图示。
循环双向链表的插入过程如下图所示。图中的指针p表示要插入结点的位置,s表示要插入的结点,①、②、③、④表示实现插入过程的步骤。
循环双向链表的删除过程如下图所示。图中的指针p表示要插入结点的位置,①、②表示实现删除过程的步骤。
循环链表应用
游戏规则:N个人围成一个圈,从第一个人开始传花,当数到M时,该人退出游戏,直到剩下最后一个人。
单向循环链表是单链表的另一种形式,其结构特点是链表中最后一个结点的指针不再是结束标记,而是指向整个链表的第一个结点,从而使单链表形成一个环。和单链表相比,循环单链表的长处是从链尾到链头比较方便。当要处理的数据元素序列具有环型结构特点时,适合于采用循环单链表。
与单链表相同,循环单链表也有带头结点结构和不带头结点结构两种,带头结点的循环单链表实现插入和删除操作时,算法实现较为方便。
带头结点的循环单链表结构如下:
带头结点的循环单链表的操作实现方法和带头结点的单链表的操作实现方法类同,差别仅在于:
(1)在构造函数中,要加一条head.next = head 语句,把初始时的带头结点的循环单链表设计成图2-11 (a)所示的状态。
(2)在index(i)成员函数中,把循环结束判断条件current != null改为current != head。(见上篇博客)
public interface List { // 获得线性表长度 public int size(); // 判断线性表是否为空 public boolean isEmpty(); // 插入元素 public void add(int index, Object obj) throws Exception; // 删除元素 public void delete(int index) throws Exception; // 获取指定位置的元素 public Object get(int index) throws Exception; }
//节点类 public class Node { Object element; // 数据域 Node next; // 指针域 //头结点的构造方法 public Node(Node nextval){ this.next=nextval; } //非头结点的构造方法 public Node(Object obj,Node nextval){ this.element=obj; this.next=nextval; } public Object getElement() { return element; } public void setElement(Object element) { this.element = element; } public Node getNext() { return next; } public void setNext(Node next) { this.next = next; } public String toString() { return this.element.toString(); } }
public class CycleLinkedList implements List { Node head; // 头指针 Node current;// 当前结点对象 int size;// 结点个数 public CycleLinkedList(){ //初始化头结点,让头指针指向头结点。并且让当前结点对象等于头结点。 this.head = current = new Node(null); this.size =0;//单向链表,初始长度为零。 this.head.next =this.head; } //定位函数,实现当前操作对象的前一个结点,也就是让当前结点对象定位到要操作结点的前一个结点。 public void index(int index) throws Exception{ if(index<-1||index>this.size-1){ throw new Exception("参数错误!"); } if(index==-1){ return; } this.current=this.head.next; int j=0; while(this.current!=this.head&&j<index){ this.current=this.current.next; j++; } } @Override public int size() { // TODO Auto-generated method stub return this.size; } @Override public boolean isEmpty() { // TODO Auto-generated method stub return this.size == 0; } @Override public void add(int index, Object obj) throws Exception { // TODO Auto-generated method stub if (index < 0 || index > this.size) { throw new Exception("参数错误!"); } this.index(index - 1); this.current.setNext(new Node(obj, this.current.next)); this.size++; } @Override public void delete(int index) throws Exception { // TODO Auto-generated method stub // 判断链表是否为空 if (isEmpty()) { throw new Exception("链表为空,无法删除!"); } if (index < 0 || index > size) { throw new Exception("参数错误!"); } this.index(index-1); this.current.setNext(this.current.next.next); this.size--; } @Override public Object get(int index) throws Exception { // TODO Auto-generated method stub if(index <-1 || index >size-1) { throw new Exception("参数非法!"); } this.index(index); return this.current.getElement(); } }
双向循环链表
双向链表是每个结点除后继指针外还有一个前驱指针。和单链表类同,双向链表也有带头结点结构和不带头结点结构两种,带头结点的双向链表更为常用;另外,双向链表也可以有循环和非循环两种结构,循环结构的双向链表更为常用。
在双向链表中,每个结点包括三个域,分别是element域、next域和prior域,其中element域为数据元素域,next域为指向后继结点的对象引用,prior域为指向前驱结点的对象引用。下图为双向链表结点的图示结构。
如下图是带头结点的循环双向链表的图示结构。循环双向链表的next和prior各自构成自己的循环单链表。
在双向链表中,有如下关系:设对象引用p表示双向链表中的第i个结点,则p.next表示第i+1个结点,p.next.prior仍表示第i个结点,即p.next.prior== p;同样地,p.prior表示第i-1个结点,p.prior.next仍表示第i个结点,即p.prior.next ==p。下图是双向链表上述关系的图示。
循环双向链表的插入过程如下图所示。图中的指针p表示要插入结点的位置,s表示要插入的结点,①、②、③、④表示实现插入过程的步骤。
循环双向链表的删除过程如下图所示。图中的指针p表示要插入结点的位置,①、②表示实现删除过程的步骤。
public interface List { // 获得线性表长度 public int size(); // 判断线性表是否为空 public boolean isEmpty(); // 插入元素 public void add(int index, Object obj) throws Exception; // 删除元素 public void delete(int index) throws Exception; // 获取指定位置的元素 public Object get(int index) throws Exception; }
public class Node { Object element; // 数据域 Node next; // 后继指针域 Node prior; // 前驱指针域 Node(Node nextval){ this.next=nextval; } Node(Object obj,Node nextval){ this.next=nextval; this.element=obj; } // 获得当前结点的后继结点 public Node getNext() { return this.next; } // 获得当前结点的前驱结点 public Node getPrior() { return this.prior; } // 获得当前的数据域的值 public Object getElement() { return this.element; } // 设置当前结点的后继指针域 public void setNext(Node nextval) { this.next = nextval; } // 设置当前结点的前驱指针域 public void setPrior(Node priorval) { this.prior = priorval; } // 设置当前结点的数据域 public void setElement(Object obj) { this.element = obj; } public String toString() { return this.element.toString(); } }
public class DoubleCycleLinkedList implements List { Node head; // 头指针 Node current;// 当前结点对象 int size;// 结点个数 public DoubleCycleLinkedList(){ //初始化头结点,让头指针指向头结点。并且让当前结点对象等于头结点。 this.head = current = new Node(null); this.size =0; this.head.next =this.head; this.head.prior=this.head; } //定位函数,实现当前操作对象的前一个结点,也就是让当前结点对象定位到要操作结点的前一个结点。 public void index(int index) throws Exception{ if(index<-1||index>this.size-1){ throw new Exception("参数错误!"); } if(index==-1){ return; } this.current=this.head.next; int j=0; while(this.current!=this.head&&j<index){ this.current=this.current.next; j++; } } @Override public int size() { // TODO Auto-generated method stub return this.size; } @Override public boolean isEmpty() { // TODO Auto-generated method stub return this.size == 0; } @Override public void add(int index, Object obj) throws Exception { // TODO Auto-generated method stub if (index < 0 || index > this.size) { throw new Exception("参数错误!"); } this.index(index - 1); this.current.setNext(new Node(obj, this.current.next)); this.current.next.setPrior(this.current); this.current.next.next.setPrior(this.current.next); this.size++; } @Override public void delete(int index) throws Exception { // TODO Auto-generated method stub // 判断链表是否为空 if (isEmpty()) { throw new Exception("链表为空,无法删除!"); } if (index < 0 || index > size) { throw new Exception("参数错误!"); } this.index(index-1); this.current.setNext(this.current.next.next); this.current.next.setPrior(current); this.size--; } @Override public Object get(int index) throws Exception { // TODO Auto-generated method stub if(index <-1 || index >size-1) { throw new Exception("参数非法!"); } this.index(index); return this.current.getElement(); } }
循环链表应用
游戏规则:N个人围成一个圈,从第一个人开始传花,当数到M时,该人退出游戏,直到剩下最后一个人。
//游戏类 public class Game { //单向循环链表 CycleLinkedList list = new CycleLinkedList(); //总人数 int num; //数到几退出 int key; //游戏初始化方法 public Game(int num,int key) { this.num = num; this.key = key; } public void play() throws Exception { for(int i=0;i<num;i++) { list.add(i, i); } System.out.println("\n-------游戏开始之前---------\n"); for(int i=0;i<list.size();i++) { System.out.print(list.get(i)+" "); } System.out.println("\n-------游戏开始---------\n"); int iCount=num; //开始等于总人数num int j=0; //累加器,计算是否能被key整除。 Node node = list.head; while(iCount!=1) { if(node.getElement()!=null&& Integer.parseInt(node.getElement().toString())!=-1) { j++; if(j%key==0) { node.setElement(-1); iCount--; System.out.println(); for(int i=0;i<list.size();i++) { System.out.print(list.get(i)+" "); } } } node = node.next; } System.out.println("\n-------游戏结束---------\n"); for(int i=0;i<list.size();i++) { System.out.print(list.get(i)+" "); } } }
相关文章推荐
- 判断单链表是否是循环链表以及找出循环链表入口
- 数据结构与算法(Java描述)-5、循环链表仿真链表以及循环链表应用
- 数据结构(4)--循环链表的应用之约瑟夫环问题以及线性表总结之顺序表与链表的比较
- 单链表的应用2(单向循环链表变双向循环链表)
- 单向循环链表简单应用
- foreach 循环遍历 以及函数的应用
- 操作系统循环链表应用(之第二次机会页面置换法)
- C++数据结构--循环链表的应用--解决约瑟夫问题
- 【学习总结】循环链表模拟约瑟夫问题和循环链表的初始化、建立、删除(按值与按位置)
- leetcode-1:python基础,循环、条件、列表、字典的应用,enumerate、range函数以及2.0和3.0print的区别
- 单向循环链表的头插,尾插,中间插以及删除节点
- 已知一单链表中的数据元素含有三类字符:字母、数字和其他字符。是编写算法,构造三个循环链表,使每个循环链表中只含同一类字符
- 循环链表的应用——约瑟夫环
- 约瑟夫环——静态循环链表,动态循环链表
- 循环链表之双循环链表
- 说透一级指针和二级指以及(void**)&在双链表中的应用
- 链表的相交以及链表的循环的判断以及查找
- 单链表,双向循环链表应用
- 双循环链表的创建以及插入删除等操作
- 走入javascript(六)for循环自定义属性的应用以及算数运算符