数据结构与算法之六 双向链表和循环链表

版权声明:报名咨询QQ:3246333637,本文为 张晨光老师 创作,未经博主允许不得转载 https://blog.csdn.net/zhangchen124/article/details/51637428
在本章中,你将学习:
执行双链接列表
执行循环链接列表

应用链接列表以解决编程问题

现在,考虑一个示例,您需要以降序的方式显示这些数字。
如何解决此问题?
每一个节点链接到序列中的下一个节点,这意味着您只能以正向遍历列表,这样的链接列表称为单链接列表。要以降序的方式显示数字,您需要反转此链接列表。
运用算法以反转单链接列表。


1. 声明三个变量 / 指针, ptr1 ptr2 ptr 3
2.
2. 如果列表中仅有一个节点:
3.
a. 退出。
3.
3. 使列表中的第一个节点为 ptr1
4.
4. 使 ptr1 后面的一个节点为 ptr2
5.
5. 使 ptr2 后的的一个节点为 ptr3
6.
6. 使 ptr1 next 字段指向 NULL
7.
7. 使 ptr2 next 字段指向 ptr1
8.
8. 重复直至 ptr3 NULL
9.
a. 设置 ptr1 = ptr2
b. 设置 ptr2 = ptr3
c. 使 ptr3 指向序列中的下一个节点。
d. 使 ptr2 next 字段指向 ptr1
9.
9. 使 START 指向 ptr2


上述算法的有什么问题?
无论你什么时候访问下一节点,你都需要调整三个变量的所有链接。
此方法的缺点:
此方法对大列表来说效率低且耗时。

你如何解决此问题?
如果列表中每一个节点不仅包含序列中其下一个节点的引用,而且还包含其前一 节点的引用,那么此问题就可以解决。
考虑下面的列表。


你可以在单链接列表的每个节点中引入一个额外字段,它持有前一个节点的 地址。
这种类型的列表就是双链接列表。


可以通过声明两个类在程序中表示双链接列表:
Node 类:在双链接列表中,每个节点需要存储:
信息
序列中下一个节点的地址
前一个节点的地址
// C# 代码
class Node
{
     public int info;
     public Node next;
     public Node prev;
}


DoubleLinkedList 类: 该类由一组执行链接列表的操作组成。另外,它还声明变 / 指针 START ,它将始终指向列表中的第一个节点。
// C# 代码
class DoubleLinkedList
{
  Node START;
  DoubleLinkedList(){}
  public void addNode(int element){}
  public bool search(int element, ref Node previous, ref Node current){}
  public bool delNode(int element){}
  public void traverse() {}
  public void revtraverse(){}
}


课间思考
双链接列表中的节点表示法与单链接列表中的节点表示法有什么不同?


答案:
在单链接列表中,每个节点只存储列表中下一个节点的地址,而在双链接列表 中,每个节点还持有其前一个节点的地址。


编写一算法以正向遍历双链接列表。


1. 将列表中的第一个节点标记为 currentNode
2.
2. 重复步骤 3 和步骤 4 ,直到 currentNode 成为 NULL 为止。
3.
3. 显示标记为 currentNode 的节点中包含的信息。
4.
4. 使 currentNode 指向序列中的下一个节点。


运用算法以在双链接列表的开头插入节点。


1. 为新节点分配内存。
2.
2. 为新节点的数据字段赋值。
3.
3. 使新节点的 next 字段指向列表中的第一个节点。
4.
4. 使 START prev 字段指向该新节点。
5.
5. 使新节点的 prev 字段指向 NULL
6.
6. 使 START 指向该新节点。


编写一算法在双链接列表的两个节点之间插入节点。


