当前位置: 首页 > news >正文

算法练习(链表)

链表

链表的分类

  1. 单向链表,双向链表
  2. 带头链表,不带头链表
  3. 循环的,非循环的

链表的结构

在这里插入图片描述
图中所示的为链表的一个节点,value是这个节点的所存储的数据值,next为下一节点的地址。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码实现链表

1.创建节点类

节点由val域(数据域),以及next域(指针域)组成,对于next域,其是引用类型,存放下一个节点的地址,故

//ListNode代表一个节点
class ListNode{
    public int val;
    public ListNode next;
 
    //构造函数
    public ListNode(int a){
        this.val = a;
    }
}

用public ListNode next来创建next。
同时设置构造函数,方便对val进行初始化。

2.创建链表

方法一:枚举法(简单)
public class MyLinkedList {
    public ListNode head;//链表的头
    public void creatList(){
        ListNode listNode1 = new ListNode(11);
        ListNode listNode2 = new ListNode(22);
        ListNode listNode3 = new ListNode(33);
        ListNode listNode4 = new ListNode(44);
        ListNode listNode5 = new ListNode(55);
        this.head = listNode1;
        listNode1.next = listNode2;
        listNode2.next = listNode3;
        listNode3.next = listNode4;
        listNode4.next = listNode5;
    }
}

直接进行val的赋值以及对next的初始化。
注意:不用对最后一个节点的next进行赋值,因为next是引用类型,不赋值则默认为null。

方法二:头插法 public void addFirst(int data)

头插法是指在链表的头节点的位置插入一个新节点,定义一个node表示该节点,然后就是对node的next进行赋值,用node.next = this.head即可完成(注意:head应指向新节点)

public void addFirst(int data){
    ListNode node = new ListNode(data);
    node.next = this.head;
    this.head = node;
}
方法三:尾插法public void addLast(int data)

尾插法是指在链表的尾节点的位置插入一个新节点,定义一个node表示该节点,然后就是对原来最后一个节点的next进行赋值,先将head移动至原来最后一个节点,用head.next = node进行赋值(注意,如果链表不为空,需要定义cur来代替head)

public void addLast(int data){
    ListNode node = new ListNode(data);
    if(this.head == null){
       this.head = node;
    }else {
    	ListNode cur = this.head;
        while(cur.next != null){
            cur = cur.next;
        }
          cur.next = node;
    }
}

3.打印链表:public void display()

认识了链表的结构,可以知道,节点与节点之间通过next产生联系。已将创建了head,即头节点的地址,通过head的移动来实现链表的打印。
注意:为了使head一直存在且有意义,我们在display()函数中定义一个cur:ListNode cur = this.head;来替代head。
对于head的移动,可用head = head.next来实现。

public void display(){
   ListNode cur = this.head;
   while(cur != null){
       System.out.print(cur.val+" ");
       cur = cur.next;
   }
   System.out.println();
}

4.查找是否包含关键字key是否在单链表当中:public boolean contains(int key)

查找key,可以利用head移动,实现对于key的查找(注意:同样要定义一个cur来代替head)

public boolean contains(int key){
  ListNode cur = this.head;
  while(cur != null){
  if(cur.val == key){
      return true;
  }
  cur = cur.next;
  }
  return false;
}

5.得到单链表的长度:public int Size()

定义计数器count = 0,通过head的移动来判断链表长度(注意:同样要定义一个cur来代替head)

public int Size(){
   int count = 0;
   ListNode cur = this.head;
   while(cur != null){
       count++;
       cur = cur.next;
   }
   return count;
}

6.任意位置插入,第一个数据节点为0号下标:public boolean addIndex(int index,int data)

比如,把一个值为1314,地址是0x520(设为node引用)的节点,即val域值为1314,next域为null,地址是520,将该节点插入至3号位置
在这里插入图片描述经过分析,需要将head先移至2号位置(注意:用cur代替head,防止head丢失),然后
node.next = cur.next使该节点的next域改为下一节点的地址,再cur.next = node.next使前一节点的next域改为该节点的地址。

