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

数据结构概述

数据结构包括:线性结构和非线性结构
线性结构:存在一一对应关系,比如数组a[0]=1.(数组,队列,栈,链表)
线性结构有两种存储方式:顺序存储和链式存储,顺序存储称为线性表,存储的元素地址是连续的比如数组。链式存储的线性表称为链表,存储数据不连续,靠地址指针来定位。链式存储适用于在较频繁地插入、删除、更新元素时,而顺序存储结构适用于频繁查询时使用。
非线性结构:二维数组,图,树。

稀疏数组

[外链图片转存失败(img-aVtXWget-1568776723900)(media/15686434577522.jpg)]

队列arrayQueue

类似管道,先进先出,队列两种实现:数组实现和链表实现

单链表LinkedList

每个节点包括data域和next域

定义节点

//定义节点
class HeroNode {
    public int number;
    public String name;
    public String nickName;
    public HeroNode next;

    public HeroNode(int hNumber, String hName, String hNickName) {
        this.number = hNumber;
        this.name = hName;
        this.nickName = hNickName;

    }

    //重写toString来打印
    @Override
    public String toString() {
        return "Hero: [ number: " + number + ", name: " + name + ", nickName: " + nickName + "]";
    }
}

单链表


//单链表
class SingleLinkedList {
    //先初始化头节点,不存放具体数据
    private HeroNode head = new HeroNode(0, "", "");
    public HeroNode getHead(){
        return this.head;
    }
    //添加节点到链表尾部
    public void add(HeroNode node) {
        //使用临时节点
        HeroNode temp = head;//temp=head则循环就要加next
        //遍历找到尾节点来插入
        //当temp的下一个节点为null时说明temp为尾节点
        while (temp.next != null) {
            temp = temp.next;//后移节点
        }
        //将最后一个节点指向新节点
        temp.next = node;
    }

    //在特定位置插入节点
    public void insert(HeroNode node) {

        //创建temp需是在要插入节点的前一个节点
        HeroNode temp = head;
        //循环直到temp为最后一个节点
        while (temp.next != null) {

            if (temp.next.number == node.number) {
                System.out.println("该节点已存在,不能插入");
                return;

            }
            //遍历查找当temp.next.number > node.number那么就是找到了该节点位置
            else if (temp.next.number > node.number) {//找到该节点位置
                break;
            }
            temp = temp.next;
        }
        //找到之后插入,
        node.next = temp.next;
        temp.next = node;

    }

    //更新节点
    public void update(HeroNode node) {

        //不修改第一个
        HeroNode temp = head.next;
        boolean flag = false;
        //循环直到temp为最后一个节点
        while (temp != null) {

            if (temp.number == node.number) {
                flag = true;
                break;
            }
            temp = temp.next;
        }
        //如果找到了
        if (flag) {
            temp.nickName = node.nickName;
            temp.name = node.name;
        } else {
            System.out.println("没有找到该节点。");
        }


    }

