本篇博客将介绍以下内容:
-什么是java链表,它有什么特点?
-java链表基本功能的实现方法
-什么是泛型?泛型有什么用?
链表介绍
- 链表是一种储存数据的结构。我们常用的数组的储存空间是连续的,而链表的储存空间是离散的、不连续的。链表的不连续的特点使得链表的使用比数组更加灵活,且不用在最开始定义其大小。
- 从上图中我们可以看到,除头尾结点外,每一个节点都由数据域和指针域两部分组成。数据域用于存放需要的数据,指针域存放下一个节点的位置。当我们需要寻找链表上的某一个节点时,我们需要头节点位置以及目标节点的相对位置,然后从头节点开始逐个节点地向后寻找,直到找到目标节点。(因为单向链表中每个节点只知道下一个节点的位置,所以不能够跳过任何一个节点,只能逐个往后找)
- 现在我们大致了解了链表的结构,如果要实现链表的功能,我们首先需要创建一个Node类,用于存放数据和存储下一个节点的位置。
public class Node<E>{//这里的E是指泛型,后面有讲解
//数据
E data;
//下一个节点
Node<E>next;
//要往节点中存入数据时调用此方法
Node(E data){this.data=data;}
//创建首个头节点时调用此方法
Node(){}
}
泛型
当我们想要往链表中存放数据,但 暂时还不知道需要放什么数据类型 时,可以用泛型来暂时代替我们将来可能要放置的类。所以说泛型可以指代任何类,具体指代什么类,在使用它的时候才需要去定义。比如说在上面的例子中,我们创建一个Node对象的时候就需要将泛型定义为我们需要用的类。Node<Integer> head()=new Node();
就可以创建一个存放Integer的节点。泛型用大写字母表示,常用的字母有E(代表element)、K(代表key)和V(代表value)。
创建链表
- 在链表创建之初,我们先要定义链表的头节点和尾节点,因为此时链表中还没有数据,头节点和尾节点均为空,且头节点和尾节点是同一个节点。然后我们还要定义链表的长度,初始值为0。
public class LinkList<E> {
private Node<E> head,tail;//创建头尾节点
private int size;
public LinkList(){
size=0;
head=new Node<>();
tail=head;
}
链表提供的基本功能应该有:查询链表长度、获取链表某个位置的元素、往链表末尾添加元素、修改链表某个位置的元素、删除链表某个位置的元素、向指定位置插入一个元素。下面我们来逐一实现。
查询长度及元素
查询操作不需要对链表进行修改,相对来说比较简单。其中查询长度只需要返回我们链表的size值就可以了。
public int size(){
return size;
}
查询链表某个位置的元素,就像前面说到的我们只知道目前节点的下一个节点是什么,所以我们需要逐个逐个节点的往后寻找。
public E get(int index){
if(index>=0&index<=size-1){//先判断链表是否为空或索引是否超出链表长度范围
Node<E>temp=head.next;
//因为头节点是不储存数据的,从头节点的后一个节点才开始储存数据
//所以我们需要从头节点的后一个节点遍历链表
for(int i=0;i<index;i++){
temp=temp.next;
}
return temp.data;
}else{
System.out.println("索引超出表格范围!");
return null;
}
}
添加元素
public void add(E e){
Node<E>node=new Node<>(e);//创建新节点存放元素
tail.next=node;//把该节点放到原尾节点的最后
tail=node;//把新节点定义为尾节点
size++;//更新长度
}
修改元素
修改元素和查询元素相似,只是修改元素多了一步修改指定位置的数据,且修改元素的方法不设返回值。
public void set(int index,E e){
if(index>=0&index<=size-1){
Node<E>temp=head.next;
for(int i=0;i<index;i++){
temp=temp.next;
}
temp.data=e;//将该节点的元素更新
}else{
System.out.println("索引超出表格范围!");
}
}
删除元素
删除元素是稍微复杂一些的操作,我们来看一下示意图
我们需要找到需要删除的节点的前一个节点和后一个节点,然后对这两个节点进行连结。
public void del(int index){
if(index>0&index<=size-1){
Node<E>temp1=head.next;//从头节点的后一个节点开始遍历
Node<E>temp2,temp3;
for(int i=0;i<index-1;i++){
temp1=temp1.next;//找到需删除的节点的前一个节点
}
temp2=temp1.next;//temp2即为需要删除的节点
temp3=temp2.next;//找到需要删除的节点的后一个节点
temp1.next=temp3;//将节点1和节点3进行连结
size--;//删除操作完成后记得更新链表长度
}else{
System.out.println("索引超出表格范围!");
}
}
插入元素
public void input(int index,E e){
if(index>=0&index<=size-1){
Node<E>temp=head.next;
Node<E>temp2=new Node<>(e);//需要插入的新节点
for(int i=0;i<index;i++){
temp=temp.next;//找到需要插入的位置(新节点插入于该节点之后)
}
temp.next=temp2;
temp2.next=temp.next;//此处的temp.next请看示意图
size++;//插入操作完成后记得更新链表长度
}else{
System.out.println("索引超出表格范围!");
}
}
测试一下
public static void main(String[]arguments){
LinkList<Integer> linkList=new LinkList<>();//创建一个存放Integer的链表
for(int i=0;i<10;i++){
linkList.add(i);//往链表中加入10个元素
}
linkList.del(5);//删除链表中的第6个元素
linkList.set(2,88);//将链表中第3个元素更改为88
linkList.input(3,77);//在链表第4个元素的后面插入一个元素
for(int i=0;i<linkList.size();i++){//将操作后的链表逐一输出
System.out.println(linkList.get(i));
}
}
运行结果
完整代码
public class LinkList<E> {
private Node<E> head,tail;
private int size;
public LinkList(){
size=0;
head=new Node<>();
tail=head;
}
public int size(){
return size;
}
public void add(E e){
Node<E>node=new Node<>(e);
tail.next=node;
tail=node;
size++;
}
public void del(int index){
if(index>0&index<=size-1){
Node<E>temp1=head.next;
Node<E>temp2,temp3;
for(int i=0;i<index-1;i++){
temp1=temp1.next;
}
temp2=temp1.next;
temp3=temp2.next;
temp1.next=temp3;
size--;
}else{
System.out.println("索引超出表格范围!");
}
}
public E get(int index){
if(index>=0&index<=size-1){
Node<E>temp=head.next;
for(int i=0;i<index;i++){
temp=temp.next;
}
return temp.data;
}else{
System.out.println("索引超出表格范围!");
return null;
}
}
public void set(int index,E e){
if(index>=0&index<=size-1){
Node<E>temp=head.next;
for(int i=0;i<index;i++){
temp=temp.next;
}
temp.data=e;
}else{
System.out.println("索引超出表格范围!");
}
}
public void input(int index,E e){
if(index>=0&index<=size-1){
Node<E>temp=head.next;
Node<E>temp2=new Node<>(e);
for(int i=0;i<index;i++){
temp=temp.next;
}
temp2.next=temp.next;
temp.next=temp2;
size++;
}else{
System.out.println("索引超出表格范围!");
}
}
class Node<E>{
//数据
E data;
//下一个节点
Node<E>next;
Node(E data){
this.data=data;
}
Node(){}
}
public static void main(String[]arguments){
LinkList<Integer> linkList=new LinkList<>();
for(int i=0;i<10;i++){
linkList.add(i);
}
linkList.del(5);
linkList.set(2,88);
linkList.input(3,77);
for(int i=0;i<linkList.size();i++){
System.out.println(linkList.get(i));
}
}
}