单链表的简述和方法原理

本文介绍了单链表的概念,包括链表的定义、特点和单链表的结构。对比了数组的缺点,强调链表在插入和删除操作上的优势。文章详细讲解了单链表的节点定义、头节点的作用,并提供了插入、遍历、查找和删除等操作的解析。

内容概述

  • 1、什么是链表

引子

class Stu{   创建Stu表
     String id;
     String name;
     Teacher teache;  在Stu表中创建Teacher类型的变量
}
class Teacher{
    String id;
}
public static void main(String[] args){
    Teacher t = new Teacher();
    Stu s = new Stu();
    s.teacher = t ; //调用Stu类型中的Teacher类型的teacher
}

接下来我们进行内存分析:
在这里插入图片描述
引子2

class Stu{   创建Stu表
     String id;
     String name;
     Stu next; 创建一个自己类型的next
}
public static main(String[] args){
    Stu s0 = new Stu();
    s0.next=new Stu();
    s0.next = new Stu();
    //反复调用自己的Stu类型定义的next
}

接下来我们来看看内存分析
在这里插入图片描述原来是这样,当s0.next的时候会进入下一个Stu对象(我们应称之为节点),然后再反复调用再到下一个。

单链表结点定义规范化
在这里插入图片描述定义一个Node类来规范化,并加上泛型。

//当我们使用命令 
Node current = node0;

在这里插入图片描述

//继续向下执行
Node current = current.nex

在这里插入图片描述
链表的最后一个节点为null,so

Node current = node0;
while(current!=null){ //当current不等于null的时候说明链表没有遍历完全
    current = current.next;//继续执行下一个节点
}

引入头节点

什么叫头节点?
规定单向链表中的第一个节点的数据与为空,真正的节点从第二个结点开始,单链表使用头节点是为了方便数据维护。
在这里插入图片描述有头节点的单链表的比遍历代码

Node current = head.next;//需要指向头节点的下一个节点,从第二个节点开始
//因为第一个节点的值为null
while(current!=null){
    current = current.next;
}

上面简单的介绍了一下单链表的定义和规则,接下来我们来对比一下数组!

数组的缺点

一、数组是很有用的数据结构,但是又两个局限性:
(1)若改变数据的大小,需要创建一个新数组并从原数组中拷贝所有数组至新数组
(2)数组数据在内存中依次连续存储,向数组中插入一项要移动数组中的其他数据。

链表的概念
一、链表这种数据结构是使用指针(即引用)将存储数据元素的那些单元依次串联再一次。这种方法避免了在数组中用连续的单元存储元素的缺点。因而在插入或者删除时不再需要移动元素来腾空出空间或填补空缺。。
二、需要做出的改变就是每个单元中设置指针(即引用),来表示表中元素之间的逻辑关系(前还是后)。因此每个单元至少有两个域,一个用于数据元素的存储,一个用于指向其他单元的指针。这种具有一个数据域和多个指针域的存储单元称为节点(Node)
三、链表的特点就是:查询效率低,增删效率搞,线程不安全。
在这里插入图片描述
单链表的概念
一、单链表的每个节点只有一个指向表中下一个节点的指针。第一个节点称为头节点,头节点的特征是数据域为空(null),最后一个称为尾节点,尾节点的特征是next引用为空(null)。
二、单链表的一个重要特征是只能通过前驱节点找到后续节点,而无法从后续节点找到前驱节点。
三、因此在单链表中进行查找操作,只能从链表的首节点开始,通过每个节点的next引用来依次访问链表中的每个节点以完成相应的查找操作。
四、为使程序更简洁,通常在单链表的最前面添加一个哑元节点,也成为头节点(Head),注意:有别于真正的首节点,头节点中部存储任何实质的数据对象,其next通常指向第一位真正存储数据的元素。

单链结点的定义