1. 确定要在哪两个节点之间插入新节点。分别将它们标记为前一个节点和当前节点。要找到这两个节点,请执行以下步骤:
a. 使当前节点指向第一个节点。
b. 使前一个节点指向 NULL
c. 重复步骤 d 和步骤 e ,直到 current.info > newnode.info 或者 current = NULL
d. 使前一个节点指向当前节点。
e. 使当前节点指向序列中的下一个节点。
2. 为新节点分配内存。
3. 为新节点的数据字段赋值。
4. 将新节点的 next 字段指向当前节点。
5. 使新节点的 prev 字段指向前一个节点。
6. 使当前节点的 prev 字段指向新节点。
7. 使前一个节点的 next 字段指向新节点。
8.


此算法有什么问题?
如果当前节点是 NULL ,则新节点应插入到列表的末尾。
然而,在这种情况下,执行步骤 6 会显示错误。
这是因为 NULL 不能有 prev 字段。
因此,您需要修改此算法以便您也可以在列表的末尾插入节点。


1. 确定要在哪两个节点之间插入新节点。分别将它们标记为前一个和当前节点。要找到它们,请执行以下步骤:
a. 使当前节点指向第一个节点。
b. 使前一个节点指向 NULL
c. 重复步骤 d 和步骤 e ,直到 current.info > newnode.info current = NULL
d. 使前一个节点指向当前节点。
e. 使当前节点指向序列中的下一个节点。
2. 为新节点分配内存。
3. 为新节点的数据字段赋值。
4. 使新节点的 next 字段指向当前节点。
5. 使新节点的 prev 字段指向前一个节点。
6. 如果当前节点不是 NULL
a. 则使当前节点的 prev 字段指向新节点。
7. 使前一个节点的 next 字段指向新节点。


运用算法以在双链接列表的末尾插入一节点。


1. 为新节点分配内存。
2.
2. 为新节点的数据字段赋值。
3.
3. 使标记为 LAST 节点的 next 字段指向新节点。
4.
4. 使新节点的 prev 字段指向标记为 LAST 的节点。
5.
5. 使新节点的 next 字段指向 NULL
6.
6. 将新节点标记为 LAST


假定您正在开发一款动作游戏,其中会给游戏者一套武器。
经过特定时间段后,会在屏幕上出现每种武器。
要求游戏者在10秒钟之内选择武器,否则该武器就不能使用了。
一旦显示第n个武器后,就会再次显示第一次出现的武器,并且这种顺序会跟前面一样继续。
您将使用哪种数据结构来存储此示例中武器的列表?

您可以使用单链接列表。
但是,武器需要以循环重复的次序显示。
因此,一旦显示了所有武器,指针必须从列表中第一个武器重新开始。
这需要在每次到达列表结尾时重新初始化指针。
在此情况下,如果遍历最后一个武器对应的节点后指针能够自动移到列表中 的第一个武器,那将是很好的。
使用循环链接列表可以实现这一点。

您可以通过将列表中最后一个节点链接回第一个节点来实现循环链接列表。


在循环链接列表中,最后一个节点持有第一个节点的地址。


在循环链接列表中,您需要维护一个 LAST 变量 / 指针,它始终指向最后一个 节点。

要表示一个循环链接列表,需要声明两个类: Node List
Node 类:循环链接列表的 Node 类的声明与单链接列表相同。
List 类:该类由一组对链接列表执行的操作组成。这些操作是插入、删除、搜索 和遍历。它还包含 LAST 变量 / 指针的声明,它始终指向列表中的最后一个节点。


  // C# 代码
class List
{
private Node LAST;
List()
{
LAST = NULL;
}
public void addNode(int element) {}
  public bool search(int element, ref Node previous, ref Node current){}
  public bool delNode(int element) {}
  public void traverse() {}
  }



1. 使 currentNode 指向标记为 LAST 节点的后面一个节点,这样 currentNode 就指向列表中的第一个节点。
2.
2. 重复步骤 3 和步骤 4 ,直到 currentNode = LAST
3.
3. 显示标记为 currentNode 的节点中包含的信息。
4.
4. 使 currentNode 指向序列中的下一个节点。
5.
5. 显示标记为 LAST 的节点中包含的信息。


