IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 链表 -> 正文阅读

[数据结构与算法]链表

一:单向链表

?链表是一个一个元素的添加的

?

每一个节点都是用到时 才会进行分配内存空间

?由于动态数组和链表中? 接口方法是相同的但是实现的代码是不一样的

因此我们定义一个接口List

实现这个接口的每一个类都应该实现这个接口中的所有方法

?插播一条Java语法的问题:

我们的动态数组ArrayList和链表LinkedList都是实现于List的

因此我们可以用类似于多态的形式进行new

?接口设计:

?

clear:

next不需要设置为null

因为当size==0时? 第一个节点消失死亡 跟着的后面节点一个一个也跟着死亡消失?

add:

步骤:找到要添加到位置的前一个元素

让添加的元素的next指向1处的22

让0处的next指向添加元素的44?

1. 找到对应索引下标的节点node

?2.获取某个节点处的元素值

?3.add

先找到要添加位置的前一个位置

之后再进行new出来一个新的节点

但是如果增加到0下标处时

我们需要改正? 改正如下:

我们需要让头节点的指向也就是这里的first指向重新定义

?

如果增加到最后一个位置时? 但是这种情况可以被第二种添加方式所包含

?

?删除:

?获取前面一个元素??

让前面一个next的指向? 指向下一个位置

?这里的first也就是链表头节点的first

?练习题1:

?

思路:

1.首先用要被删除元素的元素的值进行覆盖 node.val=node.next.val;

2.再用要被删除元素的前一个结点的next指向node.next.next

node.next=node.next.next;

?

练习题2:

反转:

方法一:递归方法

举个例子:
当我们函数传参传递的是4时 那么反转之后的链表形式如图?:

?

?

?

?

?习题3:

package 链表动态数组.链表.单链表;

import 链表动态数组.链表.双向链表.双向链表;

public class LinkedList<E> extends 双向链表<E>{
    /**
     * 清除所有元素
     */
    public void clear(){
        size=0;         
        first=null;
    }
    /**
     * 元素的数量
     */
    public int size() {
        return size;
    }
    /**
     * 判断是否为空
     */
    public boolean isEmpty(){
        return size==0;
    }
    /**
     * 判断是否包含某个元素
     */
    public boolean contains(E elements){
        双向链表.Node node=first;
        for (int i = 0; i < size; i++) {
            if(node.element==elements){
                return true;
            }
            node=node.next;
        }
        return false;
    }
    /**
     * 添加元素到尾部
     */
    public void add(int index,E element) {
        if(index==0){
            first=new 双向链表.Node<>(element,first);
        } else {
            双向链表.Node<E> prev=node(index-1);
            prev.next=new 双向链表.Node<>(element,prev.next);
        }
        size++;
    }

    /**
     *找到某一位置的节点并且返回
     */
    private 双向链表.Node<E> node(int index){
        双向链表.Node<E> node=first;
        for (int i = 0; i <index; i++) {
            node=node.next;
        }
        return node;
    }
    /**
     * 获取index位置的元素
     */
    public E get(int index) {
        return node(index).element;
    }
    /**
     * 设置index位置的元素
     */
    public E set(int index,E element){
        双向链表.Node<E> node=node(index);
        E old=node.element;
        node.element=element;
        return old;//返回原来的元素值
    }
 /*   *//**
     * 在index插入一个元素
     *//*
    public void add(int index,E elememt) {

    }*/
    /**
     * 删除index位置的元素
     */
    public E remove(int index){
        双向链表.Node<E> node=first;
        if(index==0){
            first=first.next;
        } else {
            双向链表.Node<E> prev=node(index-1);//找到前驱
            node=prev.next;//对node重新赋值哦
            prev.next=node.next;//进行删除
        }
        size--;
        return node.element;//把这个被删除的节点的元素值进行返回
    }
    /**
     * 查看元素的索引
     */
    public int indexOf(E element){
        if(element==null){
            双向链表.Node<E> node=first;
            for (int i = 0; i <size; i++) {
                if(node.element==null){
                    return i;
                }
                node= ((Node<E>) node).next;
            }
        } else {
            双向链表.Node<E> node=first;
            for (int i = 0; i <size; i++) {
                if(node.element.equals(element)){
                    return i;
                }
                node=node.next;
            }
        }
        return ELEMENT_NOT_FOUND;
    }
}

