概念:链表是有序的列表,在内存中存储如下:
小结:
(1)链表是以节点的方式来存储,是链式存储
(2)每个节点包含data域、next域(用于指向下一个节点)
(3)链表每个节点不一定是连续存储
(4)链表分带头节点和不带头节点链表(根据需求确定)
单链表(带头节点)逻辑结构示意图:
单链表的创建:(不考虑节点顺序)
示意图:
步骤:
1、先创建一个Head节点,作用就是表示单链表的头
2、后面没添加一个节点,就直接加入到链表的最后
3、遍历:通过一个辅助变量帮助遍历整个单链表
单链表节点添加(按节点顺序)
步骤:
1、首先找到新添加的节点的位置,通过辅助变量(temp),遍历找到
2、新的节点.next=temp.next
3、temp.next=新节点
删除节点
步骤:
1、先找到需要删除的这个节点的前一个节点temp
2、temp.next=temp.next.next
3、被删除的节点,将不会在有其他引用的指向,会被垃圾回收机制回收
代码实现:
public class SigleLinkedList {
//创建头结点。表示链表的头
private Node Head=new Node(0,"","");
//AddNode1:添加节点到单链表的尾部
//思路:当不考虑节点顺序
//1、找到链表的最后一个节点
//2、将最后这个节点的Next指向新节点
public void AddNode1(Node node) {
//因为头节点不能动,所以需要一个辅助节点遍历
Node temp=Head;
while(true) {
//找到链表的最后一个节点
if(temp.next==null) {
break;
}
//否则temp=temp的下一个节点
temp=temp.next;
}
//循环出来之后,temp是最后一个节点
temp.next=node;
}
//AddNode2:添加节点,按顺序
public void AddNode2(Node node) {
//因为头结点不能动,所以需要一个辅助节点遍历,找到添加新节点的位置
Node temp=Head;
boolean flag=false; //用于标识链表中是否已经存在新节点的顺序
while(true) {
//如果该节点是最后一个节点,则新节点添加到最后一个位置
if(temp.next==null) {
break;
}else if(temp.next.number>node.number) { //说明找到了添加新节点的位置
break;
}else if(temp.next.number==node.number) { //说明新节点的顺序已经存在在链表中
flag=true;
}
temp=temp.next;
}
if(flag) {
System.out.println("该节点的顺序已经存在,插入失败");
}else {
//则说明新节点在链表中不存在,插入新节点
//新节点的下一个节点=辅助节点的下一个节点
node.next=temp.next;
//辅助节点的下一个节点=新节点
temp.next=node;
}
}
//删除节点
public void remove(Node node) {
if(Head.next==null) {
System.out.println("链表为空!");
return;
}
//创建辅助节点
Node temp=Head;
boolean flag=false; //标识是否找到了要删除的节点
while(true) {
if(temp.next==null) { //遍历完链表了
break;
}else if(temp.next.number==node.number) { //找到要删除的节点了
flag=true;
break;
}
temp=temp.next;
}
if(flag) { //链表中存在要删除的节点
temp.next=temp.next.next;
}else {
System.out.printf("不存在编号为%d的节点",node.number);
}
}
//修改节点,按照节点的Number来修改
public void update(Node newNode) {
if(Head.next==null) {
System.out.println("链表为空!");
return;
}
//创建辅助节点,对链表遍历,知道找到等于修改节点的number的时候
Node temp=Head.next;
boolean flag=false; //用来标识是否找到了修改节点的Number
while(true) {
if(temp==null) { //则已经遍历完链表
break;
}
if(temp.number==newNode.number) {
flag=true;
break;
}
temp=temp.next;
}
if(flag) {
temp.name=newNode.name;
temp.nickName=newNode.nickName;
}else {
System.out.printf("没有找到编号为%d的节点",newNode.number);
}
}
//展示链表
public void show() {
if(Head.next==null) {
System.out.println("链表为空!");
return;
}
//因为头节点不能动,所以通过辅助节点遍历链表
Node temp=Head.next;
while(true) {
//判断是不是最后一个节点
if(temp.next==null) {
System.out.println(temp);
break;
}
System.out.println(temp);
//temp指向下一个节点
temp=temp.next;
}
}
}
//创建节点
class Node{
public int number;
public String name;
public String nickName;
public Node next; //指向下一个节点
//构造器
public Node(int number,String name,String nickName) {
this.number=number;
this.name=name;
this.nickName=nickName;
}
@Override
public String toString() {
return "Node [number=" + number + ", name=" + name + ", nickName=" + nickName + "]";
}
}
检验:
public static void main(String[] args) {
// TODO 自动生成的方法存根
Node node1=new Node(1,"宋江","及时雨");
Node node2=new Node(2,"卢俊义","玉麒麟");
Node node3=new Node(3,"吴用","智多星");
Node node4=new Node(4,"林冲","豹子头");
//创建一个链表
SigleLinkedList linkedList=new SigleLinkedList();
linkedList.AddNode2(node1);
linkedList.AddNode2(node3);
linkedList.AddNode2(node4);
linkedList.AddNode2(node2);
linkedList.show();
System.out.println("------------");
linkedList.remove(node1);
linkedList.show();
}
结果:
Node [number=1, name=宋江, nickName=及时雨]
Node [number=2, name=卢俊义, nickName=玉麒麟]
Node [number=3, name=吴用, nickName=智多星]
Node [number=4, name=林冲, nickName=豹子头]
Node [number=2, name=卢俊义, nickName=玉麒麟]
Node [number=3, name=吴用, nickName=智多星]
Node [number=4, name=林冲, nickName=豹子头]