美文网首页
数据结构和算法(三)单向链表

数据结构和算法(三)单向链表

作者: 烧伤的火柴 | 来源:发表于2020-07-06 20:12 被阅读0次

    介绍

    线性表是 n 个数据元素的有限序列,最常用的是链式表达,通常也叫作线性链表或者链表。在链表中存储的数据元素也叫作节点,一个节点存储的就是一条数据记录。

    单向链表的实现

    /**
     * 单链表的节点
     */
    public class Node<Data> {
        private Data data;
        private Node<Data> next;
        private int size = 0;
        private Node<Data> firstNode;//头节点
        private Node<Data> lastNode;//尾节点
    
        public Node(Data data) {
            this.data = data;
            if (firstNode == null) {
                firstNode = new Node<>(data, null);
            }
            size++;
        }
    
        private Node(Data data, Node<Data> next) {
            this.data = data;
            this.next = next;
        }
    
        /**
         * 插入元素
         *
         * @param d 数据
         */
        public void addData(Data d) {
            if (firstNode == null) {
                firstNode = new Node<>(d, null);
            } else if (lastNode == null) {
                lastNode = new Node<>(d, null);
                firstNode.next = lastNode;
            } else {
                lastNode.next = new Node<>(d, null);
                lastNode = lastNode.next;
            }
            size++;
        }
    
        /**
         * 删除元素
         * 单向链表只能从头向尾遍历
         *
         * @param d 数据
         */
        public void deleteData(Data d) {
            if (firstNode == null) {
                return;
            } else {
                if (lastNode == null) {
                    if (firstNode.data == d) {
                        firstNode = null;
                    }
                } else {
                    Node<Data> tmpNode = firstNode;
                    while (tmpNode != null) {
                        if (tmpNode.next != null && tmpNode.next.data == d) {
                            tmpNode.next = tmpNode.next.next;
                        }
                        tmpNode = tmpNode.next;
                    }
                }
                size--;
            }
        }
    
        public int getSize() {
            return size;
        }
    
        public Data getData() {
            return data;
        }
    
        @Override
        public String toString() {
            Node<Data> tmpNode = firstNode;
            StringBuilder string = new StringBuilder();
            while (tmpNode != null) {
                string.append(tmpNode.data + " ");
                tmpNode = tmpNode.next;
            }
            return string.toString();
        }
      
    }
    

    Node类内部定义了要存储的数据Data和指向下一个节点的指针,以及链表头部和尾部指针。

    几种算法

    案例1、奇数链表中查找到中间的元素和位置。
    链表只能通过头指针向后一个一个的去遍历元素,那么如何能够快速的找到奇数链表中查找到中间的元素和位置呢?有两种方法:
    方法1 如果知道长度,就按照从头到尾一次遍历计算位置,进行比较。
    方法2 如果不知道长度,可以采用快指针和慢指针的方法,关于快慢指针可以自行百度。
    这里实现以下快慢指针:

     /**
         * 如果是奇数查找中间元素
         */
        public Node<Data> findMiddle() {
            if (size > 1 && ((size & 1) == 1)) {
                Node<Data> fastPointerNode = firstNode.next.next;
                Node<Data> slowPointerNode = firstNode.next;
                int index = 1;
                while (fastPointerNode!=null&&fastPointerNode.next != null){
                    fastPointerNode = fastPointerNode.next.next;
                    slowPointerNode = slowPointerNode.next;
                    index++;
                }
                System.out.println("中间位置是:"+index);
                return slowPointerNode;
            }
            return null;
        }
    

    案例2:对链表进行反向旋转
    为了解决这个问题,我们需要构造三个指针 prev、curr 和 next,对当前结点、以及它之前和之后的结点进行缓存,再完成翻转动作。

    
        /**
         * 翻转链表
         */
        public void reverseNode(){
            if (size>1) {
                Node<Data> current = firstNode.next;
                Node<Data> previous = firstNode;
                Node<Data> next = null;
                while (current!=null){
                    next = current.next;
                    current.next = previous;
                    if (previous==firstNode) {
                        previous.next=null;
                    }
                    previous = current;
                    current = next;
                }
                firstNode = previous;
            }
    
        }
    

    这里容易犯一个错误,在第一次循环的时候忘记把previous.next=null;那么就会导致firstNode和下一个节点相互引用,在遍历的时候导致内存溢出。

    总结

    当数据的个数不确定时,而且经常添加和删除数据时,可以选择链表。
    单链表和双向链表的区别是:双向链表可以从两端遍历,单项链表只能用一端遍历。

    相关文章

      网友评论

          本文标题:数据结构和算法(三)单向链表

          本文链接:https://www.haomeiwen.com/subject/xebgqktx.html