在循环链接列表中,您可以在以下任何位置插入一节点:
列表的开头
列表的末尾
列表的两个节点之间


链接列表的应用
链接列表为存储数据提供有效的机制。
它们能够容易地解决许多编程问题。
它们形成了实现各种其他数据结构(如堆栈、队列和二进制树)的基础。


链接列表在各种游戏应用程序中执行。
考虑这样一种游戏,游戏者要通过射出子弹来保护自己避免敌人的攻击。
一旦子弹射出了,需要在某个地方存储其详细信息,这些详细信息包括某个特定时间点子弹的大小、颜色和坐标。
子弹的详细信息存储在链接列表中,因为预先不知道要射击的子弹数。
节点中存储的子弹的坐标按常规作更新以表明子弹正在向前移动。
同样的结果在屏幕上也会显示。


链接列表用来执行内部的文件系统。
一个文件可以分成各个块,它们可以随机分散在磁盘上。
当创建一个新文件时,就为它分配了一个新的内存块。
新块可能与先前分配的块不是连续的。
因此,每个块还包含下一个被分配的内存块的地址,这样就形成了链接列表。
链接列表可用来对多项表达式执行各种算数操作。
在一个多项表达式 4x5 + 5x4 + 2x3 + 3x2 + 7x 中,变量 x 的每次出现都伴有 两个值:
系数
指数

每个节点包含以下信息:
系数
序列中下一个节点的地址

小结


在本章中,您已经学到了:
在双链接列表中,每个节点需要存储:
信息
序列中下一个节点的地址
前一个节点的地址
双链接列表使您能够以正向和反向遍历整个列表。
通过将列表的中最后一个节点指回到列表中的第一个节点,可以将单链接列表 变成循环链接列表。

链接列表提供各种应用,例如:
形成各种其他数据结构(如堆栈、队列和二进制树)的基础。
用于各种游戏应用程序中。
用于实现各种操作系统中的内部文件系统。
提供简单、方便的机制对多项表达式执行各种算术操作。
/*
创建链表,通过使用节点类来创建
*/
using System;
class Node
{
	public int 	data;		//data用来存放节点的数据
	public Node 	next;		//next(节点对象)用来存放下一个节点的地址
}

