zoukankan      html  css  js  c++  java
  • Java数据结构和算法(一)线性结构之单链表

    Java数据结构和算法(一)线性结构之单链表

         prev                 current              next
      --------------      --------------     --------------
     | value | next | -> | value | next | -> | value | next |
      --------------      --------------     --------------
    

    单链表的结构如上:最后一个节点的 next=null。下面看一下代码。

    (1) 链表的基本操作

    public class Node<E> {
    
        private E value;
        private Node next;
    
        public Node(E value) {
            this.value = value;
        }
    
        // 追加到最后一个元素
        public Node append(Node node) {
            Node tail = tail();
            tail.next(node);
            return this;
        }
    
        // 删除指定的节点
        public void remove(Node node) {
            Node prev = prev(node);
            if (prev != null) {
                prev.next = node.next;
            }
        }
    
        // 节点总数
        public int size() {
            int size = 1;
            Node current = this;
            while (current.next != null) {
                size++;
                current = current.next;
            }
            return size;
        }
    
        // 查找指定节点的上一个节点
        public Node prev(Node node) {
            Node prev = this;
            while (prev != null) {
                if (prev.next == node) {
                    return prev;
                }
                prev = prev.next;
            }
            return null;
        }
    
        // 查找尾节点,单链表 tail.next=null
        public Node tail() {
            Node tail = this;
            while (tail.next != null) {
                tail = tail.next;
            }
            return tail;
        }
    
        // 设置当前节点的下一个节点
        public void next(Node next) {
            // 设置该节点的后继节点
            next.next = this.next;
            // 将该节点设置为当前节点的前驱节点
            this.next = next;
        }
    
        public Node next() {
            return next;
        }
    
        public E getValue() {
            return value;
        }
    
        public void setValue(E value) {
            this.value = value;
        }
    }
    

    (2) 取出中间节点

    偶数节点取中间两个节点的前一个节点,奇数节点取正中间的节点

    public Node mid() {
        Node stepOneNode = this;
        Node stepTwoNode = this;
        while (stepTwoNode != null) {
            stepTwoNode = stepTwoNode.next;
            if (stepTwoNode != null) {
                stepTwoNode = stepTwoNode.next;
                if (stepTwoNode != null) {
                    stepOneNode = stepOneNode.next;
                }
            }
        }
        return stepOneNode;
    }
    

    (3) 链表反转

    public Node reverse() {
        Node prev = null;
        Node next = null;
        Node current = this;
        while (current != null) {
            next = current.next;
            current.next = prev;
            prev = current;
            current = next;
        }
        return prev;
    }
    

    测试一把:

    public void test1() {
        Node n1 = new Node(1);
        Node n2 = new Node(2);
        Node n3 = new Node(3);
    
        n1.append(n2).append(n3);
        Assert.assertEquals(3, n1.next().next().getValue());
        Assert.assertEquals(3, n1.tail().getValue());
        Assert.assertEquals(2, n1.prev(n3).getValue());
        Assert.assertEquals(3, n1.size());
    
        n1.remove(n2);
        Assert.assertEquals(3, n1.next().getValue());
        Assert.assertEquals(1, n1.mid().getValue());
    
        n1.next(n2);
        Assert.assertEquals(3, n1.next().next().getValue());
        Assert.assertEquals(2, n1.mid().getValue());
    
        Node reverse = n1.reverse();
        Assert.assertEquals(3, reverse.getValue());
        Assert.assertEquals(2, reverse.next().getValue());
        Assert.assertEquals(1, reverse.next().next().getValue());
    }
    

    (4) 有序链表的合并

    两个有序链表合并后还是有序的,代码如下:

    // 有序链表合并,两个链表均升序排列,最终的结果也升序排列
    public static Node merge(Node<Integer> node1, Node<Integer> node2) {
        if (node1 == null || node2 == null) {
            return node1 == null ? node2 : node1;
        }
    
        Node<Integer> head = node1.value < node2.value ? node1 : node2;
        Node<Integer> cur1 = head == node1 ? node1 : node2; // 小
        Node<Integer> cur2 = head == node1 ? node2 : node1; // 大
    
        Node prev = null; // curl1 的前驱节点,小
        while (cur1 != null && cur2 != null) {
            if (cur1.value < cur2.value) {
                prev = cur1;
                cur1 = cur1.next;
            } else {
                // 将 curl2 插入到 prev 和 curl1 之间
                Node tmp = cur2.next;
                cur2.next = cur1;
                prev.next = cur2;
                prev = cur2;
                cur2 = tmp;
            }
        }
        prev.next = cur1 == null ? cur2 : cur1;
        return head;
    }
    
    // 有序链表合并,两个链表均升序排列,最终的结果也升序排列
    public static Node mergeRecurse(Node<Integer> node1, Node<Integer> node2) {
        if (node1 == null || node2 == null) {
            return node1 != null ? node1 : node2;
        }
        Node head = null;
        if (node1.value > node2.value) {
            head = node2;
            head.next = mergeRecurse(node1, node2.next);
        } else {
            head = node1;
            head.next = mergeRecurse(node1.next, node2);
        }
        return head;
    }
    

    测试:

    public void mergeTest() {
        Node n1 = new Node(1);
        // 省略...
        Node n6 = new Node(6);
    
        n1.append(n3).append(n5);
        n2.append(n4).append(n6);
    
        Node merge1 = Node.merge(n1, n2);
        //Node merge1 = Node.mergeRecurse(n1, n2);
        Assert.assertEquals(6, merge1.size());
        Assert.assertEquals(2, merge1.next().getValue());
    }
    

    每天用心记录一点点。内容也许不重要,但习惯很重要!

  • 相关阅读:
    Android数字选择器-NumberPicker
    Eclipse上传代码到GitHub
    TortoiseGit上传代码到GitHub
    Git的简单介绍
    Android中的树状(tree)列表
    Android数据适配-ExpandableListView
    Android动画-补间(Tween)动画
    Android动画-帧动画
    Android中样式及主题
    Android消息通知-Notification
  • 原文地址:https://www.cnblogs.com/binarylei/p/10115888.html
Copyright © 2011-2022 走看看