内容概述
- 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万+

被折叠的 条评论
为什么被折叠?



