一、什么是单向链表
单向链表由一个个节点组成,头节点没有元素只有指向下一个节点的地址域,尾节点有元素但是指向地址域为null,其余的节点都有一个数据域和地址域,数据域用于存储数据,地址域用于指向下一个节点,第一个元素是头节点后的第一个节点内的数据;
链表和顺序表是不同的,顺序表有数组作为基础,存储空间连续,有索引可以实现快速查找,但是添加元素和删除元素效率较低;
链表不以数组作为基础,存储空间可以不连续,查找只能从头开始遍历,因此查找速度慢,但是添加和删除元素效率高。
二、java代码实现
package mypackage;
/**
* 单向链表的创建
* 要实现的功能包括:
* 初始化
* 返回长度,即节点个数
* 插入、删除节点
* 根据索引获取节点
* 根据节点获取索引
* 判断是否为空
*
* 单项链表的核心在于节点类,有了节点类,才能更好的表示节点之间的链接关系
*
* 注意,关于第i个节点的约定,第1个节点是头节点后的第一个节点,依次类推.
* 我们把第一个节点就称之为第一个节点,注意没有索引的概念
* 即使有索引的话,也是从1开始的,而不是从0开始的
*/
import java.util.Iterator;
//<T>泛型表示支持任意类型
class LinkList<T> implements Iterable<T>{
//记录头节点
private Node head;
//记录链表的长度,即节点的个数
private int N;
//定义节点类,这一步至关重要
//注意构造方法的参数有一个是next,这个类型是Node,正是我们定义的这个类Node
//这样的话,我们每个节点就可以传入一个参数,next,然后用当前结点调用.next属性就可以获得下一个节点
//这就是单项链表链接的核心
private class Node{
//数据项和下一个节点项
T data;
Node next;
//构造方法
public Node(T data, Node next){
this.data=data;
this.next=next;
}
}
//构造方法
public LinkList(){
//初始化头节点,初步的头节点的数据项和下一个节点项都是null,节点个数为0
//头节点的数据项本身就定义为null,他的作用只是指向链表的第一个由数据的节点而已
//尾节点的下一个节点项本身就定义为null,表示链表的结束
this.head=new Node(null,null);
this.N=0;
}
//清空链表,使得头节点不指向任何节点,且节点个数为0
public void clear(){
head.next=null;
this.N=0;
}
//获取节点个数
public int length(){
return N;
}
//判断链表是否为空
public boolean isEmpty(){
return N==0;
}
//直接在尾部添加节点
public void append(T data){
Node n=head;
//找到最后一个节点
while(n.next!=null){
n=n.next;
}
//创建新节点,最后一个节点的next=null
Node newnode=new Node(data,null);
//让当前借点指向新节点
n.next=newnode;
N++;
}
//向指定位置插入节点,使得这个位置之前的节点指向这个新节点,
//这个新节点指向这个位置的原本的那个节点
//其实就是先打断,再链接
//i第几个节点,和索引没有任何关系,链表没有索引的概念
public void insert(int i,T data){
//如果i==N就代表是要在最后添加
if(i==N){
Node n=head;
while(n.next!=null){
n=n.next;
}
//创建新节点,最后一个节点的next=null
Node newnode=new Node(data,null);
//让当前借点指向新节点
n.next=newnode;
N++;
}
//如果在非最后添加
else{
// 从头节点开始循环,循环一次,到第一个节点,循环第i-1次,循环到第i-1个节点
// 这就找到了第i-1个节点
Node prenode=head;
//找到待插入节点的前一个节点
for (int index=1;index<=i-1;index++){
prenode=prenode.next;
}
// 第i个节点
Node curnode=prenode.next;
// 创建新节点,并且新节点指向第i个节点
Node newnode=new Node(data,curnode);
//将前一个节点指向新节点
prenode.next=newnode;
}
}
//返回第i个节点的值
public T get(int i){
//从头节点向后循环找,循环1此找打第一个节点,循环i次找到第i个节点
Node n=head;
for (int index=1;index<=i;index++){
n=n.next;
}
//找到节点后,返回节点的数据
return n.data;
}
//删除指定位置节点,并返回删除的值
//删除后将指定位置的前一个节点指向后一个节点
public T remove(int i){
//如果删除最后一个节点,直接将最后一个节点的前一个节点next=null,并且N--
if(i==N){
Node prenode=head;
for (int index=1;index<=i-1;index++){
prenode=prenode.next;
}
// 最后一个节点
Node curnode=prenode.next;
// 使最后一个节点的前一个节点指向null
prenode.next=null;
N--;
// 返回最后一个节点的元素值
return curnode.data;
}
//如果删除非最后节点
else{
//找到i位置的前一个节点,删除后将指定位置的前一个节点指向后一个节点
Node prenode=head;
for (int index=1;index<=i-1;index++){
prenode=prenode.next;
}
// 指定节点
Node curnode=prenode.next;
// 指定节点的后一个节点
Node nextnode=curnode.next;
// 使得指定节点的前一个节点指向指定节点的后一个节点
prenode.next=nextnode;
N--;
// 返回指定节点的元素
return curnode.data;
}
}
//查找某个节点第一次出现的位置,即是第几个元素,从1开始
//循环查找,找到就返回,没找到就返回-1
public int indexOf(T data){
Node n=head;
for (int index=1;index<=N;index++){
n=n.next;
if(n.data.equals(data)){
return index;
}
break;
}
return -1;
}
//实现遍历
//遍历的话,要重写此方法
@Override
public Iterator<T> iterator() {
// 返回的Iterator对象,创建一个内部类实现这个接口
return new LIterator();
}
// 创建一个内部类实现Iterator接口
public class LIterator implements Iterator {
// 定义一个遍历的节点
private Node n;
public LIterator(){
// 初始化为0索引位置
this.n=head;
}
//重写两个方法
@Override
public boolean hasNext() {
// 这个方法判断是否超出最大索引,如果超出会停止遍历
return n.next!=null;
}
@Override
public Object next() {
// 这个方法会遍历得每个节点
n=n.next;
return n.data;
}
}
}
//测试
public class Test {
public static void main(String[] args) {
// 创建一个链表
LinkList<Object> list = new LinkList<>();
// 添加节点节点
list.append(1);
list.append(2);
list.append(3);
//开始遍历
for(Object ls:list){
System.out.println("遍历元素---"+ls);
}
// 返回节点个数
int length1 = list.length();
System.out.println("元素个数"+length1);
// 插入节点
list.insert(2, 100);
//开始遍历
for(Object ls:list){
System.out.println("插入节点后遍历元素---"+ls);
}
// 删除节点
Object remove = list.remove(1);
System.out.println("删除指定位置处的节点元素是"+remove);
//开始遍历
for(Object ls:list){
System.out.println("删除节点后遍历节点元素---"+ls);
}
// 返回第几个节点元素
System.out.println("第1个节点的元素是"+list.get(1));
// 返回某个值的位置
System.out.println("指定节点元素对应的位置为"+list.indexOf(100));
// 清空
list.clear();
// 是否为空
System.out.println("判断是否为空"+list.isEmpty());
}
}
结果: