一、我对单链表的理解
链表就像一条链子,上面连接了一个个节点,每个节点存储着数据。
单链表是单向的,非循环的,每一个节点内都存放了数据和下一个节点的地址,一个接一个的连在一起,便有了下图这样的数据结构。
如下图所示:
二、单链表的创建
1)创建节点类
/先创建单链表上的节点
class Node{
public int data;
public Node next;//指向下一个节点,next内存储的是下一个节点的引用(地址),节点为Node型,所以next也应该是Node
public Node(int data) {
this.data = data;
}
//重写toString方法,输出链表数据
@Override
public String toString() {
return "Node{" +
"data=" + data +
'}';
}
}
2)创建链表类连接节点,链表的相关操作方法都在该类中
3)添加节点到链表,用尾插法
//添加节点到单链表,下面是尾插法
//1.找到当前单链表的最后节点
//2.让最后节点的next指向新的节点
public void add(Node node){
//head节点不能动,所以需要一个辅助变量temp
Node temp = head;
//遍历链表,找到尾节点
while (true){
//找到尾节点
if ( temp.next == null){
break;
}
//没找到的话就接着往后找,让temp后移
temp = temp.next;
}
//当退出while后,temp就指向最后节点
//将最后这个节点的next指向新的节点
temp.next = node;
}
4)打印链表
//打印链表(遍历)
public void list(){
//判断链表是否为空
if(head.next == null){
System.out.println("链表为空");
return;
}
//不为空,遍历链表
//head节点不能动,所以需要一个辅助变量temp
HeroNode temp = head.next;
while (true) {
//判断是否到链表最后
if (temp == null) {
break;
}
System.out.println(temp);
//temp后移
temp = temp.next;
}
}
5)指定位置插入节点
1、先找到要插入位置的前一个节点
2、要插入的节点node指向下一个节点temp.next
3、让前一个节点指向要插入的节点
//指定位置插入节点
//1.封装一个方法确定指定位置
//2.找到指定位置的前一个位置
private Node searchIndex(int index) {//封装一个方法用来找指定位置
if(index<0 || index>this.size())//判断位置合法性
{
throw new RuntimeException("index位置不合法");
}
Node temp = head;
int count = 0;
while (count != index-1)//找到指定位置的前一个位置,返回这个节点
{
count++;
temp = temp.next;
}
return temp;
}
//在指定位置int index添加节点
public void addIndex(int index,Node node) {
if(index==0) {//空链表直接插
this.add(node);
return;
}
if(index==this.size()) {//this.size()返回链表长度,位置为最后,直接调用尾插法
this.add(node);
return;
}
Node temp = searchIndex(index);//返回目标位置的前一个位置的节点
node.next=temp.next;//以下两步完成连接,一般都是先接上后边,如果这两步顺序调换,则无法完成连接
temp.next=node;
}
6)删除关键字
1、找到要删除节点的前一个节点ahead,temp就是要判断是否删除的节点
2、要删除时:让temp的前一个节点直接指向temp的下一个节点, 然后后移,这样temp没有其它引用指向,会被垃圾回收机制回收.
//删除关键字
public void removeAllKeys(int key) {
//因为删除一个节点需要前一个节点的连接,所以需要建立两个节点完成整个工程
Node ahead = this.head;//前一个节点
Node temp = ahead.next;//后一个节点(在temp中判断data是否与key相等),两个节点从头开始往后遍历
while (temp != null) {//当temp为空时完成遍历
if(temp.data == key) {//在temp中判断data是否与key相等,如果相等则删除
ahead.next = temp.next;//先完成连接
temp = temp.next;//连接完成后temp后移继续判断该temp.data是否为关键字,ahead不用动(因为已经删除该节点以后,只需temp后移,ahead仍为temp的前一个节点)
}else {//如果不相等,则两者均后移
ahead = temp;
temp = temp.next;
}
}
if(this.head.data==key) {//最后考虑头节点,如果相等再完成删除
this.head=this.head.next;
}
}