Java数据结构之链表的增删查改详解

论坛 期权论坛     
niminba   2021-5-26 12:32   3994   0
<h2>一、链表的概念和结构</h2>
<h3>1.1 链表的概念</h3>
<blockquote>
<p>简单来说链表是物理上不一定连续,但是逻辑上一定连续的一种数据结构</p>
</blockquote>
<h3>1.2 链表的分类</h3>
<blockquote>
<p>实际中链表的结构非常多样,以下情况组合起来就有8种链表结构. 单向和双向,带头和不带头,循环和非循环。排列组合和会有8种。<br>
但我这只是实现两种比较难的链表,理解之后其它6种就比较简单了<br>
1.单向不带头非循环链表<br>
2.双向不带头非循环链表</p>
</blockquote>
<h2>二、单向不带头非循环链表</h2>
<p style="text-align: center"><img alt="在这里插入图片描述" src="https://beijingoptbbs.oss-cn-hangzhou.aliyuncs.com/jb/2426819-95e058ca24812af348e05554215396bc.png"></p>
<h3>2.1 创建节点类型</h3>
<blockquote>
<p>我们创建了一个 ListNode 类为节点类型,里面有两个成员变量,val用来存储数值,next来存储下一个节点的地址。<br>
还有一个带一个参数的构造方法在实例化对象的同时给val赋值,因为我们不知道下一个节点的地址所以next是默认值一个null</p>
</blockquote>
<div class="blockcode">
<pre class="brush:java;">
class ListNode {
    public int val;//数值
    public ListNode next;//下一个节点的地址

    public ListNode(int val) {
        this.val = val;
    }
}</pre>
</div>
<p>我们在 MyLinkedList 里创建一个head变量来标识链表的头部,接着就是实现单链表的增删查改了</p>
<p style="text-align: center"><img alt="在这里插入图片描述" src="https://beijingoptbbs.oss-cn-hangzhou.aliyuncs.com/jb/2426819-7bb308634e67d5e4329068646578fcf2.png"></p>
<h3>2.2 头插法</h3>
<p style="text-align: left">这个头插法并不要考虑第一次插入,每次插入只需要把插入的节点node 的next值改成头节点,再把头节点指向node</p>
<p style="text-align: center"><img alt="在这里插入图片描述" src="https://beijingoptbbs.oss-cn-hangzhou.aliyuncs.com/jb/2426819-55307037f371dd3b5f3b088197b938ae.png"></p>
<div class="blockcode">
<pre class="brush:java;">
//头插法
public void addFirst(int data) {
    ListNode node = new ListNode(data);
    node.next = this.head;
    this.head = node;
}</pre>
</div>
<h3>2.3 尾插法</h3>
<blockquote>
<p>尾插法首先要考虑是不是第一次插入,如果是的话直接把head指向node就好了,如果不是第一次插入,则需要定义一个cur来找尾巴节点,把尾巴节点的next值改成node就好了。因为如果不用尾巴节点的话,head就无法标识到头部了</p>
</blockquote>
<p style="text-align: center"><img alt="在这里插入图片描述" src="https://beijingoptbbs.oss-cn-hangzhou.aliyuncs.com/jb/2426819-7422fdb1da3687df49a8b46faadf79c2.png"></p>
<div class="blockcode">
<pre class="brush:java;">
//尾插法
public void addLast(int data) {
    ListNode node = new ListNode(data);
    ListNode cur = this.head;
    //第一次插入
    if(this.head == null) {
        this.head = node;
    }else{
        while (cur.next != null) {
            cur = cur.next;
        }
        cur.next = node;
    }
}
</pre>
</div>
<h3>2.4 获取链表长度</h3>
<blockquote>
<p>定义一个计数器count,当cur遍历完链表的时候直接返回count就好</p>
</blockquote>
<div class="blockcode">
<pre class="brush:java;">
//得到单链表的长度
public int size() {
    int count = 0;
    ListNode cur = this.head;
    while (cur != null) {
        cur = cur.next;
        count++;
    }
    return count;
}
</pre>
</div>
<h3>2.5 任意位置插入</h3>
<blockquote>
<p>我们假设链表的头是从0位置开始的,任意位置插入需要考虑几点<br>
1.位置的合法性,如果位置小于0,或者大于链表长度则位置不合法<br>
2.如果要插入的是0位置直接使用头插法<br>
3.如果插入的位置等于链表长度则使用尾插法,因为我们这链表是从0开始的</p>
</blockquote>
<p>最关键的就是从中间任意位置插入 要从中间位置插入,就需要找到要插入位置的前一个节点的位置。再插入到它们中间。</p>
<p style="text-align: center"><img alt="在这里插入图片描述" src="https://beijingoptbbs.oss-cn-hangzhou.aliyuncs.com/jb/2426819-60b15d3e2aa5b1c3b04f331b33e964b9.png"></p>
<div class="blockcode">
<pre class="brush:java;">
  /**
     * 让 cur 向后走 index - 1 步
     * @param index
     * @return
     */
public ListNode findIndexSubOne(int index) {
    int count = 0;
    ListNode cur = this.head;
    while (count != index-1) {
        cur = cur.next;
        count++;
    }
    return  cur;
}
//任意位置插入,第一个数据节点为0号下标
public void addIndex(int index,int data) {
    //判断合法性
    if(index &lt; 0 || index &gt; size()) {
            System.out.println("index位置不合法");
            return;
    }
    //头插法
    if(index == 0) {
        this.addFirst(data);
        return;
    }
    //尾插法
    if(index == size()) {
        this.addLast(data);
        return;
    }
    //找前驱,cur指向的是 index 的前一个节点
    ListNode cur = findIndexSubOne(index);
    ListNode node = new ListNode(data);
    node.next = cur.next;
    cur.next
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1060120
帖子:212021
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP