数据结构之单链表(增删改查,链表反转,链表逆序遍历,链表合并)

15 篇文章 1 订阅

单链表

单链表介绍

链表在内存中物理结构示意图

  1. 链表是以节点的方式存储的。
  2. 每个节点包含data域和next域
  3. 链表的各个节点之间并不是连续的
  4. 链表分为带头节点的链表和不带头节点的链表
    链表的逻辑结构示意图
单链表的基本操作
  1. 链表节点的数据结构
    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;
            this.next = null;
        }
    
        @Override
        public String toString() {
            return "HeroNode {" +
                    "no=" + no +
                    ", name='" + name + '\'' +
                    ", nickname='" + nickname + '\'' +
                    '}';
        }
    }
    
  2. 带头节点的链表的初始化
    class SingleLinkedList {
    
        private HeroNode head;
    
        public SingleLinkedList() {
            head = new HeroNode(0, "", "");
        }
    }
    
  3. 向链表的尾部添加元素
    public void addNode(HeroNode heroNode) {
        HeroNode temp = head;
        // 循环找到最后一个节点
        while (temp.next != null) {
            temp = temp.next;
        }
        temp.next = heroNode;
    }
    
  4. 按照编号的顺序,将元素加入链表
    // 添加英雄时,按照编号顺序
    public void addNodeByNoOrder(HeroNode heroNode) {
        HeroNode temp = head;
        boolean find = false;
        while (temp.next != null) {
            if (temp.next.no > heroNode.no) {
                break;
            } else if (temp.next.no == heroNode.no) {
                find = true;
                break;
            }
            temp = temp.next;
        }
        if (find) {
            System.out.printf("准备插入的英雄编号%d已经存在,不能加入\n", heroNode.no);
        } else if (temp.next == null) {
            temp.next = heroNode;
        } else {
            heroNode.next =  temp.next;
            temp.next = heroNode;
        }
    }
    
  5. 根据编号删除链表中指定的节点
    // 删除指定的节点
    public void deleteHeroNode(int no) {
    
        HeroNode temp = head;
        boolean find = false;
        while (temp.next != null) {
            if (temp.next.no == no) {
                find = true;
                break;
            }
            temp = temp.next;
        }
        if (find) {
            temp.next = temp.next.next;
        } else {
            System.out.printf("要删除的节点%d不存在", no);
        }
    }
    
  6. 根据标号修改链表元素
    // 修改链表
    public void updateHero(HeroNode newHero) {
    
        HeroNode temp = head.next;
        if (temp == null) {
            System.out.println("链表为空,没有要修改的元素");
            return ;
        }
        boolean find = false;
        while (temp != null) {
            if (temp.no == newHero.no) {
                find = true;
                break;
            }
            temp = temp.next;
        }
        if (find) {
            temp.name = newHero.name;
            temp.nickname = newHero.nickname;
        } else {
            System.out.printf("没有找到编号为%d的英雄\n", newHero.no);
        }
    }
    
  7. 遍历链表
    public void showList() {
        HeroNode temp = head.next;
        while (temp != null) {
            System.out.println(temp);
            temp = temp.next;
        }
    }
    
  8. 测试表的增删改查
    public class SingleLinkedListDemo {
    
        public static void main(String[] args) {
    
            SingleLinkedList singleLinkedList = new SingleLinkedList();
            HeroNode heroNode1 = new HeroNode(1, "宋江", "呼保义");
            HeroNode heroNode2 = new HeroNode(2, "卢俊义", "玉麒麟");
            HeroNode heroNode3 = new HeroNode(3, "吴用", "智多星");
            HeroNode heroNode4 = new HeroNode(4, "公孙胜", "入云龙");
            HeroNode heroNode5 = new HeroNode(5, "大刀", "关胜");
            HeroNode heroNode6 = new HeroNode(6, "林冲", "豹子头");
    
    //        singleLinkedList.addNode(heroNode4);
    //        singleLinkedList.addNode(heroNode1);
    //        singleLinkedList.addNode(heroNode6);
    //        singleLinkedList.addNode(heroNode5);
    //        singleLinkedList.addNode(heroNode3);
    //        singleLinkedList.addNode(heroNode2);
    
            singleLinkedList.addNodeByNoOrder(heroNode4);
            singleLinkedList.addNodeByNoOrder(heroNode1);
            singleLinkedList.addNodeByNoOrder(heroNode6);
            singleLinkedList.addNodeByNoOrder(heroNode5);
            singleLinkedList.addNodeByNoOrder(heroNode3);
            singleLinkedList.addNodeByNoOrder(heroNode2);
    
            singleLinkedList.showList();
    
            HeroNode newHeroNode = new HeroNode(8, "小卢", "玉麒麟~~~");
            singleLinkedList.updateHero(newHeroNode);
            System.out.println("修改后的链表情况~~~~~~~~");
            singleLinkedList.showList();
    
            singleLinkedList.deleteHeroNode(1);
            singleLinkedList.deleteHeroNode(6);
            System.out.println("删除后的链表情况~~~~~~~~");
            singleLinkedList.showList();
        }
    }
    

