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,双向链表可以完成自我删除,效率相对高,而且你明白这双向链表后,为你将来学习二叉树打下良好基础。
浙公网安备 33010602011771号