一.链表与数组的区别
数组:
1)需要一块连续的内存空间,定义之后,长度不可变
2)数组根据下标来操作,在添加/获取数据时比较快
3)数组在插入/移除数据时,其后的元素下标全部需要改变,会比较麻烦
链表:
1)不需要连续的内存空间,通过节点相连,长度可变
2)插入/移除数据比较快,头/尾添加数据比较快
二.链表与节点
1)n个节点连接成一个链表,一个节点由指针域和数据域构成
2)链表用于管理节点
三.节点类
class Node<E>{ public E e; //保存数据 public Node next; //保存下一个节点 public Node(E e){ this.e= e; } public Node(){ } }
四.链表初始化
代码实现如下
public class LinkList<E> { private Node root; //保存链表的头节点 private Node last; //记录链表的尾节点 private int size = 0; //记录节点个数 //初始化root public LinkList() { root = new Node(); }
五.链表中的常用方法
1、add,即添加链表节点
添加节点首先要定义一个新的节点保存要添加的数据,接着将其添加到目标位置
添加时要注意当前链表是否有节点,分情况进行判断,当没有节点时所添加节点既是头节点也是尾节点
每添加一个节点,链表的节点个数要增加1
代码及其注释如下:
//末尾添加,头部添加,插入 public void add(E e) { //创建节点对象,保存数据 Node node = new Node(e);//建立一个node节点保存添加的数据 //取出头节点 Node head = root.next;//头节点命名为head(复制给head) if (head == null) { //当前头节点不存在,把node作为头节点 root.next = node;//node既是头节点也是尾节点 last = node; //只有一个节点的情况下,头节点 尾节点是同一个 } else { //保存到尾节点 last.next = node;//添加到尾节点后面 //更新当前节点为尾节点 last = node; } size++;//节点个数自增1 }
2、remove即移除,就是移除链表中的节点,包括移除指定数据节点和移除指定位置节点
(1)移除指定位置节点
注意要对节点位置进行判断,当节点位置下标index<0或位置下标超过节点个数index>=size时,无法进行移除操作,当节点位置合法时才能进行移除操作
代码实现及注释如下:
public E remove(int index) { if (index < 0 || index >= size) { System.out.println("超出范围...."); return null; } //取出头节点为当前节点 Node curr = root.next;//curr为当前节点保存头节点 //如果删除头节点 if (index == 0) { root.next = curr.next;//当前节点是头节点,把当前节点的下一个节点保存到当前节点即头节点 size--; return (E) curr.e; } else { //找到被删除节点的上一个节点 for (int i = 0; i < index - 1; i++) { curr = curr.next; //遍历链表 } //rNode是被删除节点 Node rNode = curr.next; //让当前节点保存被删除节点的下一个节点 curr.next = rNode.next;//这一步实现了删除节点 size--;//节点个数减一 return (E) rNode.e; } }
(2)removes移除指定数据
该方法就是将链表中的某一具体数据移除,遍历链表,在找到所要移除的数据的节点后调用上面的remove方法
代码实现及注释如下:
public boolean removes(E e){ int index=0; Node curr=root.next;//当前节点保存头节点(从头节点开始遍历) while(curr.e!=e&&curr!=null){ curr=curr.next; //当 当前节点 的数据不是要删除的或者不为空时把当前节点的下一个保存到当前节点(依次前移1位覆盖被删除节点) index++;//从前往后遍历节点 } remove(index);//调用移除方法 if(index<0){ return false; } return true; }
3.get获取数据
该方法指的是获取链表中指定节点的数据,那么我们就要遍历链表找到该位置,然后返回当前节点的数据,注意节点下标不能小于0或超过链表中节点个数,要对节点下标index进行判断
代码实现及注释如下:
public E get(int index){ if(index < 0 || index >= size ){ System.out.println("超出范围...."); return null; } //取出头节点作为当前节点 Node curr = root.next; for(int i=0;i<index;i++) { //节点后移 curr = curr.next; } return (E) curr.e;//返回数据 }
4.链表反转
链表是具有方向的,由头节点指向下一个节点,并依次指向下一个节点,直到指向尾节点结束
链表反转就是改变链表的方向,反转后尾节点变成头节点,头节点变成尾节点
代码实现及注释如下:
public void reverList(){ Node prev=null;//建立一个新节点(空节点) Node curr=root.next;//当前节点保存头节点 while(curr!=null) { Node nextNode=curr.next;//建立一个新节点nextNode保存当前节点的下一个节点 curr.next=prev;//节点反转,第一个和最后一个互换 //节点后移 prev=curr; curr=nextNode; } root.next=prev;//更新链表的头节点 }
5.size打印节点个数
在链表初始化时已经定义了节点个数size,在测试类中添加节点类后size已经保存了节点的个数
所以我们直接返回size即可
代码实现及注释如下:
public int size(){ return size; }
六.测试类
public static void main(String[] args) { LinkList link = new LinkList(); link.add(1); //添加节点 link.add(2); link.add(3); link.reverList(); //链表反转 link.removes(2); //移除指定数据 link.remove(0); //移除指定位置 link.size(); //节点个数 for(int i=0;i<link.size();i++){ System.out.println(link.get(i));//获取数据 } }