public void addIndex(int index,int data){
    if(index < 0 ||index > Size()){   //对index位置的合法性进行判断
        return;
    }
    if(index == 0){          //相当于头插法
        addFirst(data);
        return;
    }
    if(index = Size()){      //相当于尾插法
        addLast(data);
        return;
    }
    ListNode cur = findIndex(index);//找到index位置前一位置的地址
    ListNode node = new ListNode(data);//初始化node
    node.next = cur.next;
    cur.next = node;
}

7.删除第一次出现关键字为key的节点:public void remove(int key)

对于删除第一次出现的key值的节点,若不是头节点,我们只需将key值对应的节点的前一节点的next的域改为key值对应的节点的next域即可。
对于头节点,直接head = head.next即可。
对于key值对应的节点的前一节点,我们可以写一个函数来找到它,方便后续的代码书写。

//找到key的前驱(前一节点)
public ListNode searchPrev(int key){
ListNode cur = this.head;
while(cur.next != null){
    if(cur.next.val == key){
        return cur;
    }
    cur = cur.next;
}
return null;
}
//删除第一次出现关键字为key的节点
public void remove(int key){
    if(this.head == null){
        return;
    }
    if(this.head.val == key){
        this.head = this.head.next;
        return;
    }
    ListNode cur = searchPrev(key);
    if(cur == null){
        return;             //没有要删除的节点
    }
    ListNode del = cur.next;//定义要删除的节点
    cur.next = del.next;
}

8.删除所有值为key的节点:public void removeAllKey(int key)

若要删除所有值为key的节点,其实我们只需多次调用上面所写的remove函数即可完成,但是,
若要达到面试难度,那么要求就是遍历一遍链表,删除所有值为key的节点。
情况一:key连续,如下(1,2,3节点)
在这里插入图片描述
情况二:key不连续,如下(1,3节点)
在这里插入图片描述

public ListNode removeAllKey(int key){
if(this.head = null){
    return null;
}
ListNode prev = this.head;
ListNode cur = this.head.next;
while(cur != null){
    if(cur.val == key){
        prev.next = cur.next;
        cur = cur.next;
    }else {
        prev = cur;
        cur = cur.next;
    }
}
if(this.head.val == key){
    this.head = this.head.next;
}
return this.head;
}

9.清空链表:public void clear()

1.简单粗暴的方法:将头节点置为空head = null;即可
2.细腻温柔的做法:将每一个节点都置为空

public void clear(){
    while(this.head != null){
        ListNode curNext = this.head.next;
        this.head.next = null;
        this.head = curNext;
    }
}

相关文章:

  • linux——计算机内存详解通俗理解
  • 文本数据处理——最佳文本切分策略
  • 【开源免费】基于SpringBoot+Vue.JS电商应用系统(JAVA毕业设计)
  • 编程题《牛牛的链表删除》的python可以用非链表的方式
  • 射频前端模块(FEM)中的功率放大器(PA):关键作用与优化方法
  • 掌阅iReader全球首款 7 英寸 Carta 1300 墨水屏阅读器即将发布
  • 【TI MSPM0】GPIO学习
  • 五大基础算法——递归算法
  • AI软件栈:推理框架(二)-Llama CPP1
  • 软件需求分类、需求获取(高软46)
  • 【专栏预告】《VR 360°全景视频开发:从GoPro到Unity VR眼镜应用实战》
  • 量化交易学习笔记02:双均线策略
  • YOLO简史:从YOLOv1到YOLOv12的技术革新与演进
  • 类和对象C++ (未完:对象特征)
  • 一周学会Flask3 Python Web开发-SQLAlchemy更新数据操作-班级模块
  • 蓝桥模拟+真题讲解
  • MySQL -- 基本函数
  • vmware环境(vcenter许可证过期问题)
  • pytorch小记(八):pytorch中有关于.detach()的浅显见解
  • 暨南大学MEM复试资料
  • 江西望仙谷回应“游客凌晨等不到接驳车”:已限流,接驳车运行时间延长
  • 今年五一假期出游人群规模预计比去年提升8%,哪里最热门?
  • 人民日报社论:坚定信心、奋发有为、创新创造——写在“五一”国际劳动节
  • 国台办:民进党当局所谓“对等尊严”,就是企图改变两岸同属一中
  • 外媒称菲方允许菲官员窜台,国台办:应停止在台湾问题上玩火
  • 腾讯重构混元大模型研发体系:成立大语言和多模态模型部,提升AI长期技术作战能力