单链表

单链表

在这里插入图片描述

  • 链表依然属于线性结构.只不过它不像数组那样在内存中是连续存储的.它在内存中并不一定是连续存放的.
  • 单链表就是一个结点指向下一个节点.
  • 节点包含了存放数据的域.和指向下一个节点的域.
  • 这个域也可以理解为变量.只是我看那是一块一块的区域.
  • 节点类,这个类我单独抽离出来了.其实他是在整个单链表类里面的一个静态内部类.只服务于单链表类.所以作为一个静态内部类比较合适.
这里普及一下嵌套类的概念以及应用场景:定义在一个类内部的类,它的存在仅仅只是为了他的外围类提供服务.
否则如果该嵌套类会用于其他的某个环境中,它应该是顶层类.
如果声明的成员类不要求访问外部类的实例,就要始终将它定义为静态static的.
如果声明的是非静态的内部类.那么每个内部类的实例中都将会包含一个额外的指向外围对象的引用.保存这份引用需要消耗时间和空间,并且会导致外围实例在符合垃圾回收时却任然得以保留.由此而造成的内存泄露常常难以发现.因为这个额外的引用并不常见.
至于为何是私有的.因为这个Node是作为单链表类的一个组件.并不需要外部访问.我们只在内部进行访问.
所以最后应该是私有的静态成员类
	/**
     * Node Class.
     */
    private static class Node<E>{

        E item;

        /**
         * Point to next node.
         */
        private Node<E> next;

        Node(E element, Node<E> next) {
            this.item = element;
            this.next = next;
        }
    }

操作

常见的增删改查,这里直接上代码了.整体是仿照LinkedList的源码来写的.看懂这个,其实LinkedList源码.你也是看了一部分的.这里你要耐心的一点一点捋.其实并不难.

package name.dancer.linkedlist;

import java.util.NoSuchElementException;

/**
 * @author dancer
 * @date 2019-09-26
 * @see java.util.LinkedList
 **/
@SuppressWarnings("unused")
public class SingleLinkedList<E>{

    private int size = 0;

    /**
     * Pointer to first node.
     */
    private Node<E> first;

    /**
     * Point to last node.
     */
    private Node<E> last;


    public boolean add(E e) {
        linkLast(e);
        return true;
    }

    /**
     * Links e as last element.
     */
    private void linkLast(E e) {
        // 保存尾节点的状态
        Node<E> l = last;
        // 将当前元素.组装为一个Node节点
        Node<E> newNode = new Node<>(e, null);
        // 为尾节点last赋新值(要添加的节点)
        last = newNode;
        // 如果fist为null,将当前节点赋值给头节点
        if (null == first) {
            first = newNode;
        } else {
            /*
             * 将原头节点l. 的下一个节点指向当前新的头节点;
             * 思考一个问题:
             *      为什么JDK不用l.next = last.
             *      而是用l.next = newNode.
             */
            l.next = newNode;
            // l.next = last;
        }
        size++;
    }

    /**
     * Inserts element e before non-null Node succ.
     */
    private void linkBefore(E e, Node<E> succ) {
        if (null == succ) {
            Node<E> next = first;
            first = new Node<>(e, next);
        } else {
            Node<E> next = succ.next;
            succ.next = new Node<>(e, next);
        }
        size++;
    }

    /**
     * Before returns the Node as specified element index
     */
    private Node<E> node(int index) {
        if (index == 0) {
            return null;
        }
        Node<E> x = first;
        for(int i = 0, end = index - 1; i < end; i++) {
            x = x.next;
        }
        return x;
    }

    /**
     * Inserts the specified element at the specified position in this list.
     */
    public void add(int index, E element) {
        // 判断添加的位置是否越界
        checkElementIndex(index);

        // 等于size添加到链表尾
        if (index == size) {
            linkLast(element);
        // 添加到指定索引位置
        } else {
            linkBefore(element, node(index));
        }
    }

    private void checkElementIndex(int index) {
        if (! (index >= 0 && index <= size)) {
            throw new IndexOutOfBoundsException("Index: "+index+",Size: "+size);
        }
    }

    /**
     * Replaces the element at the specified position in this list with the specified element.
     */
    public E set(int index, E element) {
        checkElementIndex(index);
        Node<E> x= node(index);
        if (null == x) {
            E oldVal = first.item;
            first.item = element;
            return oldVal;
        }
        E oldVal = x.next.item;
        x.next.item = element;
        return oldVal;
    }

    public E remove() {
        return removeFirst();
    }

    private E removeFirst() {
        Node<E> f = first;
        if (null == f) {
            throw new NoSuchElementException();
        }
        return unlinkFirst(f);
    }

    private E unlinkFirst(Node<E> f) {
        E element = f.item;
        Node<E> next = f.next;
        f.item = null;
        f.next = null;
        first = next;
        if (null == next) {
            last = null;
        }
        size--;
        return element;
    }