public class Node<T>{
    T  date;
    node<T> next;
    public Node(T date,Node<T> next){
        super();
        this.date = date;
        this.next = next;
    }
    public Node(T date){
        super();
        this.date = date;
        
    }
    public Node(){
        super();
    }
    public T getDate(){
        return date;
    }
    public void setDate(T date){
        this.date = date;
    }
    public Node getNext(){
        return next;
    }
    public void setNext(Next<T> next){
        this.next = next;
    }
    @Override
    public String toString(){
        return "Node [date = "+date+",next="+next+"]";
    }  
    @Override
    //重写equals方法
    public boolean equals(Objext obj){
        if(this == obj)
        return true;
        if(obj==null)
        return false;
        if(getClass()!=obj.getClass()) //比较类的类型是否相同,不相同返回false
        return false;
        Node<T> other =(Node<T>)obj; //上面条件成立了以后可以进行赋值
        if(date == null){
            if(other.date !=null){
                return false;
            }else if (!date.equals(other.date))
            return false;
            return ture; 
         }
      
    }
}

再定义个实现Node功能类Link

public class Link<T>{
    Node<T> head;
    public Link(){
        super;
        head = new Node<T>();
    }
    //追加功能
    //循环结执行完毕后,lp.next为null,lp指向最后一个结点
    public void appand(Node<T> node){
        if(node==null)
        return;
        Node<T>lp = head;
        while(lp.next!=null)
        {
            lp = lp.next;
        }
        lp.next =node;
    }
    //查找功能
    public Node<T> find(Node node){
        Node<T>  move = head.next;
        while(move!=null){
            if(move.equals(node))
            return move;
            move=move.next;
        }
        return null;
    }
    //访问所有元素
    //循环执行完毕以后,lp为null
    public void visiAll() {
        Node<T> lp = head.next;
        while(lp!=null){
            System.out.println(lp.data);
            lp=lp.next;
        }
    }
    //访问所有元素
    //循环执行完毕以后,lp.next为null,lp指向最后一个结点
    public void visiAll2(){
        Node<T> lp = head;
        while(lp.next!=null){
            lp = lp.next;
            System.out.println(lp.data);
        }
    }
    //在最前面插入元素
    public void insetFirst(Node<T> node){
        node.next = head.next;
        head.next = node;
    }
    //删除元素
    public void remove(Node<T> node){
        Node<T> prior = head;  
        Node<T> current = head.next; //指向第一个节点
        while(current!=null)  //判断current节点是否为空 不为空则进行循环
        {
            if(current.equals(node)){  //判断current的元素是否与node相同
                prior.next = current.next; //如果相等则将current的下一个节点
                   retuern;  //结束        //next传给 prior.next
                                            //所以current就被删掉了
            }
            //否则继续向下执行
            prior=prior.next;
            current = current.next;
        }
    } 
    //在某个节点前面插入元素
    public boolean inset(Node<T> newNode,Node<T> node){
      Node<T> prior = head;
      Node<T>current = head.next;
      while(current!=null) //循环,直至current等于空
      {
          if(current.equals(node)){ //判断current是否与传进来的node相等
             //相等则执行将current节点位置传给newNode的下一个节点
               newNode.next = current; 
              //然后将newNode当前节点传给current的上一个节点。
              prior.next = newNode;
              //插入成功返回true
              return true;
          }
          //否则继续向下一个节点前进
          prior = prior.next;
          current = current.next;
      }
       //都不成立返回false
       return false;
    
    } 
}

主函数:

ublic static void main(String[] args) {
		 
		Link<Integer> link = new Link<Integer>();
		link.insertFirst( new Node<Integer>(1)  );
		link.insertFirst( new Node<Integer>(2)  );
		link.insertFirst(new Node<Integer>(3)  );
		link.insertFirst(new Node<Integer>(4)  );
		link.insertFirst(new Node<Integer>(5)  );
		link.remove(new Node<Integer>(1));
		link.remove(new Node<Integer>(5));
		link.visitAll();
		link.insert( new Node<Integer>(5),new Node<Integer>(4));
		link.visitAll();
		System.out.print(link.find(new Node<Integer>(5)));
		System.out.print(link.find(new Node<Integer>(1)));
	 

		
	}

}

每个功能的详细解析
insetFirst方法解析(前插法):
在这里插入图片描述
visiAll方法解析(遍历方法1):
在这里插入图片描述
以下步骤与上头基本一致

visiAll2方法解析(遍历方法2):
在这里插入图片描述
find方法(单链表种查找某个元素)
在这里插入图片描述
appand方法(单链表的最后添加元素,尾插法)
在这里插入图片描述在这里插入图片描述
remove方法解析(单链表中删除某个元素)

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
insert方法解析(在某个位置的前面插入某元素)
在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值