2020-08-23

单链表的具体操作(基于JAVA)

单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。

在这里插入图片描述

即:每个节点包含data域、next域(指向下一个节点)

在这里插入图片描述

单链表的应用(使用带头结点的单链表实现银行账户的管理):

(1)第一种添加节点方法,直接添加到单链表的尾部。
 首先创建一个head头结点,里面不存放任何数据内容,作用是用来表示单链表的头结点
通过遍历找到最后一个节点,将最后一个节点的next指针指向需要添加的节点。

在这里插入图片描述

(2)通过指定的位置添加节点

通过遍历以及辅助指针temp预处理(单链表是否为空、需要添加的节点是否存在等),然后找到新添加节点的位置
将新的节点的next = temp.next
将temp.next = 新的节点

在这里插入图片描述

(3)修改指定节点

通过遍历以及辅助指针temp找到需要修改的节点
将temp.name = newNode.name
temp.money = newNode.money

(4)删除指定节点

接收需要删除节点的no
通过比那里找到需要删除节点的前一个节点
temp.next = temp.next.next

(5)打印单链表

预处理判断链表是否为空
通过遍历以及temp辅助指针遍历单链表并打印

(6)单链表的有效节点

声明一个length = 0
预处理判断单链表是否为空
通过遍历,每次length++,最后打印length

(7)查到单链表倒数第n个节点

接收倒数第n个节点,求出单链表长度size,定义辅助指针cur
遍历size - n次,此时的cur就为倒数第n个节点

(8)单链表的反转(这里使用头插法)

声明一个新的头节点(reverseHead)
通过遍历,把每次遍历到的节点都放在新的单链表(reverseHead)最前端
把原来链表head.next指向reversehead.next

在这里插入图片描述

(9)使用栈把单链表逆序输出出来

首先利用栈先进后出的道理,把各个节点压入栈中了,然后遍历输出即可逆序输出

以下为实现代码:

package com.java;

import java.util.Scanner;
import java.util.Stack;

public class SingleLinkedListDemo {
    public static void main(String[] args) {
        BankNode bankNode1 = new BankNode(1101,"马一",100);
        BankNode bankNode2 = new BankNode(1102,"马二",1000000);
        BankNode bankNode3 = new BankNode(1103,"马三",1000000);
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        singleLinkedList.add(bankNode1);
        singleLinkedList.add(bankNode2);
        singleLinkedList.add(bankNode3);
        boolean loop = true;
        Scanner scanner = new Scanner(System.in);

        while (loop)
        {
            System.out.println("-----------------------");
            System.out.println("show----显示单链表-----");
            System.out.println("add-----增加节点-------");
            System.out.println("addBy--增加指定节点----");
            System.out.println("del----删除指定节点----");
            System.out.println("rev----单链表的反转----");
            System.out.println("get----单链表的节长----");
            System.out.println("i-----倒数第i个节点----");
            System.out.println("stack--利用栈倒叙输出--");
            System.out.println("exit------退出--------");
            System.out.println("-----------------------");
            String key = scanner.next();
            switch (key)
            {
                case "show":
                    singleLinkedList.list();
                    break;
                case "add":
                    System.out.println("请输入账户、名字、余额");
                    int no_add = scanner.nextInt();
                    String name_add = scanner.next();
                    long money_add = scanner.nextLong();
                    singleLinkedList.add(new BankNode(no_add,name_add,money_add));
                    break;
                case "addBy":
                    System.out.println("请输入账户、名字、余额");
                    int no_byOrder = scanner.nextInt();
                    String name_byOrder = scanner.next();
                    long money_byOrder = scanner.nextLong();
                    singleLinkedList.addByOrder(new BankNode(no_byOrder,name_byOrder,money_byOrder));
                    break;
                case "del":
                    System.out.println("请输入需要删除的银行账户");
                    int no_del = scanner.nextInt();
                    singleLinkedList.del(no_del);
                    break;
                case "exit":
                    scanner.close();
                    loop = false;
                    break;
                case "rev":
                    singleLinkedList.reverse();
                    break;
                case "get":
                    System.out.println(singleLinkedList.getLength());
                    break;
                case "i":
                    System.out.println("请输入倒数第i个数");
                    int index = scanner.nextInt();
                    System.out.println(singleLinkedList.findLastIndexNode(index));
                    break;
                case "stack":
                    singleLinkedList.reverseShow();
                    break;
                default:
                    break;
            }
        }
        System.out.println("退出程序");
    }
}
class SingleLinkedList {
    //定义一个头结点,头结点不放任何数据
    BankNode head = new BankNode(0, "", 0);

    //1、添加节点
    //思路,找到当前的最后一个节点,把最后一个节点指向当前节点
    public void add(BankNode bankNode) {
        //由于头结点的位置固定,所以要用一个temp接收头结点来进行寻找
        BankNode temp = head;
        while (true) {
            if (temp.next == null)
                //此时通过temp找到数组的最后一项,退出循环
                break;
            else //此时没找到,则将temp后移
                temp = temp.next;
        }
        //退出循环,此时temp为最后一个节点,把temp.next指向我们现在需要添加的节点
        temp.next = bankNode;
    }

