链表是以节点的方式来存储,是链式存储
每个节点包含data域,next域,指向下一个节点
如图,发现链表的各个节点不一定是连续存储
链表分带头节点和不带头节点链表,根据实际的需求来确定
链表主要的操作就是增删查改,还有逆序输出。
添加(创建)
1.先创建一个head头节点,作用就是表示单链表的头
2.后面我们每添加一个节点,就直接加到链表最后
遍历:
通过一个辅助变量,帮助遍历整个链表
public void printList(){
HeroNode temp = head.next;
while (true){
if (temp == null){
break;
}
System.out.println(temp);
temp = temp.next;
}
}
插入:
按照有序加入节点:
首先找到新添加节点的位置,通过辅助变量指针来实现,
新的节点.next = temp.next;
将temp.next = 新的节点
插入一个节点:
//添加节点到单链表
//思路
//1.找到这个链表的最后节点
//2.将最后这个节点的next指向新的节点
public void add(HeroNode heroNode){
//因为head节点不可以动,所以我们添加一个辅助遍历temp
HeroNode temp = head;
//遍历链表找到最后
while (true){
//判断是否是最后一个节点
if (temp.next == null){
break;//找到最后节点就退出
}
temp = temp.next;//不是最后一个节点就往后移
}
temp.next = heroNode;//推出循环以后就将temp指向链表最后,然后就将传入的节点加入到链表最后
}
按照节点顺序添加节点
//按照顺序添加节点
public void addByOrder(HeroNode heroNode){
//头节点不可以动,通过辅助指针来遍历
//我们的temp要位于添加位置的前一个节点,否则插入不了
HeroNode temp = head;
boolean flag = false;
while (true){
if (temp.next == null){
break;
}
if (temp.next.no > heroNode.no){
break;
}else if (temp.next.no == heroNode.no){
flag = true;
break;
}
temp = temp.next;
}
if (flag){
System.out.printf("该编号%d已经存在,不可以插入\n",heroNode.no);
}else{
heroNode.next = temp.next;
temp.next = heroNode;
}
}
删除
删除比较简单
只要将要删除前面的那个节点的next指向删除节点的next,这就实现了删除。
//删除节点
//我们需要找到要删除节点的前一个节点,然后删除节点
public void del(int no){
//判断链表是否为空
if (head.next == null){
System.out.printf("链表为空\n");
return;
}
HeroNode temp = head;
boolean flag = false;//标志是否找到要删除的节点
while (true){
if (temp.next == null){//已经到节点最后
break;
}
if (temp.next.no == no){
flag = true;
break;
}
temp = temp.next;
}
if (flag){
temp.next = temp.next.next;
System.out.printf("删除 %d 节点\n",no);
}else {
System.out.printf("删除失败\n");
}
}
修改:
//修改节点信息
public void update(HeroNode newHeroNode){
//先判断链表是否为空
if (head.next == null){
System.out.println("链表为空");
return;
}
//找到需要修改的节点,根据编号
HeroNode temp = head.next;
boolean flag = false;
while (true){
if (temp == null){
break;
}
if (temp.no == newHeroNode.no){
flag = true;
break;
}
temp = temp.next;
}
if (flag){
temp.name = newHeroNode.name;
temp.nickName = newHeroNode.nickName;
}else{
System.out.printf("编号为 %d 的节点没有找到\n",newHeroNode.no);
}
}
将单链表反装:
主要思路:
每遍历一个节点之后将节点放在链表最前面;
主要实现代码:
public static void reverseLinkedList(HeroNode head){
//判断链表是否为空
if (head.next == null){
System.out.print("链表为空");
return ;
}
HeroNode cur = head.next;//定义一个辅助指针,帮助我们遍历原来的链表
HeroNode next = null; //指向当前节点【cur】的下一个节点
HeroNode reverseHead = new HeroNode(0,"","");
//遍历原来的链表,每遍历一个节点,就将这个节点取出放入这个链表的最前面
while (cur != null){
next = cur.next;//先暂时保管下一个节点
cur.next = reverseHead.next;//将cur的下一个节点指向链表的最前端
reverseHead.next = cur;//将cur连接到新的链表上
cur = next;//让cur后移
}
head.next = reverseHead.next;//将head.next指向reverseHead.next,实现单链表的反转
}
查找单链表中的倒数第K个链表的节点
public static void findHeroNode(int k,HeroNode head){
//判断链表是否为空
if (head.next == null){
System.out.printf("链表为空\n");
return;
}
int length = getLength(head);//得到链表长度
HeroNode temp = head.next;
if (length < k || k < 0){
System.out.print("输入查找条件不正确");
return;
}
for (int i = 0; i < length - k; i++){
temp = temp.next;
}
System.out.print("倒数第"+k+"个节点为:"+temp);
}
得到链表长度
//得到链表的长度
//传入一个头节点
public static int getLength(HeroNode head){
if (head.next == null){
return 0;//链表为空
}
HeroNode temp = head.next;
int length = 0;
while (temp != null){
length ++;
temp = temp.next;
}
return length;
}
上面是单链表的一些基本操作
下面是完整的测试代码
package com.gsy.linkedlist;
import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;
import javax.rmi.ssl.SslRMIClientSocketFactory;
/**
* @program: DataStructures
* @description: 单链表
* @author: GSY
* @create: 2020-03-27 10:41
**/
public class SingleLinkedListDemo {
public static void main(String[] args){
HeroNode heroNode1 = new HeroNode(1,"武松","行者");
HeroNode heroNode2 = new HeroNode(2,"关羽","武圣");
HeroNode heroNode3 = new HeroNode(3,"花容","小李广");
HeroNode heroNode4 = new HeroNode(4,"林冲","豹子头");
HeroNode heroNode5 = new HeroNode(5,"卢俊义","玉麒麟");
SingleLinkedList singleLinkedList = new SingleLinkedList();
//插入测试
/* singleLinkedList.add(heroNode1);
singleLinkedList.add(heroNode2);
singleLinkedList.add(heroNode3);
singleLinkedList.add(heroNode4);
singleLinkedList.add(heroNode5);*/
//按照节点号码顺序插入
singleLinkedList.addByOrder(heroNode3);
singleLinkedList.addByOrder(heroNode5);
singleLinkedList.addByOrder(heroNode2);
singleLinkedList.addByOrder(heroNode1);
singleLinkedList.addByOrder(heroNode4);
singleLinkedList.printList();
HeroNode newHeroNode = new HeroNode(5,"卢哥","玉老虎");
singleLinkedList.update(newHeroNode);
System.out.printf("跟新之后\n");
singleLinkedList.printList();
singleLinkedList.del(1);
System.out.printf("删除节点之后\n");
singleLinkedList.printList();
System.out.printf("链表长度为%d\n",getLength(singleLinkedList.getHead()));
findHeroNode(1,singleLinkedList.getHead());
System.out.print("\n反向输出\n");
reverseLinkedList(singleLinkedList.getHead());
singleLinkedList.printList();
}
//得到链表的长度
//传入一个头节点
public static int getLength(HeroNode head){
if (head.next == null){
return 0;//链表为空
}
HeroNode temp = head.next;
int length = 0;
while (temp != null){
length ++;
temp = temp.next;
}
return length;
}
/*
* 查找单链表中的倒数第K个链表的节点
*
* */
public static void findHeroNode(int k,HeroNode head){
//判断链表是否为空
if (head.next == null){
System.out.printf("链表为空\n");
return;
}
int length = getLength(head);//得到链表长度
HeroNode temp = head.next;
if (length < k || k < 0){
System.out.print("输入查找条件不正确");
return;
}
for (int i = 0; i < length - k; i++){
temp = temp.next;
}
System.out.print("倒数第"+k+"个节点为:"+temp);
}
//将链表方向输出
public static void reverseLinkedList(HeroNode head){
//判断链表是否为空
if (head.next == null){
System.out.print("链表为空");
return ;
}
HeroNode cur = head.next;//定义一个辅助指针,帮助我们遍历原来的链表
HeroNode next = null; //指向当前节点【cur】的下一个节点
HeroNode reverseHead = new HeroNode(0,"","");
//遍历原来的链表,每遍历一个节点,就将这个节点取出放入这个链表的最前面
while (cur != null){
next = cur.next;//先暂时保管下一个节点
cur.next = reverseHead.next;//将cur的下一个节点指向链表的最前端
reverseHead.next = cur;//将cur连接到新的链表上
cur = next;//让cur后移
}
head.next = reverseHead.next;//将head.next指向reverseHead.next,实现单链表的反转
}
}
//定义SingleLinkedList来管理
class SingleLinkedList{
//先初始化一个头节点,头节点不要动,不存放具体的数据
private HeroNode head = new HeroNode(0,"","");
public HeroNode getHead() {
return head;
}
//添加节点到单链表
//思路
//1.找到这个链表的最后节点
//2.将最后这个节点的next指向新的节点
public void add(HeroNode heroNode){
//因为head节点不可以动,所以我们添加一个辅助遍历temp
HeroNode temp = head;
//遍历链表找到最后
while (true){
//判断是否是最后一个节点
if (temp.next == null){
break;//找到最后节点就退出
}
temp = temp.next;//不是最后一个节点就往后移
}
temp.next = heroNode;//推出循环以后就将temp指向链表最后,然后就将传入的节点加入到链表最后
}
//按照顺序添加节点
public void addByOrder(HeroNode heroNode){
//头节点不可以动,通过辅助指针来遍历
//我们的temp要位于添加位置的前一个节点,否则插入不了
HeroNode temp = head;
boolean flag = false;
while (true){
if (temp.next == null){
break;
}
if (temp.next.no > heroNode.no){
break;
}else if (temp.next.no == heroNode.no){
flag = true;
break;
}
temp = temp.next;
}
if (flag){
System.out.printf("该编号%d已经存在,不可以插入\n",heroNode.no);
}else{
heroNode.next = temp.next;
temp.next = heroNode;
}
}
//打印链表
public void printList(){
HeroNode temp = head.next;
while (true){
if (temp == null){
break;
}
System.out.println(temp);
temp = temp.next;
}
}
//修改节点信息
public void update(HeroNode newHeroNode){
//先判断链表是否为空
if (head.next == null){
System.out.println("链表为空");
return;
}
//找到需要修改的节点,根据编号
HeroNode temp = head.next;
boolean flag = false;
while (true){
if (temp == null){
break;
}
if (temp.no == newHeroNode.no){
flag = true;
break;
}
temp = temp.next;
}
if (flag){
temp.name = newHeroNode.name;
temp.nickName = newHeroNode.nickName;
}else{
System.out.printf("编号为 %d 的节点没有找到\n",newHeroNode.no);
}
}
//删除节点
//我们需要找到要删除节点的前一个节点,然后删除节点
public void del(int no){
//判断链表是否为空
if (head.next == null){
System.out.printf("链表为空\n");
return;
}
HeroNode temp = head;
boolean flag = false;//标志是否找到要删除的节点
while (true){
if (temp.next == null){//已经到节点最后
break;
}
if (temp.next.no == no){
flag = true;
break;
}
temp = temp.next;
}
if (flag){
temp.next = temp.next.next;
System.out.printf("删除 %d 节点\n",no);
}else {
System.out.printf("删除失败\n");
}
}
}
//定义一个HeroNode,每个HeroNode对象就是一个节点
class HeroNode{
public int no;
public String name;
public String nickName;
public HeroNode next;//指向下一个节点
//构造器
public HeroNode(int no,String name,String nickName){
this.no = no;
this.name = name;
this.nickName = nickName;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}