单链表面试题

  1. 求单链表中有效节点的个数。

    // 获取链表的长度
    public int getLength() {
        if (head.next == null) {
            return 0;
        }
        int length = 0;
        HeroNode currNode = head.next;
        while (currNode != null) {
            length ++;
            currNode = currNode.next;
        }
        return length;
    }
    
  2. 查找单链表中的倒数第k个节点。

    // 获取链表找那个的倒数第k个元素
    public HeroNode getReverseKElement(SingleLinkedList singleLinkedList, int k) {
        // 获取链表的长度
        int length = singleLinkedList.getLength();
        if (length < k || k < 0) {
            System.out.println("要获取的第k个元素不存在");
            return null;
        }
        // 要获取逆序第k个相当有获取正序列的第length - k + 1个元素。
        // 如有10 个元素,获取逆序的第5个相当有获取正序的第6个元素
        int m = length - k + 1;
        int cn = 0;
        HeroNode heroNode = singleLinkedList.getHead();
        while (heroNode.next != null) {
            cn ++;
            if (cn == m) {
                return heroNode.next;
            }
            heroNode = heroNode.next;
        }
        return null;
    }
    
  3. 单链表的反转

    // 方法1,定义一个空的链表,遍历原来的链表
    public SingleLinkedList getReverseList(SingleLinkedList singleLinkedList) {
    
        // 获取老链表的头节点
        HeroNode headOld = singleLinkedList.getHead();
    
        // 获取到一个新的空链表
        SingleLinkedList newSingleList = new SingleLinkedList();
    
        // 遍历老链表
        while (headOld.next != null) {
            HeroNode heroNode = headOld.next;
            headOld.next = heroNode.next;
            heroNode.next = null;
    
            HeroNode newListHead = newSingleList.getHead(); // 新链表的头节点
            HeroNode temp = newListHead.next;
            newListHead.next = heroNode;
            heroNode.next = temp;
        }
        return newSingleList;
    }
    // 方法2,定义新的头节点
    public void getReverseList2(SingleLinkedList singleLinkedList) {
        // 定义一个新的头节点
        HeroNode newHead = new HeroNode(0, "", "");
        // 获取老链表的头节点
        HeroNode headOld = singleLinkedList.getHead();
    
        // 遍历老链表
        while (headOld.next != null) {
            HeroNode heroNode = headOld.next;
            headOld.next = heroNode.next;
    
            HeroNode temp = newHead.next;
            newHead.next = heroNode;
            heroNode.next = temp;
        }
        singleLinkedList.setHead(newHead);
    }
    
  4. 从尾到头打印单链表【方式1,反向遍历;方式2,Stack栈】

    /**
     * 借助 stack,逆序打印单链表
     * 1. 首先遍历链表,将每个元素入栈
     * 2. 遍历栈,打印每一个元素
     */
    public void printReverseLinkedList(SingleLinkedList singleLinkedList) {
    
        HeroNode head = singleLinkedList.getHead();
        Stack<HeroNode> stack = new Stack<>();
    
        HeroNode temp = head.next;
        while (temp != null) {
            stack.push(temp);
            temp = temp.next;
        }
    
        while (!stack.isEmpty()) {
            HeroNode pop = stack.pop();
            System.out.println(pop);
        }
    }
    
  5. 合并两个有序的单链表,合并之后的链表依然有序。

    /**
     * 合并两个链表,将两个有序链表,合并到第三个链表中。而保持合并后的链表依然有序。
     */
    public SingleLinkedList mergeTwoList(SingleLinkedList singleLinkedList1, SingleLinkedList singleLinkedList2) {
    
         HeroNode head1 = singleLinkedList1.getHead();
         HeroNode head2 = singleLinkedList2.getHead();
    
         SingleLinkedList singleLinkedList = new SingleLinkedList();
         HeroNode head = singleLinkedList.getHead();
         HeroNode temp = head;
    
         HeroNode temp1 = head1.next;
         HeroNode temp2 = head2.next;
    
         while (temp1 != null && temp2 != null) {
    
             if (temp1.no > temp2.no) {
                 temp.next = temp2;
                 temp2 = temp2.next;
             } else {
                 temp.next = temp1;
                 temp1 = temp1.next;
    
             }
             temp = temp.next;
         }
         if (temp1 == null) {
             temp.next = temp2;
         }
         if (temp2 == null) {
             temp.next = temp1;
         }
    
         return singleLinkedList;
     }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值