?注意:

环形链表用快慢指针? 快慢指针初始指向位置是不同的

动态数组缩容操作:

?缩容和扩容差不多思想:把原来的元素移到新搞出来的数组内存

?二:双向链表

?找到对应index下标的节点node

因为这个节点node具有双指向性

next和prev指向 因此利用对称来找出对应索引处的节点

这样分一半一半的找

提高了效率

?

?clear:

当我们把LinkedList对象的两条线去掉以后

整个节点数组都会死掉

虽然说仍然有引用互相进行指向

但这些节点已经丧失了gc root对象的指向

JVM宣布他们这些节点全部死掉

那么作用之后只剩下:

?

?双向链表add:

first只关注第一个节点元素

last只关注最后一个节点元素?

?

?但如果最开始什么都没有:

last==null

?只有一个

  /**
     * 在index插入一个元素
     */
    public void addindex(int index,E elememt) {
        if (index < 0 || index > size) {
            return;
        }
        if (index == size) {
            Node oldlast=last;
            Node leo=new Node(element,oldlast,null);
            last=leo;
            if(oldlast==null){//当只有一个元素的时候first last都指向这个节点
                last=leo;
             first=leo;
            } else {
                oldlast.next=last;
            }
        } else {
            Node next = node(index);//找到要添加位置的节点
            Node prev = next.prev;//要添加的节点的上一个
            Node node = new Node(element, prev, next);
            next.prev = node;
            if (next.prev == null) {//index==0
                first = node;
            } else {
                prev.next = node;
            }
        }

?删除:

  /**
     * 删除index位置的元素
     */
    public void remove(int index){
        Node<E> node=node(index);
        Node<E> prev=node.prev;//这里的prev next就相当于一个节点了吧
        Node<E> next=node.next;
        if(prev==null){
            first=next;
        } else {
            prev.next=next;
        }
        if(next==null){
            last=prev;
        } else {
            next.prev=prev;
        }
    }

双向链表总代码:

package 链表动态数组.链表.双向链表;

import 链表动态数组.链表.单链表.leo;

public class 双向链表<E> extends leo<E> {
    //元素的数量
    protected int size;
    protected static final int ELEMENT_NOT_FOUND=-1;
    protected Node<E> first;
    private   Node<E> last;
    /**
     *内部类定义一个Node类
     */
 public static class Node<E>{
     public E element;
     Node<E> prev;
     public Node<E> next;
     public Node(E element, Node<E> prev, Node<E> next) {
         this.element = element;
         this.prev = prev;
         this.next = next;
     }
 }
    /**
     * 清除所有元素
     */
    public void clear(){
        size=0;
        first=null;
        last=null;
    }
    /**
     * 元素的数量
     */
    public int size() {
        return size;
    }
    /**
     * 判断是否为空
     */
    public boolean isEmpty(){
        return size==0;
    }
    /**
     * 判断是否包含某个元素
     */
    public boolean contains(E elements){
        Node node=first;
        for (int i = 0; i < size; i++) {
            if(node.element==elements){
                return true;
            }
            node=node.next;
        }
        return false;
    }
    /**
     *找到某一位置的节点并且返回
     * 双向链表利用对称性 大大提高了查找速率
     */
    private Node<E> node(int index){
        if(index<0||index>size){
            return null;
        }
        //当在左半边的时候
        if(index<(size>>1)){
            Node<E> node=first;
            for (int i = 0; i <index; i++) {
                node=node.next;
            }
            return node;
        } else {  //当在右半边的时候
            Node<E> node=last;
            for (int i =size-1; i <index; i++) {
                node=node.prev;
            }
            return node;
        }
    }
    /**
     * 获取index位置的元素
     */
    public E get(int index) {
       return node(index).element;
    }
    /**
     * 设置index位置的元素
     */
    public E set(int index,E element){
      Node<E> node=node(index);
      E old=node.element;
      node.element=element;
      return old;//返回原来的元素值
    }
    /**
     * 在index插入一个元素
     */
    public void addindex(int index,E elememt) {
        if (index < 0 || index > size) {
            return;
        }
        if (index == size) {
            Node oldlast=last;
            Node leo=new Node(element,oldlast,null);
            last=leo;
            if(oldlast==null){//当只有一个元素的时候first last都指向这个节点
                last=leo;
             first=leo;
            } else {
                oldlast.next=last;
            }
        } else {
            Node next = node(index);//找到要添加位置的节点
            Node prev = next.prev;//要添加的节点的上一个
            Node node = new Node(element, prev, next);
            next.prev = node;
            if (next.prev == null) {//index==0
                first = node;
            } else {
                prev.next = node;
            }
        }
    }
    /**
     * 删除index位置的元素
     */
    public void remove(int index){
        Node<E> node=node(index);
        Node<E> prev=node.prev;
        Node<E> next=node.next;
        if(prev==null){
            first=node;
        } else {
           prev.next=next;
        }
        if(next==null){
            last=node;
        } else {
            next.prev=prev;
        }
    }
    /**
     * 查看元素的索引
     */
    public int indexOf(E element){
        if(element==null){
            Node<E> node=first;
            for (int i = 0; i <size; i++) {
                if(node.element==null){
                    return i;
                }
                node=node.next;
            }
        } else {
            Node<E> node=first;
            for (int i = 0; i <size; i++) {
                if(node.element.equals(element)){
                    return i;
                }
                node=node.next;
            }
        }
        return ELEMENT_NOT_FOUND;
    }

}

?单向循环链表:这是单链表

?当什么都没有 第一次添加节点的时候

?

?删除:

?特殊情况:只有一个节点·

package 链表动态数组.链表.单链表;
//循环链表与单链表的不同之处就在于add和remove
public class 单向循环链表<E> extends 单链表<E> {
    @Override
    public void addindex(int index, Object elememt) {
        if(index<0||index>size){
            return;
        }
        if(index==0){
            Node node=new Node(elememt,first);
            first=node;
            //找到最后一个节点
            Node last=node(index-1);
            last.next=first;//循环链表的规定
        } else {
           Node<E> prev=node(index-1);
           Node node=new Node(elememt,prev.next);
           prev.next=node;
        }
    }
    @Override
    public E remove2(int index) {
        if(index<0||index>size){
            return null;
        }
        if(index==0){
            if(size==1){
              first=null;
            } else {
                Node<E> last=node(index-1);
                Node<E> node=new Node<>(last.element,first.next);
                last=node;
            }
        } else {
            Node prev=node(index-1);
            Node node=prev.next;
            prev.next=node.next;
        }
        size--;
        return null;
    }
}

?双向循环链表:

?

?

?双向循环链表remove:

但是当链表原来只有一个节点的时候

上面代码应当修改:?

?

代码:

package 链表动态数组.链表.双向链表;
//循环链表与单链表的不同之处就在于add和remove
public class 双向循环链表<E> extends 双向链表<E> {
    @Override
    public void addindex(int index, Object elememt) {
        if(index==size){
            Node oldlast=last;
            Node<E> node=new Node<E>((E)elememt,oldlast,first);
            if(oldlast==null){
                first=last;
                first.prev=first;
                first.next=first;
            } else {
                oldlast.next=node;
                first.prev=node;
            }
        } else {
            Node<E> next=node(index);
            Node<E> prev=next.prev;
            Node<E> node=new Node<E>((E) elememt,prev,next);
            next.prev=node;
            if(prev==null){//证明index==0
               first=node;
            } else {
                prev.next=node;
            }
        }
        size++;
    }

    @Override
    public void remove(int index) {
        if (index < 0 || index > size) {
            return;
        }
        Node<E> node = first;
        if (size == 1) {
            first = null;
            last = null;
        } else {
            node = node(index);
            Node prev = node.prev;
            Node next = node.next;
            prev.next = next;
            next.prev = prev;
            if(node==first){//index==0
                first=next;
            }
            if(node==last){//index==size-1
                last=prev;
            }
        }
    }
}

?

?1.

2.

?

?

?3.封装一个remove方法直接删除传进来的节点

?4.运行测试:

?

?

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-12-02 17:01:12  更:2021-12-02 17:02:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 14:33:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码