数据结构-链表 JAVA语言实现

数据结构-链表 JAVA语言实现

作为一名Android程序员,开始学习数据结构和算法,用JAVA语言写写自己对链表的看法和代码上的实现,如果有问题,麻烦指出,互相学习。

目录

  • 单向链表
  • 双向链表
  • 循环链表

1、单向链表

单向链表包含多个结点,每个结点都有一个next指向下一个结点,直到最后一个结点的next指向为null,链表结束。

单向链表结点实体类:

/**
 * 单向链表
 */
public class ListNode {

    private int data;  //结点的数据
    private ListNode next;   //指向下一个结点

    public ListNode(int data) {
        this.data = data;
    }
    public int getData() {
        return data;
    }
    public void setData(int data) {
        this.data = data;
    }
    public ListNode getNext() {
        return next;
    }
    public void setNext(ListNode next) {
        this.next = next;
    }
}

1.1 遍历链表

循环遍历每个结点,知道结点的next为null时,当前结点为尾结点。

    /**
     * 遍历链表,获取长度
     * @param headNode
     * @return 链表长度
     */
    public int listLength(ListNode headNode){
        int count = 0;
        ListNode currentNode = headNode;
        while(currentNode != null){
            count ++;
            currentNode = currentNode.getNext();
        }
        return count ;
    }

1.2 插入元素

插入元素包括三种情况:

  • 插入到头结点前
  • 插入到链表中间位置
  • 插入到尾结点

    (1)插入到头结点只需要将插入的结点的next指向当前头结点,返回插入结点即可。
    (2)插入到中间或者尾结点,遍历结点直到插入位置的前一个节点,将next指向插入结点,再将插入结点的next指向后一元素(如果插入的结点在最后,后以节点为null)。

 /**
     * 插入结点  可以为头 中 尾插入
     * @param headNode 当前头结点
     * @param insertNode 插入结点
     * @param position 插入位置
     * @return 返回插入后的头结点
     */
    public ListNode insertNode(ListNode headNode,ListNode insertNode,int position){
        //当当前链表为空,新链表直接为插入的链表
        if(headNode == null){
            return insertNode;
        }
        //获取长度
        int size = listLength(headNode);
        if(position > size + 1 || position < 1){
            //插入位置不合法
            System.out.println("插入位置不合法!");
            return headNode;
        }
        //链表开头插入
        if(position == 1){
            insertNode.setNext(headNode);
            headNode = insertNode;

        }else{
            ListNode previousNode = headNode;
            int count = 1;
            while (count < position -1){
                previousNode = previousNode.getNext();
                count++;
            }
            insertNode.setNext(previousNode.getNext());
            previousNode.setNext(insertNode);
        }
        return headNode;
    }

1.3 删除元素

删除元素同样区别删除位置:头、中、尾
(1)删除头结点:将头结点next设为null,下一个结点即为新的头结点
(2)删除中间或尾部结点,遍历链表直到删除的位置的前一个结点,同时拿到删除位置的后一个结点,将前一个结点的next指向后一个节点。

/**
     * 删除某个结点
     * @param headNode 头结点
     * @param position 删除位置
     * @return 返回头结点
     */
    public ListNode deleteNode(ListNode headNode,int position){
        //当前链表为空,
        if(headNode == null){
            System.out.print("当前链表为空,不能删除!");
            return null;
        }
        //获取长度
        int size = listLength(headNode);
        if(position > size  || position < 1){
            //删除位置不合法
            System.out.println("删除位置不合法!");
            return headNode;
        }
        if (position == 1){
            // 删除头结点
            ListNode currentNode = headNode.getNext();
            headNode = null;
            return currentNode;
        }else {
            ListNode previousNode = headNode;
            int count = 1;
            while (count < position - 1){
                previousNode = previousNode.getNext();
                count++;
            }
            //currentNode为删除的那个结点
            ListNode currentNode = previousNode.getNext();
            previousNode.setNext(currentNode.getNext());
            currentNode = null;
        }
        return headNode;
    }

2、双向链表

双向链表顾名思义就是有两个方向,多一个前驱结点。
双向链表结点的实体类:

/**
 * 双向链表
 */
public class DLLNode {
    private int data;
    private DLLNode next;
    private DLLNode previous;

    public DLLNode(int data, DLLNode newxt, DLLNode previous) {
        this.data = data;
        this.next = newxt;
        this.previous = previous;
    }

    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }

    public DLLNode getNext() {
        return next;
    }

    public void setNext(DLLNode next) {
        this.next = next;
    }

    public DLLNode getPrevious() {
        return previous;
    }

    public void setPrevious(DLLNode previous) {
        this.previous = previous;
    }
}

2.1 遍历元素

与单向链表类似,直接上代码:

 /**
     * 获取双向链表长度
     * @param headNode 头结点
     * @return
     */
    public int getDllLength(DLLNode headNode) {
        int count = 0;
        DLLNode current = headNode;
        while (current != null) {
            current = current.getNext();
            count++;
        }
        return count;
    }

2.2 插入元素

与单向链表相似,但是要修改插入元素指向的前驱结点。

