“改变”——从单向链表开始

单向链表

有过数据结构的基础的同学应该都知道,一个链表是由若干个节点组成的,而每一个节点由两部分组成,一部分是自己本身所储存的数据,另一部分则是指向下一个节点的节点对象。这刚听起来有点别扭,因为这就相当于每一个节点都存储另一个节点的对象,这个对象指向的是下一个节点。大概的原理图如下:
在这里插入图片描述
在这里我们把A(节点本身A的简称)称作头节点(链表里的基本操作差不多都是与头节点有关的),看了这个原理图以后我相大家都一目了然,在这张图里A的指向B,B指向C。链表就是由这样若干个节点组成的。

看到这里不知道大家有没有发现一个问题,那就是链表里的最后一个节点C里的对象指向哪里呢?
其实也很简单,就相当于如果只有一个节点的话,我们只需要让它直接指向null就好了。

明白了链表的组成是由节点组成的以后,我们就可以对其进行操作了。我们都知道,一般的链表都有最基本的增删查改操作。
那么往里面添加数据的话就是添加一个节点 (注意:在这里添加的顺序是从右往左进行的),在这里我们每添加一个节点就把头节点赋给新添加的那个节点。然后再把头节点的对象指向下一个节点。删除的话就更简单了,只需要把数据取出,然后再将头节点里的节点对象指向被删除节点的下一个节点…还有许多的操作都是在头节点上做文章的,在这里我就不一一赘述了。

**添加数据:**在添加数据之前,我们需要首先判断当来一个数据的时候,我的链表是否已经含有节点。如果有的话我们就需要新建一个节点,然后我们将新来的数据添加到新创建的这个节点,再将其指向已经存在的上一个节点,并将新建的这个节点赋为头节点。如果没有的话那就更好办了,直接新建一个节点然后将数据存储进去,并将它赋为头节点。

简单来说就是三步:
**1.判断是否已经存在节点
2.如果没有就新建节点,有也要新建,然后存储数据。
3.将新建的节点赋为头节点,并其指向已经存在的上一个节点(如果链表内只有一个节点的话就指向null)

明白了以上三步以后那就简单了,接下来我们利用代码来实现:

    /**
     * 在链表里添加数据.
     * @param s 输入的数据
     * @return 返回的数据
     */
    public Object addData(String s){
        Node newNode = new Node(); //新建一个节点(无论有无节点都要新建)
        if(size==0){         //如果链表内没有节点
            newNode.data = s; //将来的数据添加到新建的节点内
            head = newNode;  //将新建的节点赋为头节点
        }
        else{
                newNode.data = s; //将来的数据添加到新建的节点内
                newNode.next = head;//指向上一个数据
                head = newNode;//将新建的节点赋为头节点
        }
        size++;
        return head.data;
    }

**删除数据:**链表里删除数据的操作很简单。但是我们需要注意,在删除数据以后被删除数据的这个节点也要删除。被删除以后,要将链表的长度-1。要知道数据是和节点是“共存亡”的。
然而实现这个操作也非常简单,在上面我们也说过了,节点是一个指向一个的。如果我们要删除一个节点的话,那么只需要将指向被删除的这个节点不要指向删除的节点就好啦,跳过它,直接指向它的下一个节点。这样被删除的的节点就会被空出来不被使用,那么Java内存在的“回收站”会自动将其删除。

    /**
     * 在链表里删除指定数据
     * @param obj  输入指定数据进行删除
     * @return  若删除成功则为真.反之则为假.
     */
    public boolean DeleteData(Object obj){
        Node forward = head;
        Node current = head;
        int tempSize = size; //链表长度
        if(tempSize==0){
            return false;
        }
        while(current.data!=obj){
        if(current.next == null)
            return false;
        else{
            forward = current;
            current = current.next;
        }
        }
        size--;
        return true;
    }

**查找数据:**在链表里查找指定数据,同样的先从头节点开始寻找,若找到了则返回该节点。若没找到则寻找下一个节点

    /**
     * 在链表内查找指定的数据,若查找到了则返回该节点
     * @param data 输入需要查找的指定数据
     * @return  存储该数据的节点
     */
    public Node getData(Object data){
        Node temp = head;
        int fake = size;
//        if(fake==0)
//            return null;
//        else{
//            for(int i = 0;i < fake;i++){
//                if(temp.data!=data)
//                    temp=temp.next;
//                else
//                    break;
//            }
//            return temp;
//        }
//    }

        if(fake==0)
            return null;
        while(fake!=0)
        {
            if(temp.data.equals(data))
            {
                break;
            }
            temp = temp.next;  //寻找下一个节点
            fake--;

        }
         return temp;
    }

