文西马龙:http://blog.csdn.net/wenximalong/
链表——双向链表
关于按照英雄的排行顺序加入,参考我的这篇博文中的详细图文说明:韩顺平_PHP程序员玩转算法公开课(第一季)03_单链表crud操作之_水浒英雄排行算法_学习笔记_源代码图解_PPT文档整理
现在分析添加的情况
已经有1号英雄和5号英雄,现在要添加3号英雄
此时cur指向了1号英雄,hero指向3号英雄
cur指向1号英雄,发现cur的下一个是5号英雄,大于要添加的3号英雄
分析图
过程
(1)让3号英雄指向5号英雄,即把这个①号线搭起来
$hero->next=$cur->next;
//$cur指向1号英雄,$cur->next指向5号英雄
(2)然后再搭pre这根线,让3号英雄的pre指向1号英雄,即把这个②号线搭起来
$hero->per=$cur;
(3)然后让5号英雄的pre指向3号英雄,即把这个③号线搭起来
$cur->next->pre=$hero;
//$cur->next指向5号英雄,$cur->next->pre为5号英雄指向1号英雄,即图中⑥号线
//此时⑥号线就断掉了,原来的5号英雄的pre是指向1号英雄的,现在指向了3号英雄
(4)让1号英雄指向3号英雄,即把这个④号线搭起来
$cur->next=$hero;
//此时⑤号线就断掉了,原来的$cur->next是指向5号英雄的,现在指向了3号英雄
★自己对照图,走一遍,一定要线清楚了
doubleLink.php
双向链表完成英雄排行管理
查询英雄
添加英雄
删除英雄
修改英雄
no=$no;
$this->name=$name;
$this->nickname=$nickname;
}
//添加hero,这里我们会构建一个双向链表
//这里使用了静态函数
public static function addHero($head,$hero){
//$head头节点不能动
//$cur为辅助节点,让$cur来穿针引线
$cur=$head;
//isExist 假设英雄不存在
$isExist=FALSE; //这是一个标志位
//首先看看目前的这个链表是不是空的
//当还有英雄的时候,$cur指向的$head节点的next属性必然为null,因为现在只有head节点,还没有添加英雄
//如果是空链表就直接加入
//怎样把空链表和普通链表并和在一起呢?
if($cur->next==null){ //如果是,就说明是空链表,添加第一个英雄
$cur->next=$hero;
//这样就首尾相连了
$hero->pre=$cur;
}else{ //当不是空节点的时候
//如果不是空节点,按照排名来添加
//首先找到添加的位置
while($cur->next!=null){ //只要$cur->next不等于null,就说明没有到队尾
if($cur->next->no > $hero->no){ //说明位置找到了,则说明$hero要加在$cur的后面
break;
}else if($cur->next->no==$hero->no){
$isExist=TRUE;
echo'
不能添加相同的编号';
}
//继续下一个
$cur=$cur->next;
}
//退出该while循环时候,我们只需要把$hero添加到$cur后面即可,(队尾)
//说明还没有这个排名,可以添加,并可以和上面的空链表判断合并
if(!$isExist){ //如果不存在就添加,因为在上面break跳出的时候,就说明找到了,跳出的时候$isExist为假,则!$isExist为真
//添加,有点麻烦
$hero->next=$cur->next;
$hero->pre=$cur;
$cur->next->pre=$hero;
$cur->next=$hero;
}
}
}
//遍历显示双向链表,显示所有英雄的函数
public static function showHero($head){
//上来线做一个辅助指针,穿针引线
$cur=$head->next; //头本来就是空的,这样就输出打印的时候,不输出头了
//$cur=$head; 如果是这样,每次输出的时候会输出:编号= 名字= 外号= 把头也输出了
while($cur->next!=null){ //为空就说明到队尾了
echo'
编号='.$cur->no.'名字='.$cur->name.'外号='.$cur->nickname;
//继续下移一步
$cur=$cur->next;
}
//当退出while的时候,$cur就指向了最后的那个节点了
//要是不输出,就会少一个人,少队尾的那个人
echo'
编号='.$cur->no.'名字='.$cur->name.'外号='.$cur->nickname;
}
}
//创建一个头节点
$head=new Hero();
//创建一个英雄
$hero=new Hero(1,'宋江','及时雨');
//静态方法的调用
Hero::addHero($head,$hero);
$hero=new Hero(2,'卢俊义','玉麒麟');
Hero::addHero($head,$hero);
$hero=new Hero(6,'林冲','豹子头');
Hero::addHero($head,$hero);
$hero=new Hero(3,'吴用','智多星');
Hero::addHero($head,$hero);
$hero=new Hero(56,'孙二娘','母夜叉');
Hero::addHero($head,$hero);
echo '
英雄排行榜.....';
//显示
Hero::showHero($head);
?>
即在doubleLink.php中的这段代码
if($cur->next==null){ //如果是,就说明是空链表,添加第一个英雄
$cur->next=$hero;
//这样就首尾相连了
$hero->pre=$cur;
}else{...
都是在说当$cur->next为空的时候,就执行
$cur->next=$hero;
$hero->pre=$cur;
所以可以把前面的if和现在的合并了,修改后的代码为
doubleLink2.php
双向链表完成英雄排行管理
查询英雄
添加英雄
删除英雄
修改英雄
no=$no;
$this->name=$name;
$this->nickname=$nickname;
}
//添加hero,这里我们会构建一个双向链表
//这里使用了静态函数
//添加英雄,把添加时是空链表和不是空链表的情况,合并到一起了
public static function addHero($head,$hero){
//$head头节点不能动
//$cur为辅助节点,让$cur来穿针引线
$cur=$head;
//isExist 假设英雄不存在
$isExist=FALSE; //这是一个标志位
//首先看看目前的这个链表是不是空的
//当还有英雄的时候,$cur指向的$head节点的next属性必然为null,因为现在只有head节点,还没有添加英雄
//如果是空链表就直接加入
//怎样把空链表和普通链表并和在一起呢?
while($cur->next!=null){ //只要$cur->next不等于null,就说明没有到队尾
if($cur->next->no > $hero->no){ //说明位置找到了,则说明$hero要加在$cur的后面
break;
}else if($cur->next->no==$hero->no){
$isExist=TRUE;
echo'
不能添加相同的编号';
}
//继续下一个
$cur=$cur->next;
}
//退出该while循环时候,我们只需要把$hero添加到$cur后面即可,(队尾)
//说明还没有这个排名,可以添加,并可以和上面的空链表判断合并
if(!$isExist){ //如果不存在就添加,因为在上面break跳出的时候,就说明找到了,跳出的时候$isExist为假,则!$isExist为真
//添加,有点麻烦
//当你添加的人物就在最后,比如现在只有1号英雄,再添加一个5号英雄,肯定是添加在1号英雄的后面
//这里加上if判断,会更稳健型些
if($cur->next!=null){
$hero->next=$cur->next;
}
$hero->pre=$cur;
if($cur->next!=null){
$cur->next->pre=$hero;
}
$cur->next=$hero;
}
}
//遍历显示双向链表,显示所有英雄的函数
public static function showHero($head){
//上来线做一个辅助指针,穿针引线
$cur=$head->next; //头本来就是空的,这样就输出打印的时候,不输出头了
//$cur=$head; 如果是这样,每次输出的时候会输出:编号= 名字= 外号= 把头也输出了
while($cur->next!=null){ //为空就说明到队尾了
echo'
编号='.$cur->no.'名字='.$cur->name.'外号='.$cur->nickname;
//继续下移一步
$cur=$cur->next;
}
//当退出while的时候,$cur就指向了最后的那个节点了
//要是不输出,就会少一个人,少队尾的那个人
echo'
编号='.$cur->no.'名字='.$cur->name.'外号='.$cur->nickname;
}
}
//创建一个头节点
$head=new Hero();
//创建一个英雄
$hero=new Hero(1,'宋江','及时雨');
//静态方法的调用
Hero::addHero($head,$hero);
$hero=new Hero(2,'卢俊义','玉麒麟');
Hero::addHero($head,$hero);
$hero=new Hero(6,'林冲','豹子头');
Hero::addHero($head,$hero);
$hero=new Hero(3,'吴用','智多星');
Hero::addHero($head,$hero);
$hero=new Hero(56,'孙二娘','母夜叉');
Hero::addHero($head,$hero);
echo '
英雄排行榜.....';
//显示
Hero::showHero($head);
?>
======
此时删除英雄就不需要辅助节点了
分析图
当要删除的节点在最后的时候,还需要判断下
此时$cur->next本身就是空了,所有要加判断了
$cur->pre->next=$cur->next; //这个就相当于把1号节点的next置空了,这个没错
所以要这样:
if($cur->next!=null){
$cur->next->pre=$cur->pre;
}
$cur->pre->next=$cur->next;
这样执行的话,把上图中的蓝线就去掉了,这样6号英雄就访问不到了,6号英雄出列了,因为我们是从表头开始找的,$cur-next就访问不到6号英雄节点了,6号英雄指向别人是没有用的,★关键★是没有人指向它。
注意:要考虑删除第一个和最后一个,(当你的代码考虑不周全的时候)这是最容易出错的,所以要测试
doubleLink3.php
双向链表完成英雄排行管理
查询英雄
添加英雄
删除英雄
修改英雄
no=$no;
$this->name=$name;
$this->nickname=$nickname;
}
//添加hero,这里我们会构建一个双向链表
//这里使用了静态函数
//添加英雄,把添加时是空链表和不是空链表的情况,合并到一起了
public static function addHero($head,$hero){
//$head头节点不能动
//$cur为辅助节点,让$cur来穿针引线
$cur=$head;
//isExist 假设英雄不存在
$isExist=FALSE; //这是一个标志位
//首先看看目前的这个链表是不是空的
//当还有英雄的时候,$cur指向的$head节点的next属性必然为null,因为现在只有head节点,还没有添加英雄
//如果是空链表就直接加入
//怎样把空链表和普通链表并和在一起呢?
while($cur->next!=null){ //只要$cur->next不等于null,就说明没有到队尾
if($cur->next->no > $hero->no){ //说明位置找到了,则说明$hero要加在$cur的后面
break;
}else if($cur->next->no==$hero->no){
$isExist=TRUE;
echo'
不能添加相同的编号';
}
//继续下一个
$cur=$cur->next;
}
//退出该while循环时候,我们只需要把$hero添加到$cur后面即可,(队尾)
//说明还没有这个排名,可以添加,并可以和上面的空链表判断合并
if(!$isExist){ //如果不存在就添加,因为在上面break跳出的时候,就说明找到了,跳出的时候$isExist为假,则!$isExist为真
//添加,有点麻烦
//当你添加的人物就在最后,比如现在只有1号英雄,再添加一个5号英雄,肯定是添加在1号英雄的后面
//这里加上if判断,会更稳健型些
if($cur->next!=null){
$hero->next=$cur->next;
}
$hero->pre=$cur;
if($cur->next!=null){
$cur->next->pre=$hero;
}
$cur->next=$hero;
}
}
//删除某位英雄,现在不需要辅助节点了
public static function delHero($head,$herono){
//我们不使用辅助节点了
//先找到$head
//$head不能动
//直接让$cur指向下一个,$head->next就是具体的英雄了,当然还要先判断,$cur->next是不是空,要是空,就是光有head了,也没有要删除的了
$cur=$head->next;
$isFind=flase; //先搞个标志位
while($cur!=null){
if($cur->no==$herono){
//找到了,就置为true,并跳出
$isFind=true;
break;
}
//如果上面的if没有找到,就不停的向下走
$cur=$cur->next;
}
if($isFind){
//当$isFind为真的时候,就说明找到了
//执行删除
//自我删除
//这里考虑了要删除的英雄在末尾的时候情况
if($cur->next!=null){
$cur->next->pre=$cur->pre;
}
$cur->pre->next=$cur->next;
echo '
要删除的英雄编号是'.$cur->no;
}else{
echo'
要删除的英雄没有';
}
}
//遍历显示双向链表,显示所有英雄的函数
public static function showHero($head){
//上来线做一个辅助指针,穿针引线
$cur=$head->next; //头本来就是空的,这样就输出打印的时候,不输出头了
//$cur=$head; 如果是这样,每次输出的时候会输出:编号= 名字= 外号= 把头也输出了
while($cur->next!=null){ //为空就说明到队尾了
echo'
编号='.$cur->no.'名字='.$cur->name.'外号='.$cur->nickname;
//继续下移一步
$cur=$cur->next;
}
//当退出while的时候,$cur就指向了最后的那个节点了
//要是不输出,就会少一个人,少队尾的那个人
echo'
编号='.$cur->no.'名字='.$cur->name.'外号='.$cur->nickname;
}
}
//创建一个头节点
$head=new Hero();
//创建一个英雄
$hero=new Hero(1,'宋江','及时雨');
//静态方法的调用
Hero::addHero($head,$hero);
$hero=new Hero(2,'卢俊义','玉麒麟');
Hero::addHero($head,$hero);
$hero=new Hero(6,'林冲','豹子头');
Hero::addHero($head,$hero);
$hero=new Hero(3,'吴用','智多星');
Hero::addHero($head,$hero);
$hero=new Hero(56,'孙二娘','母夜叉');
Hero::addHero($head,$hero);
echo '
英雄排行榜.....';
//显示
Hero::showHero($head);
echo'
';
echo '
删除后的英雄排行榜.....';
Hero::delHero($head,3);
Hero::showHero($head);
echo'
';
echo'
下面测试删除最前面的和最后面的英雄
';
echo '
删除后的英雄排行榜.....';
Hero::delHero($head,1);
Hero::showHero($head);
echo'
';
echo '
删除后的英雄排行榜.....';
Hero::delHero($head,56);
Hero::showHero($head);
?>
韩顺平_PHP程序员玩转算法公开课_学习笔记_源代码图解_PPT文档整理_目录