class CreateList
{
	private Node start;		//头指针存放第一个节点的地址.
	private Node current;	//定义个当前节点对象,用来遍历链表.
	private Node previous;	//前驱节点.
	public CreateList()
	{
		start=null;					//当初始化类时,设置头指针为空	
	}		
  /*优化的创建链表的方法*/
  public void create2()
  {
  	previous=current=start=null;		//最开始的时候都为空,就是链表为一个空链表.
  	Console.Write("请输入您要创建链表的个数:");
  	int k=Convert.ToInt32(Console.ReadLine());
  	for(int i=0;i<k;i++)
  	{
  		Console.Write("请输入您要插入的第"+(i+1).ToString()+"节点数据:");	
  		
  		current=new Node();
  		current.data=Convert.ToInt32(Console.ReadLine());	
  		
  			if(start==null)
  				start=current;
  			else
  				previous.next=current;
  			
  			previous=current;  			
  	}
  }
	public void create()		//创建链表的方法:笨蛋方法(最为朴素的方法)
	{		Node first=null;
		if(start==null)
		{
			first=new Node();	//1.分配内存	
			Console.Write("请输入第一个节点值:");	
			first.data=Convert.ToInt32(Console.ReadLine());				//2.设定数据域里面的数据为2
			first.next=null;   //3.设定地址域里面的地址为null
			start=first;			//4.建链接
			current=first;		//当前节点为第一个节点.
		}
		//------------------添加质数为3的节点
		Node second=new Node();		//1。分配内存
		Console.Write("请输入第二个节点值");
		second.data=Convert.ToInt32(Console.ReadLine());						//2.设数据
		second.next=null;					//3.设地址
		first.next=second;				//4.将第一个节点指向第二个节点	
		//---------------------
		Node third=new Node();		//1。分配内存
		Console.Write("请输入第3个节点值");
		third.data=Convert.ToInt32(Console.ReadLine());						//2.设数据
		third.next=null;					//3.设地址
		second.next=third;				//4.将第2个节点指向第3个节点	
		//---------------------------
		Node fourth=new Node();		//1。分配内存
		Console.Write("请输入第4个节点值");
		fourth.data=Convert.ToInt32(Console.ReadLine());						//2.设数据
		fourth.next=null;					//3.设地址
		third.next=fourth;				//4.将第3个节点指向第4个节点
		//-------------------------
		Node fifth=new Node();		//1。分配内存
		Console.Write("请输入第5个节点值");
		fifth.data=Convert.ToInt32(Console.ReadLine());						//2.设数据
		fifth.next=null;					//3.设地址
		fourth.next=fifth;				//4.将第4个节点指向第5个节点			
	}//创建结束
	public void scan()		//遍历链表的方法
	{
		current=start;		//从头指针开始
		int i=1;
		while(current!=null)
		{
				Console.WriteLine("第"+i+"个节点数据为:"+current.data);
				current=current.next;		//将当前节点的下一个节点的地址给current,以便current去访问下一个节点.
				i++;
		}
	}
	//插入新节点
	public void insert()
	{
		Console.WriteLine("请输入您要插入的新节点数据");
		int i=Convert.ToInt32(Console.ReadLine());
		Node newnode=new Node();
		newnode.data=i;
		
		/*判断新节点是否为空,并且链表当中没有该节点:在头节点之前插入*/	
		if((start==null)||(i<=start.data))
		{
			if((start!=null)&&(i==start.data))	
			{
				Console.WriteLine("\n重复节点不允许");
				return;	
			}
			newnode.next=start;
			start=newnode;
			return;
		}
		/*在列表中间插入*/
		previous=current=start;	//设置为开始头节点
		while((current!=null)&&(i>=current.data))
		{
			if(i==current.data)
			{
				Console.WriteLine("\n重复数据不允许");
				return;	
			}	
			previous=current;
			current=current.next;
		}
		/*找到前驱节点和后继节点之后*/
		newnode.next=current;
		previous.next=newnode;
	}
	//搜索链表元素
	public void search()
	{
		Console.WriteLine("请输入您要查找的数据:");
		int i=Convert.ToInt32(Console.ReadLine());	//1.定义一个要搜索的数字
		Node current=start;	//2.定义当前节点对象current
		while((current!=null)&&(current.data!=i))	//3.如果当前节点不为空,并且当前节点数据不等于你输入的数据,则循环.
		{				
				current=current.next;
				
		}
		//4。判断是找到了还是没有找到
		if(current==null)
			Console.WriteLine("没有找到");
		else             
			Console.WriteLine("已经找到了您输入的数据");		
	}
	//删除链表元素
	public void delete()
	{
		Console.WriteLine("请输入您要删除的元素");
		int i=Convert.ToInt32(Console.ReadLine());
		
		previous=current=start;		//设定当前节点为头指针指向的节点.
		
		if(start==null)
		{
			Console.WriteLine("吃饱了撑的,开始乱删了,滚!XXXXXXXX");	
		}else if(current.data==i)
		{
				start=current.next;
				current.next=null;	//书上忽略了,由系统自动回收不用的内存.
		}else		//否则,有多个节点,要删除我们指定的节点.
		{
				while((current!=null)&&(current.data!=i))
				{//要找下一个符合条件的节点
					previous=current;		//在找符合要求的节点之前,将原来节点的地址给previous
					current=current.next;	//当前节点指向下一个节点.
				}
				if(current==null)
					Console.WriteLine("没有找到!");
				else
					previous.next=current.next;		//将要删除的节点的后继节点地址给前驱节点的next.
		}
		
	}
	/*
	1.定义要删除节点的前驱节点对象:previous;要删除节点:current
	2.previous和current都指向start
	3.遍历链表,以便找到要删除的节点.到底什么时候遍历链表呢?
	while(current!=null)并且(current.data!=17)
	{
			previous=current;
			current=current.next;	// 要查找下一个节点,同时,前驱节点指向刚才的current节点.
	}
	如果current==空:null
		说明没有找到
	else	
		找到了则: previous.next=current.next;
	
	*/
	public static void Main(string[]args)
	{
		CreateList list=new CreateList();
		//list.create2();	//创建链表	
		list.scan();
		list.insert();
		list.delete();
		list.scan();
		//list.search();
	}
}


