单链表部分基本方法实现代码详解
包含遍历单链表,获取链表长度,查找是否包含关键字key在单链表中,头插法,尾插法
public class MySingleList {
class ListNode{//内部类
public int val;
public ListNode next;
public ListNode(int val) {
this.val = val;
}
/* 在这里为ListNode类提供构造方法(public ListNode(int val, ListNode next))
是为了方便创建链表节点时能够同时初始化节点的值和指向下一个节点的引用。如果不提供构造方法,那么创建ListNode对象时,
你需要分别设置val和next的值,这可能会使代码变得冗长且容易出错。*/
}
public ListNode head;//头节点
/*必须定义在内部类外,因为它是我整个链表的头节点,而不是一个节点的头节点*/
//此处使用这种方式创建链表是为了初学者能够更加清楚它的组成结构
public void createList(){
ListNode node1=new ListNode(12);
ListNode node2=new ListNode(32);
ListNode node3=new ListNode(44);
ListNode node4=new ListNode(55);
ListNode node5=new ListNode(77);
//创造出五个节点,但还没有赋予它们联系
//创造联系,让node中的next指向下一节点
node1.next=node2;
node2.next=node3;
node3.next=node4;
node4.next=node5;
//创造出五个节点的链表,每个节点中的next都指向下一节点
this.head=node1;//node1为此链表的头节点
}
//遍历链表
public void show(){
//链表从头往后,打印val值
ListNode cur=head;
//cur-头节点的“替身”,链表头节点不断发生变化不太合适
while(cur!=null){
/*当cur==null时,说明已经遍历到了链表的最后一个节点,停止循环*/
System.out.printf(cur.val+" ");
cur=cur.next;//每打印好当前节点,去往下一节点
}
//整个循环体完成打印当前节点val>>去往下一节点>>打印当前节点...以此类推直至打印完链表中所有节点
System.out.printf("\n");
}
//获取单链表的长度
public int size(){//获取长度,返回值为整型
/*思想类似遍历,引入计数器,每遍历一个节点,计数器++*/
int count=0;//计数器
ListNode cur=head;
while(cur!=null){
/*当cur==null时,说明已经遍历到了链表的最后一个节点,停止循环*/
count++;
cur=cur.next;//每打印好当前节点,去往下一节点
}
return count;
}
//查找是否包含关键字key在单链表中
public boolean comtains(int key){
ListNode cur=head;
/*遍历,逐一检查当前节点是否==key*/
while (cur!=null){
if(cur.val==key){
return true;//布尔类型返回真假
}
cur=cur.next;//每检查好当前节点,去往下一节点
}
//循环结束,相当于遍历完了整个链表仍旧没有找到key,则当前链表不包含key
return false;
}
//头插法
public void addFirst(int data){
//注意!头插法是插入了新的结点作为头节点,而不是直接修改原来头节点的val值
ListNode node=new ListNode(data);//new出新的节点
node.next=head;//新节点指向原头节点
head=node;//新节点为新的头节点
}
//尾插法
public void addLast(int data){
/*尾插法,突破点在于找到最后一个节点*/
ListNode node=new ListNode(data);//new出新的节点
if(head==null){//如果一个节点也没有
//使用头插法
head=node;//新节点为新的头节点
}
ListNode cur=head;
//cur-头节点的“替身”,链表头节点不断发生变化不太合适
while(cur.next!=null){
cur=cur.next;//去往下一节点
}
/*循环结束,此时cur已经到了最后一个节点位置*/
cur.next=node;//cur指向尾插节点
}
//任意位置插入
public void add(int index,int data){//提供插入位置下标index和val值
/*突破点在于找到index-1的位置*/
ListNode node=new ListNode(data);//new出新的节点
//判断index位置及要插入位置合法性
if(index>size()||index<0){
throw new IndexOutOfBounds("index位置不合法\n");//自定义抛错,也可用printf自己简单表示
}
if(index==0){
addFirst(data);//头插
return;
}
if (index==size()){
addLast(data);//尾插
return;
//头插尾插详情可见本人数据结构专栏
}
//找到index-1节点位置
ListNode cur=findIndex(index);
// 插入
node.next=cur.next;
cur.next=node;
}
private ListNode findIndex(int index){//寻找index-1节点
ListNode cur=head;//遍历
while(index-1!=0){//从头开始找index-1节点位置
cur=cur.next;
index--;
}
return cur;//此时的cur就是index-1的节点
}
//删除第一次出现关键字为key的节点
public void remove(int key){
/*突破点在于需要删除节点的前驱*/
ListNode prev=searchPrev(key);//prev-前驱
if(prev==null){
System.out.printf("没有你要删除的数字\n");
return;
}
ListNode del=prev.next;
prev.next=del.next;//相当于通过改变next指向,直接跳过了要删除的节点完成删除
}
private ListNode searchPrev(int key){//寻找前驱
ListNode prev=head;//从头到尾,开始寻找前驱
while(prev.next!=null){
if(prev.next.val==key){
return prev;
}else {
prev=prev.next;//前往下一节点继续寻找
}
}
return prev;
}
//删除所有值为key的节点
public void removeAllKeys(int key){
if (head==null) {
return;//链表中没有元素
}
if(head.val==key){
head=head.next;
}
ListNode cur=head.next;//cur为要删除元素
ListNode prev=head;
while(cur!=null){
if(cur.val==key){
//执行删除
prev.next=cur.next;
cur=cur.next;
}else {
prev=cur;
cur=cur.next;//prev和cur同时移动
}
}
}
}
//清除链表
public void clear(){
while (head!=null){
ListNode headNext=head.next;
head.next=null;
}
}
}