数据结构——单链表
单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
起初我们创建一个节点类
//英雄节点
class HeroNode {
public int no; //英雄编号
public String name; //名称
public String nickname; //绰号
public HeroNode next; //下一个节点
public HeroNode(int no, String name, String nickname) {
this.no = no;
this.name = name;
this.nickname = nickname;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickname='" + nickname + '\'' +
'}';
}
}
节点类中包括了编号和名称以及下一个节点的next。具体实现单链表主要靠no和next来实现。
创建单链表类
//单链表类
class SingleLinkedList {
//头节点用于控制,不存放数据
HeroNode head = new HeroNode(0, "", "");
/**
* 添加节点,无序,按照添加的顺序形成单链表
* 思路:找到最后一个节点,将最后一个节点的next指向添加的节点
*
* @param heroNode 要添加的节点
*/
public void add(HeroNode heroNode) {
HeroNode temp = head; //用于过渡的节点
//循环找到最后一个节点
while (true) {
if (temp.next == null) {
break;
}
temp = temp.next;
}
//循环结束:找到最后一个节点。将最后一个节点的next指向要添加的节点
temp.next = heroNode;
}
/**
* 第二种方式,再添加节点时,根据序号将节点插入到指定位置
* (如果序号已存在。则添加失败,给出提示)
* 思路:判断节点的next的no是否大于节点的no 如果大于了,说明插入的节点就应该在现在的节点之后。
* 如果next的no==插入的节点的no,说明已经存在了。
*
* @param heroNode
*/
public void addByOrder(HeroNode heroNode) {
HeroNode temp = head;
//boolean isHad = false; //标志是否节点已经存在
while (true) {
if (temp.next == null) {//已经到达了最后一个节点
break;
}
if (temp.next.no > heroNode.no) {//如果下一个节点的序号大于了要插入的节点的序号
break;
} else if (temp.next.no == heroNode.no) {//如果下一个节点的序号等于了要插入的节点的序号
System.out.println(heroNode.no + "该数据已存在");
return;
}
temp = temp.next;
}
heroNode.next = temp.next;
temp.next = heroNode;
}
//显示所有链表
public void list() {
if (head.next == null) {
//判断链表是否为空
System.out.println("链表为空");
}
//因为头节点不能动,所以我们需要用一个辅助遍历来遍历
HeroNode temp = head.next;
while (temp != null) {
System.out.println(temp);
temp = temp.next;
}
}
/**
* 找到传入节点序号的节点,修改其姓名和昵称
*
* @param newHeroNode
*/
public void update(HeroNode newHeroNode) {
if (head.next == null) {
System.out.println("链表为空,无法修改~~~");
return;
}
HeroNode temp = head.next;
while (true) {
if (temp == null) {//遍历结束了,此时temp指向了null值
break;
}
if (temp.no == newHeroNode.no) {//找到了对应的节点
temp.name = newHeroNode.name;
temp.nickname = newHeroNode.nickname;
return;
}
temp = temp.next;
}
//遍历结束,没有找到对应的节点
System.out.printf("链表中没有序号为 %d 的节点,无法修改\n", newHeroNode.no);
}
/**
* 删除节点
* 思路:必须找到要删除节点的前一个节点,如果temp.next.no == no 就让这个节点跳过要删除的节点,指向它的下一个节点
* temp.next = temp.next.next 这样遍历的时候就找不到删除的节点了,遍历不到的节点会交给java的垃圾回收机制处理。
* 这样就起到了删除的作用
* @param no 要删除的节点的编号
*/
public void delete(int no) {
HeroNode temp = head;
while (true){
if(temp.next==null){ //遍历完数据
System.out.println("没有找到要删除的元素");
break;
}
if(temp.next.no==no){
temp.next = temp.next.next;
return;
}
temp = temp.next;
}
}
}
1.向单链表中加入数据
链表是通过尾部的next指向下一个节点完成的。如图所示
2.遍历单链表展示数据
首先判断单链表是否为空,如果非空就先让一个过渡遍历temp指向头节点的下一个节点。如何判断temp是否为空,注意,这里不是判断temp的next,因为每次要输出temp所以只要每次判断temp即可。当temp为null时,遍历链表结束。
3.修改单链表的数据
既然要修改单链表的数据,那么我们就需要知道要修改的是哪一个节点,当传过来一个新节点的时候,同遍历节点一样,将temp先等于头节点的下一个节点。然后每次判断temp的no是否等于传过来的新节点的no。如果等于了。就说明找到了。当temp为null时,则遍历单链表结束。循环跳出。未找到相应的节点。
4.删除单链表中的数据
要删除单链表中的数据,不可少的就是首先要找到要删除的是哪一个数据,然后将删除的节点移除,最终要的是要将删除的节点的前一个节点的next要指向删除的节点后一个节点的next。如下图所示:
所以此处应该找到删除节点的前一个节点。(如果找到要删除的节点,而非前一个节点,则无法完成重新指向的操作)。每次判断temp.next.nono
,no是方法传递过来的值。如果temp.nextnull,则说明遍历结束没有找到要删除的节点。如果找到了则完成temp.next = temp.next.next
下面是主函数测试类
/**
* 单链表
*/
public class SingleLinkedListDemo {
public static void main(String[] args) {
HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
HeroNode hero3 = new HeroNode(3, "吴用", "智多星");
HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");
//创建单链表
SingleLinkedList singleLinkedList = new SingleLinkedList();
//向单链表中加入数据
// singleLinkedList.add(hero1);
// singleLinkedList.add(hero4); //此时没有按照英雄的编号排序,所以会根据添加的顺序进行展示
// singleLinkedList.add(hero2);
// singleLinkedList.add(hero3);
// singleLinkedList.add(hero5);
//显示链表
//singleLinkedList.list();
//向单链表中加入数据
singleLinkedList.addByOrder(hero1);
singleLinkedList.addByOrder(hero4); //此时添加的数据会按照顺序添加,并且不可添加重复的编号
singleLinkedList.addByOrder(hero2);
singleLinkedList.addByOrder(hero3);
//显示链表
singleLinkedList.list();
//执行修改链表的操作
HeroNode newHero = new HeroNode(4, "冲冲", "小豹豹");
singleLinkedList.update(newHero);
System.out.println("修改后的信息为~~");
singleLinkedList.list();
//指向删除节点的操作
singleLinkedList.delete(4);
singleLinkedList.delete(3);
singleLinkedList.delete(1);
singleLinkedList.delete(2);
System.out.println("删除节点后的链表为~~~");
singleLinkedList.list();
}
}
具体思路大家可以运行出来后,自己调试一下看看运行结果即可。