/**
     * 插入结点
     * @param headNode 当前头结点
     * @param insertNode 插入的结点
     * @param position 插入位置
     * @return 插入后的头结点
     */
    public DLLNode insertDllNode(DLLNode headNode , DLLNode insertNode, int position){
        if (headNode == null){
            return insertNode;
        }
        int size = getDllLength(headNode);
        if(position < 1 || position > size + 1){
            System.out.println("插入位置有误");
            return headNode;
        }
        //插入到首位
        if (position == 1){

            insertNode.setNext(headNode);
            headNode.setPrevious(insertNode);
            return insertNode;
        }else {
            DLLNode previousNode = headNode;
            int count = 1;
            while (count < position - 1){
                previousNode = previousNode.getNext();
                count ++;
            }
            DLLNode currentNode = previousNode.getNext();
            if(previousNode.getNext() != null){
                //插入的位置在末尾
                currentNode.setPrevious(insertNode);
            }
            insertNode.setNext(currentNode);
            previousNode.setNext(insertNode);
            insertNode.setPrevious(previousNode);
        }

        return headNode;
    }

2.3 删除元素

/**
     * 删除结点
     * @param headNode 头结点
     * @param position 插入位置
     * @return 新链表的头结点
     */
    public DLLNode deleteNode(DLLNode headNode , int position){
        if(headNode == null){
            System.out.println("当前链表为空,不能进行删除操作!");
            return null;
        }
        int size = getDllLength(headNode);
        if(position < 1 || position > size){
            System.out.println("删除位置有误");
            return headNode;
        }
        if(position == 1){
            DLLNode currentNode = headNode.getNext();
            currentNode.setPrevious(null);
            headNode = null;
            return currentNode;
        }else {
            DLLNode currentNode = headNode;
            int count = 1;
            while (count < position){
                currentNode  = currentNode.getNext();
                count++;
            }
            DLLNode previousNode = currentNode.getPrevious();
            DLLNode nextNode = currentNode.getNext();
            previousNode.setNext(nextNode);
            if(nextNode != null){
                nextNode.setPrevious(previousNode);
            }
            currentNode = null;
        }
        return headNode;
    }

3、循环链表

循环链表与单向、双向链表的很大差别是没有null值表示结束,不做判断的话,一直循环下去。
循环链表结点实体类:

/**
 * 循环链表
 */
public class CLLNode {
    private int data;
    private CLLNode next;

    public CLLNode(int data) {
        this.data = data;
    }

    public CLLNode(int data, CLLNode next) {
        this.data = data;
        this.next = next;
    }

    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }

    public CLLNode getNext() {
        return next;
    }

    public void setNext(CLLNode next) {
        this.next = next;
    }
}

3.1 遍历链表

通过判断循环后的结点是否为头结点还做出结束循环操作。

    /**
     * 循环链表长度
     *
     * @param headNode 头结点
     * @return 长度
     */

    public int getListLenth(CLLNode headNode) {
        int count = 0;
        CLLNode currentNode = headNode;
        while (currentNode != null) {
            currentNode = currentNode.getNext();
            count++;
            if (currentNode == headNode) {
                break;
            }

        }
        return count;
    }

3.2 插入元素

循环链表插入与单向链表类似,注意将尾结点指向头结点即可。

    /**
     * 尾部插入
     *
     * @param headNode   头结点
     * @param insertNode 插入结点
     * @return 返回头结点
     */
    public CLLNode insertEndNode(CLLNode headNode, CLLNode insertNode) {
        CLLNode currentNode = headNode;
        while (currentNode.getNext() != headNode) {
            currentNode = currentNode.getNext();
        }
        currentNode.setNext(insertNode);
        insertNode.setNext(headNode);
        return headNode;
    }

    /**
     * 头部插入
     * @param headNode   头结点
     * @param insertNode 插入结点
     * @return 返回头结点
     */
    public CLLNode insertStartNode(CLLNode headNode, CLLNode insertNode) {
        CLLNode currentNode;
        currentNode = headNode;
        while (currentNode.getNext() != headNode) {
            currentNode = currentNode.getNext();
        }
        currentNode.setNext(insertNode);
        insertNode.setNext(headNode);

        return insertNode;
    }

3.3 删除元素

    /**
     * 删除头结点
     *
     * @param headNode 头结点
     * @return 新头结点
     */
    public CLLNode deleteStartNode(CLLNode headNode) {
        CLLNode currentNode = headNode;
        while (currentNode.getNext() != headNode) {
            currentNode = currentNode.getNext();
        }
        CLLNode newHeadNode = headNode.getNext();
        currentNode.setNext(newHeadNode);
        return newHeadNode;
    }

    /**
     * 删除尾结点
     *
     * @param headNode 头结点
     * @return 新头结点
     */
    public CLLNode deleteEndNode(CLLNode headNode) {
        CLLNode currentNode = headNode;
        CLLNode lastNode = headNode;
        while (currentNode.getNext() != headNode) {
            lastNode = currentNode;
            currentNode = currentNode.getNext();
        }
        currentNode = null;
        lastNode.setNext(headNode);

        return headNode;
    }

循环链表中部的删除、插入于单向链表相似。

完整代码:
http://download.csdn.net/download/z740852294/9947970

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Owen_le

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值