/*
双向链表
*/
using System;

class Node
{
	public int data;	
	public Node prev;
	public Node next;
}
class DoubleLinkedList
{
	private Node start;
	private Node current;
	private Node previous;
	private Node last;
	
	public DoubleLinkedList()
	{
		start=null;
	}
	//遍历链表
	public void scan()
	{
		current=start;
		while(current!=null)
		{
			Console.Write("  "+current.data);
			current=current.next;	
		}
			
		Console.WriteLine();
	}
	//反向遍历
	public void rescan()
	{
			
	}
	//插入节点
	public void insert()
	{		
		//最开始的时候设置:前驱、后继都指向第一个头指针.
		//Console.Write("请输入您要插入的节点的数据:");
		int i=Convert.ToInt32(Console.ReadLine());
		
		Node newnode=new Node();
		newnode.data=i;
		
		  //********************
			if((start==null)||(i<=start.data))	//在链表头部插入节点.
			{
				newnode.next=start;
				if(start!=null)
				{	start.prev=newnode;}
				start=newnode;								
				return;
			}
			//其他情况
			previous=current=start;		
			while((current!=null)&&(current.data<=i))
			{
				previous=current;
				current=current.next;
			}//循环来找相应的前驱节点和后继节点.
			if(current!=null)  //********************在两个节点之间插入节点.
			{
				newnode.next=current;	  //1.第一步
				previous.next=newnode;  //2.
				
				//newnode.prev=previous;  //3				
				//current.prev=newnode;   //4
				
				current.prev=newnode;
				newnode.prev=previous;
				
			}else		//否则到达链表末尾
			{
				previous.next=newnode;
				newnode.prev=previous;  
				return;				
			}		
	}
	//删除节点
	public void delete()
	{
		Console.Write("请输入您要删除的数据:");
		int i=Convert.ToInt32(Console.ReadLine());		
		
		previous=current=start;
		if(start==null)	//链表为空
		{
			Console.WriteLine("链表没有数据");
			return;	
		}else if(i==start.data)		//删除第一个节点.
		{
				start=current.next;
				start.prev=null;
				current.next=null;	//可省略.
		}else
		{
			while((current!=null)&&(current.data!=i))
			{
				previous=current;
				current=current.next;
				//Console.Write("  "+current.data);
			}
			if(current==null)
				Console.WriteLine("没有要删除找到数据");
			else if(current.next==null)		 //为尾节点.		
				previous.next=null;
			else    //实现中间节点.
			{
				previous.next=current.next;
				current.next.prev=previous;		
			}
		}
	}
	//搜索节点.
	public void search()
	{
		Console.Write("请输入您要搜索的节点数据:");	
		int i=Convert.ToInt32(Console.ReadLine());
		
		current=start;
		while((current!=null)&&(current.data!=i))
		{
				current=current.next;
		}
		if(current==null)
			Console.WriteLine("没有找到");
		else
			Console.WriteLine("找到了");
	}
	/*******Main()方法**********/
	public static void Main(string[]args)
	{
		DoubleLinkedList doubleList=new DoubleLinkedList();
		Console.Write("请输入您要创建链表的长度 :");
		int n=Convert.ToInt32(Console.ReadLine());
		for(int i=0;i<n;i++)
		{
			Console.Write("请输入第"+(i+1).ToString()+"个数");
			doubleList.insert();
		}	
			
		doubleList.scan();	
		doubleList.search();
		//doubleList.delete();
		//doubleList.scan();
	}
}