小结一下:链表存储数据是无序的,和数组比起来它的优点是在进行删除和增加的时候更加方便,但是在修改数据方面稍有欠缺,每种数据结构都有自己的优缺点,至于再怎样选择更好的数据结构,则需要根据实际项目来选择。

下面是我的整体代码:

package twb2019_07_18;

/**
 * 用头插法简单的实现一个单向链表
 */
public class SingleLinknode {
    public Node head; //头节点
    public int size = 0;  //链表的长度

    public class Node{
        public Node next; //指向上一个节点
        public Object data; //存储的数据
    }

    /**
     * 在链表里添加数据.
     * @param s 输入的数据
     * @return 返回的数据
     */
    public Object addData(String s){
        Node newNode = new Node(); //新建一个节点(无论有无节点都要新建)
        if(size==0){         //如果链表内没有节点
            newNode.data = s; //将来的数据添加到新建的节点内
            head = newNode;  //将新建的节点赋为头节点
        }
        else{
                newNode.data = s; //将来的数据添加到新建的节点内
                newNode.next = head;//指向上一个数据
                head = newNode;//将新建的节点赋为头节点
        }
        size++;
        return head.data;
    }

    /**
     * 在链表里删除指定数据
     * @param obj  输入指定数据进行删除
     * @return  若删除成功则为真.反之则为假.
     */
    public boolean DeleteData(Object obj){
        Node forward = head;
        Node current = head;
        int tempSize = size; //链表长度
        if(tempSize==0){
            return false;
        }
        while(current.data!=obj){
        if(current.next == null)
            return false;
        else{
            forward = current;
            current = current.next;
        }
        }
        size--;
        return true;
    }

    /**
     * 在链表内查找指定的数据,若查找到了则返回该节点
     * @param data 输入需要查找的指定数据
     * @return  存储该数据的节点
     */
    public Node getData(Object data){
        Node temp = head;
        int fake = size;
//        if(fake==0)
//            return null;
//        else{
//            for(int i = 0;i < fake;i++){
//                if(temp.data!=data)
//                    temp=temp.next;
//                else
//                    break;
//            }
//            return temp;
//        }
//    }

        if(fake==0)
            return null;
        while(fake!=0)
        {
            if(temp.data.equals(data))
            {
                break;
            }
            temp = temp.next;  //寻找下一个节点
            fake--;

        }
         return temp;
    }

    /**
     * 更具指定位置的下标修改数据
     * @param index 需要修改的节点的下标.
     * @param object 需要修改的数据.
     */

    public void modifyData(int index,Object object){
        Node temp = head;
//        int fake = size;
        if(index == 0)
            System.out.println("下标必须大于0!");

        for(int fake = size;fake>0;fake--){
            if(fake == index){
                temp.data = object;
            }
            temp = temp.next;
        }

    }

    /**
     * 显示链表里的所有数据
     */
    public void displayAllDtat(){
        Node temp = head;
        int fake = size;
        while(fake!=0)
        {
            System.out.print("["+temp.data+"]"+"->");
            temp = temp.next;
            fake--;
            if(fake==1){
                System.out.println("["+temp.data+"]");
                break;
            }
        }

}

    /**
     * 返回头节点的数据
     * @return 返回的头节点内的数据
     */
    public Object getHeadNode(){
        return head.data;
    }
}

下面测试一哈子:

public class testNode {
    public static void main(String[] args){

        SingleLinknode sl = new SingleLinknode();
        //增加操作
        sl.addData("a"); 
        sl.addData("b"); 
        sl.addData("c");
        sl.addData("d");
        sl.addData("e");
        
        //显示操作
        sl.displayAllDtat();


        System.out.println(sl.DeleteData("a")); //删除操作
        System.out.println(sl.size);

        sl.displayAllDtat();

        System.out.println(sl.getData("c")); //查找操作

        sl.modifyData(3,"a"); //修改操作
        sl.displayAllDtat();
    }
}

显示结果:
在这里插入图片描述
好了,今天就先到这里,如果大家还有什么问题可以和我一起讨论一哈,贴一下联系方式,先吃个饭,有点饿~
QQ:1027759481
VX:a1027759481

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值