链表介绍:
链表是一种非常使用的数据结构,它解决了数组的一些缺点,如数组一经定义,数组的大小就固定了,但在实际开发中,我们可能不确定数组的大小,更多是需要的是一种可以自动扩充的数据结构,而链表就可以很好的实现这一点,很多时候我们在做的事可能就是增删改查,大家都知道数组的增加和删除都需要大量移动数组中的元素,所以数组在增加和删除方面效率偏低,而链表很好的解决了这个问题,链表不需要移动元素便可完成增加和删除,所以链表这种数据结构显得非常重要
实现思路:
采用带一个头结点,尾插法实现,头节点知识表示链表的第一个位置,其中不存放数据,这样可以对链表进行整体的操作,如当删除第一个节点时,这种方式可以直接删除,
增加,查询,修改都比较简单,给一个删除节点的图示和说明:
如下图所示,假设我们需要删除的节点是node2,此时辅助节点tempNode的位置应该是node1才对,因为单链表只有一个尾指针,如果辅助节点的位置指向了待删除的节点,那么该节点就不能自己删除自己,它只能删除它后面的节点,相反,如果辅辅助节点的位置是待删除节点的上一个节点,如图中的node1,直接执行tempNode.next=tempNode.next.next,即可完成对node2节点的删除
package com.lugang.list;
//链表类
public class SingleList {
private int size=0;//记录链表结点的个数
private Node head=new Node();//各种操作都需要一个临时节点来替代头节点,不要直接对头节点进行操作,因为增删改查一开始都需要找到头节点,所以头结点的位置不能动
public void add(Node newNode){
Node tempNode=head;
while(true){
if(tempNode.next==null){
break;
}
else{
tempNode=tempNode.next;
}
}
//退出循环时说明tempNode.next=null,此时让tempNode.next=newNode,即可完成添加操作
tempNode.next=newNode;
size++;
}
public void show(){
//需要判断链表是否为空
if(head.next==null){
System.out.println("链表为空");
return;
}
else{
//因为链表不为空 直接将tempNode=head.next,退出循环的条件为tempNode是否为空
Node tempNode=head.next;
while(true){
if(tempNode==null){
break;
}
else{
//需要重写toString
System.out.println(tempNode);
tempNode=tempNode.next;
}
}
}
}
public int size(){
return size;
}
/**
*
* @param value 查找结点的值
* @return 如果找到就返回找到的节点,找不到就返回空值
*/
public Node find(int value){
if(head.next==null){
//使用异常退出
throw new RuntimeException("链表为空");
}
else{
boolean flag=false;
Node tempNode=head.next;
while(true){
//找到最后不管查找节点存不存在都退出
if(tempNode==null){
break;
}
//找到退出
if(tempNode.data==value){
//标志找到
flag=true;
break;
}
//向后移动
else{
tempNode=tempNode.next;
}
}
//退出循环需要用flag判断是否找到
if(flag==true){
//找到节点,直接将tempNode返回
return tempNode;
}
else{
//没找到,返回空值
return null;
}
}
}
/**
*
* @param index 待修改元素的缩影
* @param value 待修改元素的值
*/
public void update(int index,int value){
if(head.next==null){
throw new RuntimeException("链表为空,无法修改");
}
else{
//对索引的值进行校验
//设定链表的第一个索引为一,非头节点
if(index<1||index>size()){
System.out.println("错误的索引");
return;
}
else{
Node tempNode=head.next;
//找到位置
for(int i=1;i<index;i++){
tempNode=tempNode.next;
}
//退出循环就修改
tempNode.data=value;
}
}
}
public void delete(int value){
if(head.next==null){
throw new RuntimeException("链表为空,无法删除");
}
else{
boolean flag=false;
Node tempNode=head;
while(true){
if(tempNode.next==null){
break;
}
if(tempNode.next.data==value){
flag=true;
break;
}
else{
tempNode=tempNode.next;
}
}
if(flag==true){
tempNode.next=tempNode.next.next;
size--;
}
else{
System.out.println("所删除的节点在链表中不存在");
}
}
}
}
//节点类,节点类也可以写到链表类的内部,采用内部类的方式实现更好
class Node{
public int data;//数据域
public Node next;//指向下一个节点引用,默认为空
public Node(int data){
this.data=data;
}
public Node(){}
@Override
public String toString() {
return "Node{" +
"data=" + data +
'}';
}
}
package com.lugang.list;
//测试类
public class SingleListTest {
public static void main(String[] args) {
Node node1=new Node(1);
Node node2=new Node(2);
Node node3=new Node(3);
Node node4=new Node(4);
Node node5=new Node(5);
SingleList list=new SingleList();
list.add(node1);
list.add(node2);
list.add(node3);
list.add(node4);
list.add(node5);
list.show();
//测试查找
Node node = list.find(1);
if(node==null){
System.out.println("节点不存在");
}
else{
System.out.println(node);
}
//测试修改
list.update(1,12);
list.update(5,34);
System.out.println("**********************");
list.show();
//测试删除
list.delete(1);
list.delete(4);
System.out.println("************************");
list.show();
System.out.println(":::::::::::::::::::::::::::::");
list.delete(34);
list.show();
}
}
注:代码很多地方都可以修改,如循环部分,可以添加泛型实现,此次的代码网最简单的方向写,本人第一篇文字,如果有错还希望各位纠正,文章内容很基础,自己就是做一下记录