    //2、指向添加节点方式
    public void addByOrder(BankNode bankNode) {
        //由于头结点的位置固定,所以要用一个temp接收头结点来进行寻找
        BankNode temp = head;
        boolean flag = false;//定义一个标记,看此时添加的数据是否存在单链表中
        while (true) {
            if (temp.next == null)//此时已经找到单链表最后一个,退出循环
                break;
            else if (temp.next.no == bankNode.no)//此时说明需要添加的节点已存在
            {
                flag = true;
                break;
            } else if (temp.next.no > bankNode.no)//此时说明已经找到
                break;
            temp = temp.next;
        }
        //退出循环后,使用标记判断是否能添加
        if (flag)
            System.out.println("准备插入的银行账户" + bankNode.no + "已经存在");
        else//把需要添加的节点添加进去
        {
            bankNode.next = temp.next;
            temp.next = bankNode;
        }
    }

    //3、根据bankNode.no判断是否要修改
    public void update(BankNode newbankNode) {
        if (head.next == null)//此时单链表为空
        {
            System.out.println("链表为空");
            return;
        }
        //由于头结点的位置固定,所以要用一个temp接收头结点来进行寻找
        BankNode temp = head;
        boolean flag = false;
        while (true) {
            if (temp.next == null)//此时已经找到单链表最后一个,退出循环
                break;
            else if (temp.no == newbankNode.no)//此时找到需要修改的节点
            {
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag) {
            temp.name = newbankNode.name;
            temp.money = newbankNode.money;
        } else {
            System.out.println("没有找到需要修改的节点");
        }
    }

    //4、根据编号来删除节点
    public void del(int no) {
        if (head.next == null)//此时单链表为空
        {
            System.out.println("链表为空");
            return;
        }
        boolean flag = false;//声明一个标记,判断是否找到删除的节点
        //由于头结点的位置固定,所以要用一个temp接收头结点来进行寻找
        BankNode temp = head;
        while (true) {
            if (temp.next == null)//此时已经找到单链表最后一个,退出循环
                break;
            else if (temp.next.no == no) {
                flag = true;
                break;
            }

            temp = temp.next;//后移
        }
        if (flag) {
            temp.next = temp.next.next;
        } else
            System.out.println("没有找到需要删除的" + no + "节点");
    }

    //5、遍历单链表,并显示
    public void list() {
        if (head.next == null)//此时单链表为空
        {
            System.out.println("链表为空");
            return;
        }
        //由于头结点的位置固定,所以要用一个temp接收头结点来进行寻找
        BankNode temp = head;
        while (true) {
            if (temp.next == null)//此时已经找到单链表最后一个,退出循环
                break;
            temp = temp.next;//后移
            System.out.println(temp);
        }
    }

    //6、求单链表的有效节点
    public int getLength()
    {
        int length = 0;
        if (head.next == null) return 0;
        //定义一个cur指针,保存当前节点位置
        BankNode cur = head.next;
        while (cur != null)
        {
            length ++;
            cur = cur.next;
        }
        return  length;
    }

    //7、查找单链表倒数第n个结点
    public BankNode findLastIndexNode(int index)
    {
        //此时为空链表,没有找到
        if (head.next == null)return null;
        //检索索引是否为有效值
        int size = getLength();//遍历求得有效结点的大小
        if (index<0 || index>size) return  null;
        //定义一个cur指针,保存当前节点位置
        BankNode cur = head.next;
        for (int i = 0; i < size - index; i++) {
                cur = cur.next;
            }

        return cur;
    }

    //8、实现单链表的反转功能,这里使用头插法
    public void reverse()
    {
        //判断单链表是否为空或者是否仅有一个数据,若是的话则返回
        if (head.next == null||head.next.next == null) return;

        //定义一个cur指针,保存当前节点位置
        BankNode cur = head.next;
        //定义一个next指针,用于保存当前节点的下一个节点的位置
        BankNode next = null;
        //定义一个新的链表来存放反转的链表
        BankNode reverseHead = new BankNode(0,"",0);
        while (cur != null)
        {
            next = cur.next;//保存当前节点的下一个节点
            reverseHead.next = cur;//新链表存放当前节点
            cur.next = reverseHead.next;//将cur下一个节点放入到新链表的最前端
            cur = next;//后移
        }
        head.next = reverseHead.next;//最后把旧的头结点指向新链表的新节点,完成反转
        System.out.println("反转成功!!!!!!");
    }


    //9、利用栈来倒序打印单链表
    public void reverseShow()
    {
        //此时为空链表,无须打印
        if (head.next == null)return;
        Stack<BankNode> stackNode = new Stack<BankNode>();
        //定义cur指针,保存当前节点
        BankNode cur = head.next;
        //把链表所有的值放入栈中
        while (cur != null)
        {
            stackNode.push(cur);
            cur = cur.next;
        }
        System.out.println("倒叙输出~~~~~~~~~~~");
        //将栈中的节点输出出来
        while (stackNode.size() > 0)
        {
            System.out.println(stackNode.pop());
        }
    }



}
//定义一个银行账户,每个Bank对象就是一个节点
class BankNode
{
    public int no;
    public String name;
    public long money;
    public BankNode next;//指向下一个节点
    public BankNode(int no,String name,long money)//定义构造器,在调用时创建一个节点
    {
        this.no = no;
        this.name = name;
        this.money = money;
    }
    //重写toString()

    @Override
    public String toString() {
        return "BankNode[no = "+ no +",name = "+ name +",money = "+ money +"]";
    }
}

猜你喜欢

转载自blog.csdn.net/zzFZJ_/article/details/108190954