数据结构与算法——单链表

链表

链表是有序的列表,但是它在内存中是存储如下

  1. 链表是以节点的方式来存储的
  2. 每个节点包含 data 域,next 域:指向下一个节点
  3. 链表的各个节点不一定是连续存储的
  4. 链表分 带头结点 的链表和 不带头结点 的链表

单链表的创建

在这里插入图片描述
添加

  1. 先创建一个 head 头结点,作用就是表示单链表的头
  2. 后面我们每添加一个结点,就直接加入到链表的最后

遍历:
通过一个辅助变量,帮助来遍历整个链表

单链表的应用实例

第一种方式:给链表添加结点时,直接添加到链表的尾部
第二种方式:添加结点,根据结点编号将结点插入到指定位置

第一种方式:

1、定义一个结点类(HeroNode),每个类对象都是一个链表的结点

class HeroNode{
	int no;			// 编号
	String name;		// 姓名
	String nickname;	// 昵称
	HeroNode next;		// 下一个节点
	
	public HeroNode(int no, String name, String nickname) {
		this.no = no;
		this.name = name;
		this.nickname = nickname;
	}

	// 重写toString方法
	@Override
	public String toString() {
		return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
	}
}

2、构建一个单链表 SingleLinkedList

class SingleLinkedList{
	// 先初始化一个头节点,头节点不要动,不存放具体的数据
	HeroNode head = new HeroNode(0, "", "");
}

2.1、在单链表中添加结点

  • 找到当前链表的最后结点
  • 将最后这个结点 next 指向新的结点
public void add(HeroNode heroNode) {
    // 头节点不可移动,先用一个变量给其保存起来。
    HeroNode temp = head;
    while(true) {
        // 找到链表的最后
        if(temp.next == null) {
            break;
        }
        // 如果没有找到最后,就将 temp后移
        temp = temp.next;
    }
    // 当退出 while 循环的时候,temp 就指向了链表的最后
    // 将最后这个节点的 next 指向新的节点
    temp.next = heroNode;
}

3、打印出链表

public void list() {
    // 判断链表是否为空
    if(head.next == null) {
        System.out.println("链表为空");
        return;
    }
    // 因为头节点,不能动,因此我们需要一个辅助变量
    HeroNode temp = head.next;
    while(true) {
        // 判断是否到链表最后
        if(temp == null) {
            break;
        }
        // 输出节点的信息
        System.out.println(temp);
        temp = temp.next;
    }
}

4、进行测试

public static void main(String[] args) {
    // 测试
    // 创建几个节点
    HeroNode hero1 = new HeroNode(1, "AA", "AAA");
    HeroNode hero2 = new HeroNode(2, "BB", "BBB");
    HeroNode hero3 = new HeroNode(3, "CC", "CCC");
    HeroNode hero4 = new HeroNode(4, "DD", "DDD");

    // 创建要给链表
    SingleLinkedList singlelist = new SingleLinkedList();
    // 加入
    singlelist.add(hero1);
    singlelist.add(hero2);
    singlelist.add(hero3);
    singlelist.add(hero4);

    singlelist.list();	
}

第二种方式

步骤:

  1. 首先找到新添加的结点的位置,是通过辅助变量(temp),通过遍历来保存
  2. 新的结点.next = temp.next
  3. 将 temp.next = 新的结点

添加规则:
因为头节点不能动,因此我们还需要一个辅助指针来帮我们找到添加的位置
待插入的位置应该是在辅助变量结点 temp 之后,temp.next 之前
写一个 addByOrder 的方法

public void addByOrder(HeroNode heroNode) {
    // 因为头节点不能动,因此我们仍然通过一个辅助指针(变量)来帮助找到添加的位置
    // 因为是单链表,我们找到 temp 是位于添加位置的前一个节点,否则插入不了
    HeroNode temp = head;
    boolean flag = false;
    while(true) {
        if(temp.next == null) {	// 说明到了链表的最后,直接 break
            break;
        }
        if(temp.next.no > heroNode.no) {	// 说明希望添加的 heroNode 的编号存在
            break;
        }
        if(temp.next.no == heroNode.no) {	// 说明了当前要添加的编号已经存在了
            flag = true;
            break;
        }
        temp = temp.next;	// 后移,相当于在遍历当前的链表
    }

    if(flag) {// 说明节点已经存在了
        System.out.printf("准备插入的节点 %d 已经存在了\n", heroNode.no);
    } else {
        heroNode.next = temp.next;
        temp.next = heroNode;
    }
}

注意点:

  1. 判断 temp 是不是在最后一个结点
  2. 判断待插入的结点是不是已经存在了,如果存在了输出已经存在

链表结点的修改

修改结点通过结点的编号来修改,但是结点的编号是不可以改变的

public void update(HeroNode newHeroNode) {
    // 判断是否为空
    if(head.next == null) {	// 
        System.out.println("链表为空");
        return;
    }
    // 找到需要修改的节点,根据 no 编号
    // 定义一个辅助变量
    HeroNode temp = head.next;		// 首先指向的 0 号节点
    boolean flag = false;
    while(true) {
        if(temp == null) {
            break;	// 表示已经遍历完成
        }
        if(temp.no == newHeroNode.no) {	// 找到
            flag = true;
            break;
        }
        temp = temp.next;
    }
    // 根据 flag 
    if(flag) {
        temp.name = newHeroNode.name;
        temp.nickname = newHeroNode.nickname;
    }else {
        System.out.printf("没有找对编号为 %d 的节点", newHeroNode.no);
    }
}

删除单个结点

思路:

  1. head 不能用,找一个辅助结点 temp 用来指向待删除的前一个结点
  2. 在进行比较的时候是 temp.next 与 要删除的结点的 编号(no) 进行比较
public void del(int no) {
    HeroNode temp = head;
    boolean flag = false;
    while(true) {
        if(temp.next == null) {
            break;			// 到达了链表的最后
        }
        if(temp.next.no == no) {
            flag = true;
            break;				// 说明找到了对应的节点
        }
        temp = temp.next;
    }
    // 判断 flag
    if(flag) {	// 找到
        temp.next = temp.next.next;
    }else {
        System.out.println("没有找到对应的节点");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值