来自视频尚硅谷:尚硅谷
1.代码
public class SingleLinkedListDemo {
public static void main(String[] args) {
//进行测试
//先创建节点
HeroNode heroNode = new HeroNode(1, "唐三", "昊天宗");
HeroNode heroNode1 = new HeroNode(2, "小舞", "十万年魂兽");
HeroNode heroNode2 = new HeroNode(3, "宁荣荣", "七宝琉璃宗");
HeroNode heroNode3 = new HeroNode(4, "千仞雪", "武魂殿");
//创建链表,并加入节点
MyLinkedList myLinkedList = new MyLinkedList();
// myLinkedList.add(heroNode);
// myLinkedList.add(heroNode3);
// myLinkedList.add(heroNode1);
// myLinkedList.add(heroNode2);
//根据顺序来加入节点
myLinkedList.addByOrder2(heroNode);
myLinkedList.addByOrder2(heroNode3);
myLinkedList.addByOrder2(heroNode1);
myLinkedList.addByOrder2(heroNode2);
myLinkedList.addByOrder2(heroNode2);
// //遍历节点
myLinkedList.list();
}
private static class HeroNode {
private int no;
private String name;
private String background;
private HeroNode next;
//背景
public HeroNode(int no, String name, String background) {
this.no=no;
this.name=name;
this.background =background;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", background='" + background + '\'' +
'}';
}
}
private static class MyLinkedList {
//默认设置有一个头节点
private HeroNode head=new HeroNode(0,"","");
public void add(HeroNode heroNode) {
HeroNode temp=head;
//遍历出最后一个节点
while (true) {
if (temp.next==null) {
break;
}
//后移
temp=temp.next;
}
//对最后一个节点进行赋值
temp.next=heroNode;
}
public void list() {
//判断队列是否为空,如果是空的话,就没有必要遍历
if (head.next==null) {
System.out.println("链表为空");
return;
}
System.out.println("链表结果打印如下:");
//因为头节点不能动,所以我们需要一个辅助遍历来遍历
HeroNode temp = head.next;
while (true) {
//判断是否为最后一个节点
if (temp==null) {
break;
}
//输出节点的信息
System.out.println(temp);
//将temp后移,一定要小心
temp=temp.next;
}
}
/**
* 下面的方法耦合性比较大,就是有什么就做什么。而addByOrder2里面的方法则是,分成两部分:获取状态,根据状态来进行逻辑处理,这样比较解耦,高内聚(统一处理)
* @param heroNode
*/
public void addByOrder(HeroNode heroNode) {
//判断队列是否为空队列,如果是空队列的话,就直接加入
HeroNode temp =head;
//队列不为空的情况
//遍历获取队列比heroNode.no大的值的前一个
while (true) {
//如果队列存在了,就不添加进去
if (temp.next==null) {
temp.next=heroNode;
break;
}else
if (temp.next.no==heroNode.no) {
System.out.println("队列已经存在了,无法在添加进去");
break;
}else
//下面是获取比heroNode.no大的值,然后temp就是前一个
if (temp.next.no>heroNode.no) {
//先让heroNode的next指向比它大值得那个
heroNode.next=temp.next;
//再让上一个指向添加的值
temp.next=heroNode;
break;
}else if (temp.next==null){
temp.next=heroNode;
break;
}
//如果不是的话,就后移,便于继续遍历
temp=temp.next;
}
}
/**
* ,分成两部分:获取状态,根据状态来进行逻辑处理,这样比较解耦,高内聚(统一处理)
* @param heroNode
*/
public void addByOrder2(HeroNode heroNode){
//因为头节点不能动,因此我们仍然通过一个辅助指针来帮助找到添加的位置
//要找到单链表的前一个,如果找到的是这个,那么久只能为这个赋值,
HeroNode temp = this.head;
boolean flag=false;
while (true) {
if (temp.next==null) {//说明是队列的最后一个了,直接添加即可
break;
}
if (temp.next.no>heroNode.no) {
break;
}else if (temp.next.no==heroNode.no){//这个编号已经添加过了
flag=true;
break;
}
temp=temp.next;
}
//判断flag的值
if (flag) {
System.out.printf("准备插入的英雄编号 %d 已经存在了,不能加入\n",heroNode.no);
}else {
//插入得到链表中,temp的后面
heroNode.next=temp.next;
temp.next=heroNode;
}
}
}
}
2.图解
1.特点
单向链表一般都有一个头节点(也可以没有)head,地址是无序的,而数值是有序的,数组做个指针偏移,就可以进行查找,所以数组查找比较快
date域:就是一些数值,比方说这个节点是一个斗罗大陆里面的人物,date域=名字小舞,背景是十万年魂兽,专一。
next域:指向下一个节点,如下:头结点head的头指针指向a1,a1的next域指向的是110,既就是指向a2,a2的next域地址指向a3,……
2.单向链表的简单实现
首先创建一个头节点head,作用是作为头。节点如下:
代码如下:
节点:
private static class HeroNode {
private int no;
private String name;
private String background;
private HeroNode next;
//背景
public HeroNode(int no, String name, String background) {
this.no=no;
this.name=name;
this.background =background;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", background='" + background + '\'' +
'}';
}
}
添加add与遍历list:
我们添加一个节点,先找到最后一个节点(节点.next=null,就表示是最后一个节点),这里就要通过遍历来获取,最后一个节点的特点是节点.next=null。遍历的话要先判断是否为空,如果为空的话,就没有必要遍历。如果不为空的话,就遍历,如果进行后移,在遍历……直到节点.next=null,为值遍历结束
private static class MyLinkedList {
//默认设置有一个头节点
private HeroNode head=new HeroNode(0,"","");
public void add(HeroNode heroNode) {
HeroNode temp=head;
//遍历出最后一个节点
while (true) {
if (temp.next==null) {
break;
}
//后移
temp=temp.next;
}
//对最后一个节点进行赋值
temp.next=heroNode;
}
public void list() {
//判断队列是否为空,如果是空的话,就没有必要遍历
if (head.next==null) {
System.out.println("链表为空");
return;
}
System.out.println("链表结果打印如下:");
//因为头节点不能动,所以我们需要一个辅助遍历来遍历
HeroNode temp = head.next;
while (true) {
//判断是否为最后一个节点
if (temp==null) {
break;
}
//输出节点的信息
System.out.println(temp);
//将temp后移,一定要小心
temp=temp.next;
}
}
}
3.执行:
//进行测试
//先创建节点
HeroNode heroNode = new HeroNode(1, "唐三", "昊天宗");
HeroNode heroNode1 = new HeroNode(2, "小舞", "十万年魂兽");
HeroNode heroNode2 = new HeroNode(3, "宁荣荣", "七宝琉璃宗");
HeroNode heroNode3 = new HeroNode(4, "千仞雪", "武魂殿");
//创建链表,并加入节点
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.add(heroNode);
myLinkedList.add(heroNode3);
myLinkedList.add(heroNode1);
myLinkedList.add(heroNode2);
//遍历节点
myLinkedList.list();
4.对加入的进行排序
上面的no是没有按照顺序排序的,那怎么按照no大小来排序呢
上图中,先添加no为1,然后是no=4,现在要加入no=2,我们想的是2添加到1后面,4的前面,如上图。那我们必须找到1这个节点,然后把2节点.next=1节点.next(这里就是4节点),然后再把1节点.next=2节点,这就实现需求了。如果找的是4节点,那么我们无法获取它的前一个节点1,那么我们无法对1节点.next赋值为2.
/**
* ,分成两部分:获取状态,根据状态来进行逻辑处理,这样比较解耦,高内聚(统一处理)
* @param heroNode
*/
public void addByOrder2(HeroNode heroNode){
//因为头节点不能动,因此我们仍然通过一个辅助指针来帮助找到添加的位置
//要找到单链表的前一个,如果找到的是这个,那么久只能为这个赋值,
HeroNode temp = this.head;
boolean flag=false;
while (true) {
if (temp.next==null) {//说明是队列的最后一个了,直接添加即可
break;
}
if (temp.next.no>heroNode.no) {
break;
}else if (temp.next.no==heroNode.no){//这个编号已经添加过了
flag=true;
break;
}
temp=temp.next;
}
//判断flag的值
if (flag) {
System.out.printf("准备插入的英雄编号 %d 已经存在了,不能加入\n",heroNode.no);
}else {
//插入得到链表中,temp的后面
heroNode.next=temp.next;
temp.next=heroNode;
}
}
5.
6.
7.
3.反思
1.我自己也写了添加代码addByOrder,排序的方法,就是什么情况就直接写出来。耦合性比较大,又不高内聚,不易群体控制。而它写的代码是分为两部分:先把情况列出来(这里代码不同,都是可能结果执行相同),然后再统一控制:
自己的的代码:
/**
* 下面的方法耦合性比较大,就是有什么就做什么。而addByOrder2里面的方法则是,分成两部分:获取状态,根据状态来进行逻辑处理,这样比较解耦,高内聚(统一处理)
* @param heroNode
*/
public void addByOrder(HeroNode heroNode) {
//判断队列是否为空队列,如果是空队列的话,就直接加入
HeroNode temp =head;
//队列不为空的情况
//遍历获取队列比heroNode.no大的值的前一个
while (true) {
//如果队列存在了,就不添加进去
if (temp.next==null) {
temp.next=heroNode;
break;
}else
if (temp.next.no==heroNode.no) {
System.out.println("队列已经存在了,无法在添加进去");
break;
}else
//下面是获取比heroNode.no大的值,然后temp就是前一个
if (temp.next.no>heroNode.no) {
//先让heroNode的next指向比它大值得那个
heroNode.next=temp.next;
//再让上一个指向添加的值
temp.next=heroNode;
break;
}else if (temp.next==null){
temp.next=heroNode;
break;
}
//如果不是的话,就后移,便于继续遍历
temp=temp.next;
}
}