数据结构与算法(java)——链表

来源:互联网 发布:常用的nosql数据库 编辑:程序博客网 时间:2024/06/05 06:35
  • 单链表:是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,结点的构成:元素(数据元素的映像) + 指针(指示后继元素的存放位置)。


    单链表图示

代码实现:

public class LinkList {    // 头结点    private Node head;    public LinkList() {        head = new Node();    }    /**     * 插入一个结点,在头结点后进行插入     *      * @param data     */    public void insertAtHead(long data) {        Node node = new Node(data);        node.next = head.next;        head.next = node;    }    /**     * 删除一个结点,在头结点后进行删除     *      * @return     */    public Node deleteAtHead() {        Node tmp = head.next;        head.next = tmp.next;        return tmp;    }    /**     * 显示所有数据     */    public void displayAll() {        Node curNode = head.next;        while (curNode != null) {            curNode.display();            curNode = curNode.next;        }        System.out.println();    }    /**     * 查找方法,根据数据域查找     *      * @param data     * @return     */    public Node find(long data) {        Node curNode = head.next;        while (curNode.data != data) {            if (curNode.next == null) {                return null;            }            curNode = curNode.next;        }        return curNode;    }    /**     * 删除方法,根据数据域进行删除     *      * @param data     * @return     */    public Node delete(long data) {        Node curNode = head.next;        Node preNode = head.next;        while (curNode.data != data) {            if (curNode.next == null) {                return null;            }            preNode = curNode;            curNode = curNode.next;        }        if (curNode == head.next) {            head.next = curNode.next;        } else {            preNode.next = curNode.next;        }        return curNode;    }}

  • 双端链表:将单链表的终端结点的指针端指向头结点,使头尾相接形成一个环称为单循环链表,简称循环链表(circular linked list)或双端链表。


    双端链表图示

代码实现:

public class CircularLindedList {    // 头结点    private Node head;    // 尾结点    private Node rear;    public CircularLindedList() {//构造一个空的循环单链表        head = new Node();        rear = head;        head.next = rear;    }    /**     * 插入一个结点,在头结点后进行插入     *      * @param data     */    public void insertAtHead(long data) {        Node node = new Node(data);        if(isEmpty()){            node.next = head;            head.next = node;            rear = node;        } else {            node.next = head.next;            head.next = node;           }    }    /**     * 插入一个结点,在尾结点后插入     *      * @param data     */    public void insertAtRear(long data) {        Node node = new Node(data);        if(isEmpty()){            node.next = head;            head.next = node;        } else {            node.next = head;            rear.next = node;        }        rear = node;    }    /**     * 删除一个结点,在头结点后进行删除     *      * @return     */    public Node deleteAtHead() {        if(isEmpty()){            return null;        }        Node tmp = head.next;        head.next = tmp.next;        return tmp;    }    /**     * 显示所有数据     */    public void displayAll() {        Node curNode = head.next;        while (curNode != head) {            curNode.display();            curNode = curNode.next;        }        System.out.println();    }    /**     * 查找方法,根据数据域查找     *      * @param data     * @return     */    public Node find(long data) {        if(isEmpty()){            return null;        }        Node curNode = head.next;        while (curNode.data != data) {            if (curNode.next == head) {//遍历完了整个单链表                return null;//没有找到要查询的数据            }            curNode = curNode.next;        }        return curNode;    }    /**     * 删除方法,根据数据域进行删除     *      * @param data     * @return     */    public Node delete(long data) {        if(isEmpty()){            return null;        }        Node curNode = head.next;        Node preNode = head.next;        while (curNode.data != data) {            if (curNode.next == head) {                return null;//没有找到要删除的数据            }            preNode = curNode;            curNode = curNode.next;        }        if (curNode == head.next) {            head.next = curNode.next;        } else {            preNode.next = curNode.next;        }        return curNode;    }    /**     * 是否为空     *      * @return     */    public boolean isEmpty() {        return head.next == head;    }    /**     * 获得尾结点     * @return     */    public Node getRear() {        return rear;    }}
  • 双向链表:每个结点有两个指针域,分别指向它的前驱和后继结点;循环双向链表 即尾结点的后继指针域指向头结点,头结点的前驱指针域指向尾结点,形成一个闭环。

    循环双向链表:


    循环双向链表

代码实现:

/** * 循环双向链表 * @author kushanmao * @date 2017-7-2 */public class CircularDoubleLinkedList {    // 头结点    private DoubleNode head;    // 尾结点    private DoubleNode rear;    public CircularDoubleLinkedList() {// 构造空的循环双向链表        head = new DoubleNode();        rear = head;        head.next = head;        head.previous = head;    }    /**     * 插入一个结点,在头结点后进行插入     *      * @param data     */    public void insertAtHead(long data) {        DoubleNode node = new DoubleNode(data);        if (isEmpty()) {            node.previous = head;            node.next = head;            head.previous = node;            head.next = node;            rear = node;        } else {            node.previous = head;// 1、将前驱指向头结点            node.next = head.next;// 2、将后继指向head.next            head.next.previous = node;// 3、将head.next的前驱指向node            head.next = node;// 4、将头结点的后继指向node        }    }    /**     * 插入一个结点,在尾结点后插入     *      * @param data     */    public void insertAtRear(long data) {        DoubleNode node = new DoubleNode(data);        if (isEmpty()) {            node.previous = head;            node.next = head;            head.previous = node;            head.next = node;        } else {            node.previous = rear;            node.next = rear.next;// node.next = head;            rear.next.previous = node;// head.previous = node;            rear.next = node;        }        rear = node;    }    /**     * 删除一个结点,在头结点后进行删除     *      * @return     */    public DoubleNode deleteAtHead() {        if (isEmpty()) {            return null;        }        DoubleNode tmp = head.next;        head.next = tmp.next;        tmp.next.previous = head;        return tmp;    }    /**     * 删除一个结点,从尾部进行删除     *      * @return     */    public DoubleNode deleteAtRear() {        DoubleNode node = rear;        rear.previous.next = head;        head.previous = rear.previous;        rear = rear.previous;        return node;    }    /**     * 显示所有数据     */    public void displayAll() {        DoubleNode curNode = head.next;        while (curNode != head) {            curNode.display();            curNode = curNode.next;        }        System.out.println();    }    /**     * 查找方法,根据数据域查找     *      * @param data     * @return     */    public DoubleNode find(long data) {        DoubleNode curNode = head.next;        while (curNode.data != data) {            if (curNode.next == head) {                return null;// 遍历完了整个链表,没有找到要查询的数据            }            curNode = curNode.next;        }        return curNode;    }    /**     * 删除方法,根据数据域进行删除     *      * @param data     * @return     */    public DoubleNode delete(long data) {        DoubleNode curNode = head.next;        while (curNode.data != data) {            if (curNode.next == head) {                return null;            }            curNode = curNode.next;        }        curNode.previous.next = curNode.next;        curNode.next.previous = curNode.previous;        return curNode;    }    /**     * 是否为空     *      * @return     */    public boolean isEmpty() {        return head.next == head;    }    /**     * 获取尾结点     *      * @return     */    public DoubleNode getRear() {        return rear;    }}



总结:

  1. 在这里的链表都是有头结点的;
  2. 由于链表的查找都要遍历整个链表,所以需要大量查询操作的情况一般不使用链表,但是链表的增删是很方便的,增删操作越频繁效率优势就越明显;
  3. 双向链表的的空间占用相较于单链表会大些(要保存两个指针),但是在时间性能上优于单链表,效率较高
原创粉丝点击