using System;
using System.Text;

namespace Doubly_Linked_List_CSharp
{
    class Node		//定义节点类:包含学号、姓名,前驱节点地址、后继节点地址
    {        
        public int rollNumber;
        public string name;
        public Node next;
        public Node prev;
    }
    class DoubleLinkedList
    {
        Node START;		//头指针
        public DoubleLinkedList()
        {
            START = null;
        }
        public void addNode()/*添加新节点*/
        {
            int rollNo;
            string nm;
            Console.Write("\n请输入学生学号: ");
            rollNo = Convert.ToInt32(Console.ReadLine());
            Console.Write("\n请输入学生姓名: ");
            nm = Console.ReadLine();
            
            Node newnode = new Node();
            newnode.rollNumber = rollNo;
            newnode.name = nm;
            
            if (START == null || rollNo <= START.rollNumber)/*检查链表是否为空或着为第一个节点*/
            {
                if ((START != null) && (rollNo == START.rollNumber))
                {
                    Console.WriteLine("\n不允许重复学号");
                    return;
                }
                newnode.next = START;
                if (START != null)
                    START.prev = newnode;
                newnode.prev = null;
                START = newnode;
                return;
            }
            /*其他情况:在末尾或者两个节点之间插入节点.*/
            Node previous, current;
            for (current = previous = START; current != null && rollNo >= current.rollNumber; previous = current, current = current.next)
            {
                if (rollNo == current.rollNumber)
                {
                    Console.WriteLine("\n不允许重复学号");
                    return;
                }
            }
            /*找到要插入新节点的前驱和后继节点*/            
            newnode.next = current;
            newnode.prev = previous;
            if (current == null)							/*如果要插入节点在末尾*/
            {
                newnode.next = null;
                previous.next = newnode;
                return;
            }
            current.prev = newnode;
            previous.next = newnode;
        }

        public bool Search(int rollNo, ref Node previous, ref Node current)					/*搜索节点是否存在*/
        {
            for (previous = current = START; current != null && rollNo != current.rollNumber; previous = current, current = current.next)
            { }
            
            return (current != null);
        }

        public bool delNode(int rollNo)		/*删除节点*/
        {
            Node previous, current;
            previous = current = null;
            if (Search(rollNo, ref previous, ref current) == false)
                return false;
            if (current == START)				/*删除第一个节点*/
            {
                START = START.next;
                if (START != null)
                    START.prev = null;
                return true;
            }
            if (current.next == null)		/*删除最后一个节点*/
            {
                previous.next = null;
                return true;
            }
            /*删除中间节点*/
            
            previous.next = current.next;
            current.next.prev = previous;
            return true;
        }