    /**
     * Return all nodes as Array
     */
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        if (a.length < size) {
            // 构建指定类型和大小的数组集合
            a = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
        }
        int i = 0;
        Object[] result = a;
        for (Node<E> x = first; x != null; x = x.next) {
            result[i++] = x.item;
        }
        // 如果传递过来的集合大小大于原本的长度.将索引size作为一个隔离层,隔离层之外的是读取不到的;
        if (a.length > size) {
            a[size] = null;
        }
        return a;
    }

    /**
     * Returns the number of elements in this list
     */
    public int size() {
        return size;
    }

    /**
     * Node Class.
     */
    private static class Node<E>{

        E item;

        /**
         * Point to next node.
         */
        private Node<E> next;

        Node(E element, Node<E> next) {
            this.item = element;
            this.next = next;
        }
    }
}

测试

package name.dancer.linkedlist;

/**
 * 单链表
 * @author dancer
 * @date 2019-08-30
 **/
public class SingleLinkedListDemo {
    public static void main(String[] args) {
        SingleLinkedList<Object> linkedList = new SingleLinkedList<>();
        linkedList.add("1");
        linkedList.add("2");
        linkedList.add("3");
        linkedList.add(0,"0");
        linkedList.set(3, "100");
        linkedList.remove();
        linkedList.remove();
        linkedList.remove();
        linkedList.add(0,"0");
        linkedList.add("3");
        String[] strings = linkedList.toArray(new String[linkedList.size()]);
        for (String string : strings) {
            System.out.println(string);
        }
    }
}

在这里插入图片描述

面试题

求单链表中有效节点的个数

如果是带头结点的链表,不统计头结点
遍历所有的有效节点即可

/**
 * Returns the number of elements in this list
 */
public int size() {
    return size;
}
查找链表中倒数第K个节点(新浪)

正数第size-k个节点

/**
 * 查找单链表中倒数第index个节点
 */
public Node<E> reverserNode(int index) {
    checkElementIndex(index);
    Node<E> x = first;
    for(int i = 0, v = size - index; i < v ; i++) {
        x = x.next;
    }
    return x;
}
单链表的反转(腾讯)

在这里插入图片描述

从尾到头打印单链表(百度)
  1. 反转单链表,打印.这样做会破坏原来单链表的结构
  2. 利用栈,将各个结点压入到栈中.利用栈的先进后出,实现逆序打印java.util.Stack
合并两个有序的单链表,合并之后仍然有序.

思路和反转单链表很像.将两个链表进行对比.小的那个加入新的链表中.

以下是对提供的参考资料的总结,按照要求结构化多个要点分条输出: 4G/5G无线网络优化与网规案例分析: NSA站点下终端掉4G问题:部分用户反馈NSA终端频繁掉4G,主要因终端主动发起SCGfail导致。分析显示,在信号较好的环境下,终端可能因节能、过热保护等原因主动释放连接。解决方案建议终端侧进行分析处理,尝试关闭节电开关等。 RSSI算法识别天馈遮挡:通过计算RSSI平均值及差值识别天馈遮挡,差值大于3dB则认定有遮挡。不同设备分组规则不同,如64T和32T。此方法可有效帮助现场人员识别因环境变化引起的网络问题。 5G 160M组网小区CA不生效:某5G站点开启100M+60M CA功能后,测试发现UE无法正常使用CA功能。问题原因在于CA频点集标识配置错误,修正后测试正常。 5G网络优化与策略: CCE映射方式优化:针对诺基亚站点覆盖农村区域,通过优化CCE资源映射方式(交织、非交织),提升RRC连接建立成功率和无线接通率。非交织方式相比交织方式有显著提升。 5G AAU两扇区组网:与三扇区组网相比,AAU两扇区组网在RSRP、SINR、下载速率和上传速率上表现不同,需根据具体场景选择适合的组网方式。 5G语音解决方案:包括沿用4G语音解决方案、EPS Fallback方案和VoNR方案。不同方案适用于不同的5G组网策略,如NSA和SA,并影响语音连续性和网络覆盖。 4G网络优化与资源利用: 4G室分设备利旧:面对4G网络投资压减与资源需求矛盾,提出利旧多维度调优策略,包括资源整合、统筹调配既有资源,以满足新增需求和提质增效。 宏站RRU设备1托N射灯:针对5G深度覆盖需求,研究使用宏站AAU结合1托N射灯方案,快速便捷地开通5G站点,提升深度覆盖能力。 基站与流程管理: 爱立信LTE基站邻区添加流程:未提供具体内容,但通常涉及邻区规划、参数配置、测试验证等步骤,以确保基站间顺畅切换和覆盖连续性。 网络规划与策略: 新高铁跨海大桥覆盖方案试点:虽未提供详细内容,但可推测涉及高铁跨海大桥区域的4G/5G网络覆盖规划,需考虑信号穿透、移动性管理、网络容量等因素。 总结: 提供的参考资料涵盖了4G/5G无线网络优化、网规案例分析、网络优化策略、资源利用、基站管理等多个方面。 通过具体案例分析,展示了无线网络优化中的常见问题及解决方案,如NSA终端掉4G、RSSI识别天馈遮挡、CA不生效等。 强调了5G网络优化与策略的重要性,包括CCE映射方式优化、5G语音解决方案、AAU扇区组网选择等。 提出了4G网络优化与资源利用的策略,如室分设备利旧、宏站RRU设备1托N射灯等。 基站与流程管理方面,提到了爱立信LTE基站邻区添加流程,但未给出具体细节。 新高铁跨海大桥覆盖方案试点展示了特殊场景下的网络规划需求。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值