数据结构中,链表的概念,无非是一个结构,或者类,自身中有一个Next属性或者叫任意的名字,但是类型必须也是这个节点的类型。比如下面的例子,类名叫node,其中也要有一个属性类型也是node,这样才能串接起来。如果有多个node属性的话,那可以实现双向链表,或者十字链表,树等多着结构

class node
    {
        public string content = "head";
        public node next = null;
        public node()
        {
        }
        public node(string c)
        {
            content = c;
        }
    }

 

链表的增加元素方法,就是new一个节点,然后将这个节点赋值给链表的最后一个节点的next属性,或者更形象的说是next指向此节点。

如下代码:

node head = new node();

static void AppendNode(ref node head, node data)
       {
           node pointer= head;
           while (pointer.next != null)
           {
               pointer= pointer.next;
           }
           pointer.next = data;
       }
其中head是头结点。然后有一个指针pointer,它指向当前的节点,每当当前的节点的next属性值不是null,意味着当前节点后面还有节点,则pointer移动到下一个节点。直到pointer指向的当前节点后面是null,然后next属性赋值给新的节点。

遍历和删除等操作可以参考数据结构的书,附件代码中也有。主要不要弄错指针指向的对象,和断开指针的顺序。

 

约瑟夫环的概念大家自己百度。

 

本文的实现方式,首先构造一个环形链表,收尾相连的。

static void CreateCycle(ref node head, int length)
        {
            node pointer = head;
            for (int i = 1; i <= length; i++)
            {
                node data = new node(i.ToString());
                pointer.next = data;
                pointer = pointer.next;
            }
            pointer.next = head.next;//头尾相接。
        }

遍历这个环。

static void ShowCycle(node head)
       {
           node pointer = head;
           do
           {
               pointer = pointer.next;
               Console.Write(pointer.content + "->");
           }
           while (pointer.next != head.next);//如果当前的指针的下一个元素是head的下一个元素,既可以断定所有的元素都遍历过了。
           Console.WriteLine();
       }
 

最重要的方法是删除里面的元素,这里pointer一开始和head一样赋值,都指向第一个元素。此处有一些问题如果删除第一个元素,理论上,tobeDeletednode就是第一个元素,将它的值设置null,那么最尾的节点本来连接的tobeDeletednode,设成null后,最尾节点连接的就是null了。但是,测试下来,虽然tobeDeletednode设成null,但是并未真正的释放掉该元素,这和.net垃圾回收机制相关。因此不能用是否next的值为null来判断是否是环的最末元素,只能用是否元素的next指向的值和head指向的值是同一个,来判断是否为最末元素。应该可以有其他写法,但暂时未思考出。

而对于不是删除第一个元素,则很方便的用pointer定位,因此写出如下2中不同的实现,注意高亮的代码的逻辑都是一样的。删除完元素后,把head的next继续pointer指针的next,表示下轮从这个头开始。

//删除之后,head定位到下一个元素上
       static void DeleteCycleNode(ref node head, int index)//index从1算起
       {
           node pointer = new node("pointer");
           pointer.next = head.next;//都指向第一个元素
           node tobeDeletednode;
           if (index == 1)//如果删除的为第一个元素,pointer要定位到最后一个元素上
           {
               do
               {
                   pointer = pointer.next;
               }
               while (pointer.next != head.next);

               tobeDeletednode = pointer.next;
               pointer.next = tobeDeletednode.next;
               head.next = pointer.next;//重新设定头指针
               tobeDeletednode = null;
           }
           else
           {
               for (int i = 1; i &lt; index; i++)
               {
                   pointer = pointer.next;
               }

               tobeDeletednode = pointer.next;
               pointer.next = tobeDeletednode.next;
               head.next = pointer.next;//重新设定头指针
               tobeDeletednode = null;
           }
       }
最后调用一下,加上10元素的环,每次报到3的元素删除:

head = new node();
            CreateCycle(ref  head, 10);
            ShowCycle(head);
            while (head.next.next != head.next)//如果头指向的元素的下一个元素是自己,那么表示这个环只剩下1个元素了,就退出while
            {
                DeleteCycleNode(ref  head, 3);
                ShowCycle(head);
            }

结果如下:

3775C648EDD0463E9EBB10DB0CC617EE