        public void traverse()					/*遍历链表*/
        {

            if (listEmpty())
                Console.WriteLine("\n链表为空!");
            else
            {
                Console.WriteLine("\n链表升序排列为:\n");
                Node currentNode;
                for (currentNode = START; currentNode != null; currentNode = currentNode.next)
                    Console.Write(currentNode.rollNumber + "   " + currentNode.name + "\n");
            }
        }
        public void revtraverse()			/*反向遍历*/
        {
            if (listEmpty())
                Console.WriteLine("\n链表为空");
            else
            {
                Console.WriteLine("\n链表降序排列为:\n");
                Node currentNode;
                for (currentNode = START; currentNode.next != null; currentNode = currentNode.next)
                { }
                while (currentNode != null)
                {
                    Console.Write(currentNode.rollNumber + "   " + currentNode.name + "\n");
                    currentNode = currentNode.prev;
                }
            }
        }
        public bool listEmpty()
        {
            if (START == null)
                return true;
            else
                return false;
        }
        static void Main(string[] args)
        {
            DoubleLinkedList obj = new DoubleLinkedList();
            while (true)
            {
                try
                {
                    Console.WriteLine("\n菜单");
                    Console.WriteLine("1. 增加节点");
                    Console.WriteLine("2. 删除节点");
                    Console.WriteLine("3. 升序遍历节点");
                    Console.WriteLine("4. 降序遍历节点");
                    Console.WriteLine("5. 搜索节点");
                    Console.WriteLine("6. 退出\n");
                    Console.Write("请输入您的选择(1-6): ");
                    char ch = Convert.ToChar(Console.ReadLine());
                    switch (ch)
                    {
                        case '1':
                            {
                                obj.addNode();
                            }
                            break;
                        case '2':
                            {
                                if (obj.listEmpty())
                                {
                                    Console.WriteLine("\n链表为空");
                                    break;
                                }
                                Console.Write("\n请输入您要删除的数据: ");
                                int rollNo = Convert.ToInt32(Console.ReadLine());
                                Console.WriteLine();
                                if (obj.delNode(rollNo) == false)
                                    Console.WriteLine("记录没有发现");
                                else
                                    Console.WriteLine("学生记录编号" + rollNo + "已经删除\n");
                            }
                            break;
                        case '3':
                            {
                                obj.traverse();
                            }
                            break;
                        case '4':
                            {
                                obj.revtraverse();
                            }
                            break;
                        case '5':
                            {
                                if (obj.listEmpty() == true)
                                {
                                    Console.WriteLine("\n链表为空");
                                    break;
                                }
                                Node prev, curr;
                                prev = curr = null;
                                Console.Write("\n请输入您要搜索的数据: ");
                                int num = Convert.ToInt32(Console.ReadLine());
                                if (obj.Search(num, ref prev, ref curr) == false)
                                    Console.WriteLine("\n记录没有发现");
                                else
                                {
                                    Console.WriteLine("\n记录找到:");
                                    Console.WriteLine("\n学号: " + curr.rollNumber);
                                    Console.WriteLine("\n姓名: " + curr.name);
                                }
                            }
                            break;
                        case '6':
                            return;
                        default:
                            {
                                Console.WriteLine("\n无效选择");
                            }
                            break;
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine("请检查您输入的数据.");
                }
            }
        }
    }
}

using System;
using System.Text;

namespace Circular_List_CSharp
{
    class Node
    {        
        public int rollNumber;
        public string name;
        public Node next;
    }
		//针对循环链表操作的类.
    class CircularList
    {
        Node LAST;

        public CircularList()
        {
            LAST = null;
        }

        public void addNode()
        {
            int rollNo;
            string nm;
            Console.Write("\n请输入学号: ");
            rollNo = Convert.ToInt32(Console.ReadLine());
            Console.Write("\n请输入姓名: ");
            nm = Console.ReadLine();
            Node newnode = new Node();
            newnode.rollNumber = rollNo;
            newnode.name = nm;
            if (LAST == null)/*检查列表是否为空*/
            {
                newnode.next = LAST;
                LAST = newnode;
                LAST.next = LAST;
                return;
            }
            else if (rollNo <= LAST.next.rollNumber)/*在开头插入节点*/
            {
                if (rollNo == LAST.next.rollNumber)
                {
                    Console.WriteLine("\n不允许重复学号\n");
                    return;
                }
                newnode.next = LAST.next;
                LAST.next = newnode;
                return;
            }
            Node previous, current;
            for (previous = current = LAST.next; rollNo >= current.rollNumber; previous = current, current = current.next)
            {
                if (rollNo == current.rollNumber)
                {
                    Console.WriteLine("\n不允许重复学号\n");
                    return;
                }
                if (previous == LAST)			/*添加元素到末尾.*/
                {
                    newnode.next = LAST.next;
                    LAST.next = newnode;
                    LAST = newnode;
                    return;
                }
            }
            newnode.next = current;
            previous.next = newnode;
        }

