6.单链表

1.链表介绍

image.png
  • 链表是以节点的方式存储元素的,是链式存储的
  • 每个节点包含data域和next域,data域用来存放数据,next域用来指向下一个节点
  • 如图,链表中的节点不一定是连续存储的
  • 链表可以分为带头节点和不带头节点的,可以按需求来确定

2.应用实例:给水浒好汉排序

1)完成对人物的增删改查
2)第一种方式:直接将英雄插入到链表末尾
3)第二种方式:将英雄按照排名插入到链表中


image.png

3.思路分析

将元素直接插入到链表末尾

添加:
1.先新建一个head头节点,作用就是表示单链表的头
2.后面每添加一个节点,就直接加入到链表的最后
遍历:
通过一个辅助变量帮助遍历整个链表。
问:为什么需要一个辅助变量?
答:这是因为头节点不能动。

将元素按照编号顺序插入链表

image.png

添加:
1.借助一个辅助变量找到新的元素所在的位置
2.新的节点.next = temp.next
3.temp.next = 新的节点

4.代码实现

package com.yc.day01.linkedlist;

public class SingleListTest {
    public static void main(String[] args) {
        HeroNode h1 = new HeroNode(1, "宋江", "及时雨");
        HeroNode h2 = new HeroNode(2, "卢俊义", "玉麒麟");
        HeroNode h3 = new HeroNode(3, "吴用", "智多星");
        SingleList singleList = new SingleList();
        singleList.add(h1);
        singleList.add(h2);
        singleList.add(h3);
        singleList.print();
    }
}
class SingleList{
    //初始化一个头节点,头节点不要动,不存放数据
    private HeroNode head = new HeroNode(0,"","");
    //新增节点
    public void add(HeroNode heroNode){
        HeroNode temp = head;
        while (true){
            //最后一个节点
            if(temp.next==null){
                break;
            }
            //如果不是最后一个节点,temp指向当前节点的下一个节点
            temp = temp.next;
        }
        //退出循环后表示找到最后一个节点
        temp.next = heroNode;
    }
    //显示链表
    public void print(){
        //因为头节点不能动,所以需要辅助变量temp
        HeroNode temp = head.next;
        //遍历输出
        while (true){
            if(temp==null){
                break;
            }
            System.out.println(temp);
            temp = temp.next;
        }
    }

}
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;
    }

    public HeroNode() {
    }

    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nickName='" + nickName + '\'' +
                '}';
    }
}

按照顺序添加元素

  public void addByOrder(HeroNode heroNode){
        //因为头节点不能动,所以需要一个辅助变量去找新节点的位置
        HeroNode temp = 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;
        }
        //循环退出说明已经找到新节点要插入的位置
        if(flag){
            System.out.printf("要插入的英雄编号%d已存在\n",heroNode.no);
        }else {
            heroNode.next = temp.next;
            temp.next = heroNode;
        }
    }

修改

public void update(HeroNode heroNode){
        HeroNode temp = head.next;
        boolean flag = false;//标志是否存在指定节点
        while (true){
            if(temp==null){
                break;
            }
            if(temp.no==heroNode.no){
                flag = true;
                break;
            }
            //指向下一个节点
            temp = temp.next;
        }
        //退出循环表示找到指定节点
        if(flag){
            temp.name = heroNode.name;
            temp.nickName = heroNode.nickName;
        }else {
            System.out.printf("编号为%d的节点不存在\n",heroNode.no);
        }
    }

删除

思路分析:
1)通过辅助变量temp遍历找到要删除的指定节点
2)删除操作:temp.next = temp.next.next;

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;
        }
        if(flag){
            temp.next = temp.next.next;
        }else{
            System.out.printf("编号为%d的节点不存在",no);
        }
    }

问:什么时候将temp初始化为head,而什么时候又将temp初始化为head.next?
答:当需要找到指定元素的前一个节点时就初始化为head,否则为head.next。比如说插入和删除都需要找到指定元素的前一个元素,所以初始化为head。而打印和修改只需要找到指定元素就可以了,所以初始化为head.next

5.面试题

5.1单链表中有效节点个数(不包括头节点)
    /**
     * 获取有效节点个数
     * */
    public int length(){
        HeroNode temp = head;
        int count = 0;
        while (true){
            if(temp.next==null){
                break;
            }
            temp = temp.next;
            count++;
        }
        return count;
    }
5.2获取单链表中倒数第n个节点
 /**
     * 获取链表中倒数第n个节点
     * */
    public HeroNode getTargetIndexNode(int index){
        HeroNode temp = head.next;
        int length = length();
        if(index<=0||index>length){
            return null;
        }
        for (int i=0;i<length-index;i++){
            temp = temp.next;
        }
        return temp;
    }
5.3单链表反转
 /**
     * 单链表反转
     * */
    public void reverse(){
        HeroNode temp = head.next;
        //链表为空或者只有一个元素时,不用做操作
        if(temp==null||temp.next==null){
            return;
        }
        HeroNode reverseHead = new HeroNode(0,"","");
        HeroNode next = null;
        while(temp!=null){
            next = temp.next;
            temp.next = reverseHead.next;//把reverseHead这条链表中当前元素和它的下一个元素连接起来
            reverseHead.next = temp;
            temp = next;
        }
        head.next = reverseHead.next;
    }

解释下代码

while(temp!=null){
         next = temp.next;
         temp.next = reverseHead.next;//把reverseHead这条链表中当前元素和它的下一个元素连接起来
         reverseHead.next = temp;
         temp = next;
     }

第一次进入循环时,执行前两步:temp为宋江,next为卢俊义,reverseHead.next为null,所以temo.next也为null
第二次进入循环时,执行前两步:temp为卢俊义,next为吴用,reverseHead.next为宋江,temo.next也为宋江,此时就将卢俊义和宋江连起来了

5.4逆序打印单链表

利用栈先进后出的特点

  /**
     * 逆序打印单链表
     * */
    public void reversePrint(){
        HeroNode temp = head.next;
        if(temp==null){
            return;
        }
        Stack<HeroNode> heroNodes = new Stack<HeroNode>();
        while (temp!=null){
            heroNodes.push(temp);
            temp = temp.next;
        }
        while (heroNodes.size()>0){
            System.out.println(heroNodes.pop());
        }
    }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,919评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,567评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,316评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,294评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,318评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,245评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,120评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,964评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,376评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,592评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,764评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,460评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,070评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,697评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,846评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,819评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,665评论 2 354

推荐阅读更多精彩内容