数据结构与算法——day02

会有一股神秘感。 提交于 2019-12-16 04:54:55

前言

今天大致了解了链表的基本概念,然后着重学习了单链表的增删改查、统计单链表的有效节点数和按序查找单链表的节点。由于时间原因,还要复习考试,并且这次学习的也是比较多啦,所以剩余的单链表的三个方法就明天再学之后再加上一个补充。综合来看这次的学习代码比较多,知识概念比较少。OK,切入正题!

何为链表?

链表是有序的列表

在内存中存储如下:

  1. 链表是以节点的方式来存储,是链式存储
  2. 每个节点包含data 域, next 域:指向下一个节点.两域
  3. 链表的各个节点不一定是连续存储.
  4. 链表分带头节点的链表没有头节点的链表,根据实际的需求来确
文字很抽象?

来张单链表的存储图瞅瞅(原来我以为一直很好奇链式的代码要怎么写,用了java才知道是用类定义的,就有一种恍然大悟的感觉)

简单的概念介绍之后就是应用实例的代码编写,好,进入正文!

正文

应用实例是对于带头结点的英雄节点的单链表进行如下操作:

  • 增加(分两种,一种是简单的来一个添加一个,第二种就是按no编号按顺序的添加)
  • 删除(简单的删除节点操作)
  • 修改(根据英雄的no修改英雄的信息)
  • 查询(直接显示所有的英雄信息)
  • 统计单链表中所有有效节点的个数(不包括头节点)
  • 按index查找倒数第k个节点

最开始我是很好奇,为什么要用单链表实现?(不知道你们有没有这样的好奇)

其实单链表实现的方式不需要连接数据库等进行操作,所以直接在内存中进行操作,速度比较快。

为了实现以上的功能,需要建立三个类,编写若干方法,详见如下:
在这里插入图片描述

1、HeroNode类

该类主要是定义一些属性即英雄所含的信息,重要的是next属性,是指向下一个节点的属性。代码中的注释也比较详细。

//定义一个HeroNode,每一个HeroNode对象就是一个aa节点
class HeroNode{
    public int no;//编号
    public String name;//英雄的姓名
    public String nickname;//英雄的昵称
    public HeroNode next;//指向下一个节点
    //构造器
    public HeroNode(int hNo,String hName,String hNickname){
        this.no=hNo;
        this.name=hName;
        this.nickname=hNickname;
    }
    //为了显示方便,重写toString方法

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

2、SingleLinkedList类

最为重要的单链表类,其中包含操作的所有方法,下面为有些比较不同的方法的实现原因和代码,删除和修改比较简单就不单独列出啦。

(1)添加节点到单向链表的add()方法

实现思路:

  • 找到当前链表的最后节点
  • 将最后这个节点的next指向新的节点
public void add(HeroNode heroNode){
    //因为head节点不能动,因此我们需要一个辅助遍历temp
    HeroNode temp=head;
    while (true){
        //找到链表的最后一个节点
        if(temp.next==null){
            break;
        }
        //如果没有找到就将temp后移
        temp=temp.next;
    }
    //当退出while循环时,temp就指向了链表的最后
    //将最后这个节点的next指向新的节点
    temp.next=heroNode;
}

(2)顺序添加的addByOrder()方法

多增加了一个判断,当待添加节点的编号小于一个节点时,就将待添加节点添加在该节点的前面。

public void addByOrder(HeroNode heroNode){
        //因为头节点不能动,因此我们仍然通过辅助变量temp帮助找到添加的位置;
        //因为是单链表,因此我们找到的temp是位于添加位置的前一个节点,否则加入不了
        HeroNode temp=head;
        boolean flag=false;//标志添加的编号是否存在,默认为false
        while(true){
            if(temp.next==null){//说明已在链表的最后
                break;
            }
            if(temp.next.no>heroNode.no){
                break;
            }else if(temp.next.no==heroNode.no){//说明希望添加的HeroNode的编号已然存在
                flag=true;//说明编号存在
            }
            temp=temp.next;//后移就相当与在遍历当前链表
        }
        //判断flag的值
        if (flag){
            System.out.printf("准备插入的英雄的编号%d已经存在了不能插入!\n",heroNode.no);
        }else{
            //插入到链表中,temp的后面
            heroNode.next=temp.next;
            temp.next=heroNode;
        }
    }

(3)查询所有节点信息的list()方法

这个要注意的是判断是否为空的情况以及建立辅助变量.

//显示链表(遍历)
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=temp.next;
    }
}

(4)统计单链表中所有有效节点的个数

/**
 *
 * @param head 链表的头节点
 * @return返回的就是有效节点的个数
 */
public static int getLength(HeroNode head){
    if (head.next==null){
        return 0; }
    int length=0;
    //定义一个辅助的变量,这里我们没有统计头节点
    HeroNode cur=head.next;
    while(cur!=null){
        length++;
        cur=cur.next;
    }
    return length;
}

(5)按index查找倒数第k个节点

/**
 * 查找单链表中的倒数第k个结点
 * 思路
 * 1、编写一个方法接受head节点,同时接受一个index
 * 2、index表示是倒数index个节点
 * 3、先把链表从头到尾遍历,得到链表的总得长度getLength()
 * 4、得到siz后,从链表的第一个遍历,遍历(size-index)个,就可以得到
 *5、如果找到则返回该节点,否则返回为空
 */
public static HeroNode findLastIndexNode(HeroNode head,int index){
    //判断如果链表为空,返回null
    if (head.next==null)
        return null;//没有找到
    //第一次遍历得到链表节点的个数
    int size=getLength(head);
    //第二次遍历,遍历到(size-index)个,就是目标节点
    //先做一个index的校验
    if (index<=0||index>size){
        return null;
    }
    //定义一个辅助变量,for循环定位
    HeroNode cur=head.next;
    for (int i=0;i<size-index;i++){
        cur=cur.next;
    }
    return cur;
}

3、SingleLinkedListDemo类

用于测试操作的功能:

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.addByOrder(hero1);
      singleLinkedList.addByOrder(hero4);
      singleLinkedList.addByOrder(hero2);
      singleLinkedList.addByOrder(hero3);
      System.out.println("修改前:");
      //显示
      singleLinkedList.list();

      //测试修改的代码
      HeroNode newHeroNode=new HeroNode(2,"小卢","玉麒麟**");
      singleLinkedList.update(newHeroNode);
      System.out.println("修改后:");
      //显示
      singleLinkedList.list();
      //删除一个节点
      singleLinkedList.del(1);
      singleLinkedList.del(4);
      System.out.println("删除后");
      singleLinkedList.list();
      //测试一个单链表有效节点的个数
      System.out.println(getLength(singleLinkedList.getHead()));
     //测试是否得到倒数第K个节点
      HeroNode res=findLastIndexNode(singleLinkedList.getHead(),3);
      System.out.println("res="+res);
  }
}

完整代码:由于完整代码较多我就把代码的放在码云上了,有兴趣的可以看一下:

链接:https://gitee.com/lumengli/DataStructure/blob/master/day02

运行效果如下:
在这里插入图片描述

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!