        public bool Search(int rollNo, ref Node previous, ref Node current)		/*搜索*/
        {
            for (previous = current = LAST.next; current != LAST; previous = current, current = current.next)
            {
                if (rollNo == current.rollNumber)
                    return (true);              
            }
            if (rollNo == LAST.rollNumber)                  
                return true;
            else
                return (false);
        }
        public bool listEmpty()
        {
            if (LAST == null)
                return true;
            else
                return false;
        }
        public bool delNode(int rollNo)
        {
            if (LAST.next == LAST && rollNo == LAST.rollNumber)
            {
                LAST = null;
                return true;
            }
            Node previous, current;
            previous = current = null;
            if (Search(rollNo, ref previous, ref current) == false)
                return false;
            if (current == LAST.next)
            {
                LAST.next = LAST.next.next;
            }
            else if (current == LAST)
            {
                previous.next = LAST.next;
                LAST = previous;
            }
            else
            {
                previous.next = current.next;
            }
            return true;
        }

        public void traverse()
        {
            if (listEmpty())
                Console.WriteLine("\n链表为空");
            else
            {
                Console.WriteLine("\n链表中的记录为:\n");
                Node currentNode;
                currentNode = LAST.next;
                while (currentNode != LAST)
                {
                    Console.Write(currentNode.rollNumber + "    "+ currentNode.name+"\n");
                    currentNode = currentNode.next;
                }
                Console.Write(LAST.rollNumber+"    "+LAST.name+"\n");               
            }
        }
        public void firstNode()
        {
            if (listEmpty())
                Console.WriteLine("\n链表为空");
            else
                Console.WriteLine("\n第一个记录为:\n\n " + LAST.next.rollNumber+"    " +LAST.next.name);
        }
        static void Main(string[] args)
        {
            CircularList obj = new CircularList();
            while (true)
            {
                try
                {
                    Console.WriteLine("\n菜单");
                    Console.WriteLine("1. 增加数据");
                    Console.WriteLine("2. 删除数据");
                    Console.WriteLine("3. 遍历数据");
                    Console.WriteLine("4. 搜索数据");
                    Console.WriteLine("5. 显示第一个记录");
                    Console.WriteLine("6. 退出");
                    Console.Write("\n请输入您的选择(1-6): ");
                    char ch = Convert.ToChar(Console.ReadLine());
                    switch (ch)
                    {
                        case '1':
                            {                                
                                obj.addNode();
                            
                            }
                            break;
                        case '2':
                            {
                                if (obj.listEmpty())
                                {
                                    Console.WriteLine("\n链表为空");
                                    break;
                                }
                                Console.Write("\n输入您要删除的数据: ");
                                int rollNo = Convert.ToInt32(Console.ReadLine());
                                Console.WriteLine();
                                if (obj.delNode(rollNo) == false)
                                    Console.WriteLine("记录没有找到");
                                else
                                    Console.WriteLine("学号" + rollNo + " 已经被删除了");
                            }
                            break;
                        case '3':
                            {
                                obj.traverse();
                            }
                            break;
                        case '4':
                            {
                                if (obj.listEmpty() == true)
                                {
                                    Console.WriteLine("\n链表为空");
                                    break;
                                }
                                Node prev, curr;
                                prev = curr = null;
                                Console.Write("\n请输入您要查找的学生学号: ");
                                int num = Convert.ToInt32(Console.ReadLine());
                                if (obj.Search(num, ref prev, ref curr) == false)
                                    Console.WriteLine("\n记录没有发现");
                                else
                                {
                                    Console.WriteLine("\n记录发现");
                                    Console.WriteLine("\n学生学号: " + curr.rollNumber);
                                    Console.WriteLine("\n姓名: " + curr.name);
                                }
                            }
                            break;
                        case '5':
                            {
                                obj.firstNode();
                            }
                            break;
                        case '6':
                            return;
                        default:
                            {
                                Console.WriteLine("无效选项");
                                break;
                            }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
            }
        }
    }
}




猜你喜欢

转载自blog.csdn.net/zhangchen124/article/details/51637428