    //删除节点
    //我们需要找到待删除节点的前一个节点
    public void delete(int a) {
        HeroNode temp = head;
        boolean flag = false;
        while (temp.next != null) {
            if (temp.next.number == a) {
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag) {
            temp.next = temp.next.next;
        } else {
            System.out.println("要删除的该节点不存在");
        }
    }

    //查
    public void get(int a) {
        System.out.println("查询编号为:" + a);
        HeroNode temp = head.next;
        boolean flag = false;
        while (temp != null) {
            if (temp.number == a) {
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag)
            System.out.println(temp);
        else
            System.out.println("没找到该节点");

    }

    //打印链表
    public void printList() {
        System.out.println("printList:");
        //先判断链表是否为空
        if (head.next == null) {
            System.out.println("链表为空");

        } else {
            //头节点不能动,但是头节点数据是0,所以我们给temp作为next
            HeroNode temp = head.next;
            while (temp != null) {//一直循环直到当temp指向空节点,则跳出循环
                System.out.println(temp);
                temp = temp.next;
            }

        }

    }

}

获取单链表的节点个数

    //获取单链表有效节点个数
    //形参为链表头节点
    public static int countNode(HeroNode headNode) {
        int length = 0;
        //判断是否为空链表
        if (headNode.next == null)
            return 0;
        HeroNode cur = headNode.next;
        while (cur != null) {
            length++;
            cur = cur.next;
        }
        return length;
    }

查找单链表中倒数第K个节点

//查找单链表中倒数第K个节点
    //思路:先遍历得到链表长度然后计算处第几个节点
    public static HeroNode getReverseNode(HeroNode headNode, int k){
        int length = 0;
        //判断是否为空链表
        if (headNode.next == null)
            return null;
        //第一次遍历得到节点个数
        HeroNode cur = headNode.next;
        while (cur != null) {
            length++;
            cur = cur.next;
        }
        //第二次遍历得到该节点
        if (k<=0 || k>length)
            return null;
        HeroNode cur2 = headNode.next;
        //因为是第几个所有用for循环
        for (int i = 0;i<length-k;i++){
            cur2 = cur2.next;
        }
        //for循环移动指针之后这时就指向该节点
        return cur2;

    }

反转链表

//链表的反转
    //思路:把传进的链表遍历每个节点插入到第二个链表的前端
    public static void reverseLinkedList(HeroNode headNode) {
        //如果链表为空或者只有一个节点,则直接返回
        if (headNode.next == null || headNode.next.next == null) {
            return;
        }
        HeroNode cur = headNode.next;//第一个cur遍历
        HeroNode cur2 = null;//第二个cur进行链接后面的表
        HeroNode reverseHead = new HeroNode(0, "", "");//反转链表头

        while (cur != null) {
            //cur2保存临时变量
            cur2 = cur.next;
            //将节点插入到第二个链表头节点后面
            cur.next = reverseHead.next;
            reverseHead.next = cur;
            //后移cur,这时cur=cur.next已经不能后移了,而需要用到cur2
            cur = cur2;
        }
        //所有节点放到第二个链表中把第一个链表头节点指向第二个链表
        headNode.next = reverseHead.next;

    }

逆序打印链表

//链表到逆序打印
    //思路:一:我们可以反转链表打印,但会破坏链表结构。二:将链表节点压入一个栈,然后出栈就是逆序。
    public static void reversePrint(HeroNode headNode) {
        //判断为空
        if (headNode.next == null) {
            return;
        }
        //压栈
        Stack<HeroNode> heroNodeStack = new Stack<>();
        HeroNode cur = headNode.next;
        while (cur != null) {
            heroNodeStack.add(cur);
            cur = cur.next;
        }
        //打印栈
        while (heroNodeStack.size() > 0) {
            System.out.println(heroNodeStack.pop());

        }
    }

双向链表

单链表只能一个方向查找且删除的时候需要靠辅助节点;
双向链表可以两个方向查找,且删除的时候可以自己删除。
在这里插入图片描述

全部代码实现

package DataStructure;

import java.util.Stack;

public class SingleLinkedListDemo {
    public static void main(String[] args) {
        HeroNode node1 = new HeroNode(1, "song", "ji");
        HeroNode node2 = new HeroNode(2, "lujunyi", "yu");
        HeroNode node3 = new HeroNode(3, "wuyong", "zhiduoxing");
        HeroNode node4 = new HeroNode(4, "gongsunsheng", "ruyunlong");
        HeroNode node5 = new HeroNode(3, "duyongxing", "zhid");
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        singleLinkedList.add(node1);
        singleLinkedList.add(node2);
        singleLinkedList.add(node3);//不要同一个对象添加两次
        singleLinkedList.insert(node4);
        singleLinkedList.printList();
        singleLinkedList.update(node5);
        singleLinkedList.printList();
        singleLinkedList.delete(4);
        singleLinkedList.printList();
        singleLinkedList.get(1);
        System.out.println(countNode(singleLinkedList.getHead()));
        System.out.println(getReverseNode(singleLinkedList.getHead(), 5));
        reversePrint(singleLinkedList.getHead());

    }

    //获取单链表有效节点个数
    //形参为链表头节点
    public static int countNode(HeroNode headNode) {
        int length = 0;
        //判断是否为空链表
        if (headNode.next == null)
            return 0;
        HeroNode cur = headNode.next;
        while (cur != null) {
            length++;
            cur = cur.next;
        }
        return length;
    }

    //查找单链表中倒数第K个节点
    //思路:先遍历得到链表长度然后计算处第几个节点
    public static HeroNode getReverseNode(HeroNode headNode, int k) {
        int length = 0;
        //判断是否为空链表
        if (headNode.next == null)
            return null;
        //第一次遍历得到节点个数
        HeroNode cur = headNode.next;
        while (cur != null) {
            length++;
            cur = cur.next;
        }
        //第二次遍历得到该节点
        if (k <= 0 || k > length)
            return null;
        HeroNode cur2 = headNode.next;
        //因为是第几个所有用for循环
        for (int i = 0; i < length - k; i++) {
            cur2 = cur2.next;
        }
        //for循环移动指针之后这时就指向该节点
        return cur2;

    }

    //链表的反转
    //思路:把传进的链表遍历每个节点插入到第二个链表的前端
    public static void reverseLinkedList(HeroNode headNode) {
        //如果链表为空或者只有一个节点,则直接返回
        if (headNode.next == null || headNode.next.next == null) {
            return;
        }
        HeroNode cur = headNode.next;//第一个cur遍历
        HeroNode cur2 = null;//第二个cur进行链接后面的表
        HeroNode reverseHead = new HeroNode(0, "", "");//反转链表头

        while (cur != null) {
            //cur2保存临时变量
            cur2 = cur.next;
            //将节点插入到第二个链表头节点后面
            cur.next = reverseHead.next;
            reverseHead.next = cur;
            //后移cur,这时cur=cur.next已经不能后移了,而需要用到cur2
            cur = cur2;
        }
        //所有节点放到第二个链表中把第一个链表头节点指向第二个链表
        headNode.next = reverseHead.next;

    }

    //链表到逆序打印
    //思路:一:我们可以反转链表打印,但会破坏链表结构。二:将链表节点压入一个栈,然后出栈就是逆序。
    public static void reversePrint(HeroNode headNode) {
        //判断为空
        if (headNode.next == null) {
            return;
        }
        //压栈
        Stack<HeroNode> heroNodeStack = new Stack<>();
        HeroNode cur = headNode.next;
        while (cur != null) {
            heroNodeStack.add(cur);
            cur = cur.next;
        }
        //打印栈
        while (heroNodeStack.size() > 0) {
            System.out.println(heroNodeStack.pop());

        }
    }
}

//单链表
class SingleLinkedList {
    //先初始化头节点,不存放具体数据
    private HeroNode head = new HeroNode(0, "", "");

    public HeroNode getHead() {
        return this.head;
    }

    //添加节点到链表尾部
    public void add(HeroNode node) {
        //使用临时节点
        HeroNode temp = head;//temp=head则循环就要加next
        //遍历找到尾节点来插入
        //当temp的下一个节点为null时说明temp为尾节点
        while (temp.next != null) {
            temp = temp.next;//后移节点
        }
        //将最后一个节点指向新节点
        temp.next = node;
    }

    //在特定位置插入节点
    public void insert(HeroNode node) {

        //创建temp需是在要插入节点的前一个节点
        HeroNode temp = head;
        //循环直到temp为最后一个节点
        while (temp.next != null) {

            if (temp.next.number == node.number) {
                System.out.println("该节点已存在,不能插入");
                return;

            }
            //遍历查找当temp.next.number > node.number那么就是找到了该节点位置
            else if (temp.next.number > node.number) {//找到该节点位置
                break;
            }
            temp = temp.next;
        }
        //找到之后插入,
        node.next = temp.next;
        temp.next = node;

    }

    //更新节点
    public void update(HeroNode node) {

        //不修改第一个
        HeroNode temp = head.next;
        boolean flag = false;
        //循环直到temp为最后一个节点
        while (temp != null) {

            if (temp.number == node.number) {
                flag = true;
                break;
            }
            temp = temp.next;
        }
        //如果找到了
        if (flag) {
            temp.nickName = node.nickName;
            temp.name = node.name;
        } else {
            System.out.println("没有找到该节点。");
        }


    }

    //删除节点
    //我们需要找到待删除节点的前一个节点
    public void delete(int a) {
        HeroNode temp = head;
        boolean flag = false;
        while (temp.next != null) {
            if (temp.next.number == a) {
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag) {
            temp.next = temp.next.next;
        } else {
            System.out.println("要删除的该节点不存在");
        }
    }

    //查
    public void get(int a) {
        System.out.println("查询编号为:" + a);
        HeroNode temp = head.next;
        boolean flag = false;
        while (temp != null) {
            if (temp.number == a) {
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag)
            System.out.println(temp);
        else
            System.out.println("没找到该节点");

    }

    //打印链表
    public void printList() {
        System.out.println("printList:");
        //先判断链表是否为空
        if (head.next == null) {
            System.out.println("链表为空");

        } else {
            //头节点不能动,但是头节点数据是0,所以我们给temp作为next
            HeroNode temp = head.next;
            while (temp != null) {//一直循环直到当temp指向空节点,则跳出循环
                System.out.println(temp);
                temp = temp.next;
            }
        }
    }


}


//定义节点
class HeroNode {
    public int number;
    public String name;
    public String nickName;
    public HeroNode next;

    public HeroNode(int hNumber, String hName, String hNickName) {
        this.number = hNumber;
        this.name = hName;
        this.nickName = hNickName;

    }

    //重写toString来打印
    @Override
    public String toString() {
        return "Hero: [ number: " + number + ", name: " + name + ", nickName: " + nickName + "]";
    }
}

发布了103 篇原创文章 · 获赞 94 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/chongbin007/article/details/100976752
今日推荐