1,单向链表的缺点分析:不能自我删除,需要靠辅助节点。

---因为单向链表只有后继,没有前驱,它不知道自己前边是谁,所以它自己不能删除自己,必须要辅助节点,它能删除自己。

 

2,双向链表,可以自我删除。

---上边两行语句,就能将cur节点删除,不依赖任何辅助节点,就能将自己删除。

 

3,下面是双向链表的内存示意图。

 4,C#显示代码如下:

---前台html代码:

<form id="form1" runat="server">
    <div>
        <h1>单向链表完成英雄排行管理</h1>
        <hr />
        <a href="#">查询英雄</a>
        <a href="#">添加英雄</a>
        <a href="#">删除英雄</a>
        <a href="#">修改英雄</a>
        <%=heros %>
    </div>
    </form>

---后台cs代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace linkTest
{
    public partial class doublelink : System.Web.UI.Page
    {
        protected string heros;
        protected void Page_Load(object sender, EventArgs e)
        {
            //创建一个head头,该链表只有一个头,不放入数据
            Heros head=new Heros();          
            Heros hero01=new Heros(1,"宋江","及时雨");
            Heros hero02 = new Heros(2, "卢俊义", "玉麒麟");
            Heros hero06 = new Heros(6, "林冲", "豹子头");
            Heros hero03 = new Heros(3, "吴用", "智多星");
            Heros.addHero(head,hero01);
            Heros.addHero(head, hero02);
            Heros.addHero(head, hero06);
            Heros.addHero(head, hero03);
            Heros.delHero(head,1);
            heros=Heros.showHero(head);
        }
    }

    public class Heros
    {
        public Heros pre = null;//表示指向前一个节点的引用
        public int? num;
        public string name;
        public string nickname;
        public Heros next = null;//表示指向后一个节点的引用

        public Heros(int? num=null,string name="",string nickname="")
        {
            this.num = num;
            this.name = name;
            this.nickname = nickname;
        }

        //添加hero,这里我们会构建一个双向链表。注意,英雄只能一个一个的添加,调用这个函数添加。
        public static string addHero(Heros head, Heros hero)
        {
            //head节点不能动.
            Heros cur = head;//辅助引用cur
            bool isExist = false;
            //如果不是空节点,按照排名来添加。
            //找到添加的位置
            while (cur.next != null)  //假如循环到最后,就会跳出循环,下边代码就会将hero放到cur的后边
            {
                //cur.next的序号大于插入英雄的序号,那么插入英雄,就应该放在cur和cur.next中间。
                if (cur.next.num > hero.num)
                {
                    //说明hero就应该加入到cur和cur.next中间。
                    break;
                }
                else if (cur.next.num == hero.num) //如果序号相等,就是重复的添加。
                {
                    isExist = true; //不能添加相同的编号。
                    return "<br/>不能添加相同的编号";
                }
                else  //否则就是,插入英雄的序号,大于cur.next的序号,那就应该继续循环和下面的英雄序号对比。
                {
                    cur = cur.next;
                }
            }
            //退出该while时,我们只需要把hero添加到cur后面即可。
            if (!isExist)
            {
                if (cur.next != null)
                {
                    //cur.next.pre = hero;
                    //加入一个hero,需要调整4根线的指向
                    hero.next = cur.next;
                    hero.pre = cur;
                    cur.next = hero;
                    hero.next.pre = hero;
                }
                else
                {
                    hero.pre = cur;
                    cur.next = hero;
                }
            }
            return "<br/>插入成功!";
        }

        //删除某位英雄
        public static void delHero(Heros head,int heronum)
        {
            //我们不使用辅助节点删除。
            Heros cur = head;
            bool isFind = false; //是否找到标志位
            while (cur.next != null)
            {
                if (cur.next.num == heronum)
                {
                    //如果找到了,就跳出循环,改变标志位的值。
                    isFind = true;
                    break;
                    //if (cur.next.next != null)
                    //{                     
                    //    cur.next = cur.next.next;
                    //    cur.next.pre = cur;                   
                    //}
                    //else
                    //{
                    //    cur.next = null;
                    //}
                    //break;
                }
                cur = cur.next;  //没找到,继续循环。
            }
            if (isFind)
            {
                if (cur.next.next != null)
                {
                    cur.next = cur.next.next;
                    cur.next.pre = cur;
                }
                else
                {
                    cur.next = null;
                }
            }
            else
            {
                //这里,可以返回一个响应字符串,很抱歉,没有要删除的英雄对象。
            }
        }

        //显示所有英雄的函数
        public static string showHero(Heros head)
        {
            Heros cur = head;
            StringBuilder sb=new StringBuilder();
            while (cur.next != null)
            {
                //这里输出的是当前节点的下一个节点的值。所以当最后一个节点,跳出循环时,最后一个节点的值已经输出了,在前一个节点时已经输出了。
                sb.Append("<br/>编号=" + cur.next.num + ",名字=" + cur.next.name + ",外号="+cur.next.nickname);
                cur = cur.next;
            }
            return sb.ToString();
        }
    }
}

 

@总结:

1,双向链表可以完成自我删除,效率相对高,而且你明白这双向链表后,为你将来学习二叉树打下良好基础。

posted on 2014-05-04 21:52  学到老死  阅读(692)  评论(0)    收藏  举报