Java单链表的实现(增删改、逆序输出、查找倒数第n个节点)

介绍

单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表是以节点的方式来存储的,用head作为基点,每个节点包含data域和next域(指针域)。data域用来存储数据,next指定下一节点。
如下图
在这里插入图片描述

链表的增删改

节点定义

//定义Node, 每一个Node就是一个节点
class Node{
	//数据域,可以封装成一个类
	public int num;    
	public String name;
	public String nickName;
	//下一节点
	public Node next;  
	
	public Node(int num,String name,String nickName) {
		this.num=num;
		this.name=name;
		this.nickName=nickName;
	}
	
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return "num:"+this.num+" name:"+this.name+" nickName:"+this.nickName;
	}
	
}

节点增加

前插法
先把node节点指向head节点的下一个节点(node.next=head.next),再把node节点作为head节点的下一个节点(head.next=node)
在这里插入图片描述
后插法
先遍历链表找到最后一个节点,用temp节点存储。把node节点作为temp节点的下一个temp.next=node
在这里插入图片描述

//添加节点
	//找到最后的节点,在其后方添加新节点
	public void addNode(Node Node) {
		//head节点不能动,用temp辅助操作
		Node temp=head;
		//遍历列表
		while(true) {
			//找到退出
			if(temp.next==null) {
				break;
			}
			temp=temp.next;
		}
		temp.next=Node;
	}

按数据域某一属性的顺序插入(指定位置插入)
先遍历链表找到指定节点的前一个,用temp节点存储。把temp节点作为node节点的下一个(node.next=temp.next),再把node作为temp的下一节点(temp.next=node)
在这里插入图片描述

//按顺序添加
	public void addByOrder(Node Node) {
		//寻找的节点是要添加位置的前一个
		Node temp=head;
		boolean flag=false;  //添加的节点是否存在
		
		while(true) {
			//temp为最后一个
			if(temp.next==null) {
				break;
			}
			
			if(temp.next.num>Node.num) {  //位置找到
				break;
			}else if(temp.next.num==Node.num) {   //节点已存在
				flag=true;
				break;
			}
			
			temp=temp.next;
		}
		
		if(flag) {
			System.out.println(Node+"节点已存在");
		}else {
			Node.next=temp.next;
			temp.next=Node;
			System.out.println(Node+"节点添加成功");
		}
	};

节点修改

遍历找到要修改的节点,修改数据

//修改节点
	public void updateNode(Node Node) {
		if(head.next==null) {
			System.out.println("链表为空");
			return;
		}
		
		Node temp=head.next;
		boolean flag=false;
		
		while(true) {
			if(temp==null) {  //已经遍历完
				break;
			}
			
			if(temp.num==Node.num) {  //找到数据
				flag=true;
				break;
			}
			
			temp=temp.next;
		}
		
		if(flag) {
			temp.name=Node.name;
			temp.nickName=Node.nickName;
			System.out.println(Node+"修改成功");
		}else {
			System.out.println("未找到节点");
		}
	}

节点删除

找到要删除节点的前一个,用temp节点存储,用temp的下一节点指向temp节点下一节点的下一节点(temp.next=temp.next.next),而要删除的节点由于没有指针指向,会被java的垃圾回收机制自动回收,即被删除。
在这里插入图片描述

//删除节点
public void deleteNode(int num) {
		Node temp=head;
        boolean flag=false;
		while(true) {
			if(temp.next==null) {  //已经遍历完
				break;
			}	
			if(temp.next.num==num) {  //找到数据
				flag=true;
				break;
			}
			temp=temp.next;
		}
		if(flag) {
			//变换节点
			//要删除的节点(没有指向)会被jvm回收
			temp.next=temp.next.next;
			System.out.println("节点删除成功");
		}else {
			System.out.println("未找到节点");
		}
		
	}

链表的逆序输出

1、遍历链表,用一个临时链表以前插法添加节点

//反转链表
	//遍历链表,把链表的节点前插
	public void reserveLinkedList(Node head) {
		//链表为空,或链表只有一个值
		if(head.next==null||head.next.next==null) {
			return;
		}
		
		Node temp=head.next;
		Node next=null;  //当前节点的下一节点
		Node reserveHead=new Node(0,"","");   //反转列表的头结点
		
		while(temp!=null) {
			next=temp.next;  //先存储链表的下一节点
		
			//前插到临时列表
			temp.next=reserveHead.next;
			reserveHead.next=temp;	
			
			//移到下一节点
			temp=next;
		}
		//实现列表反转
		head.next=reserveHead.next;
	}

2、利用栈先进后出的特性,把链表数据压入栈中,再输出栈中的数据


	//逆序输出,通过栈的先进后出特性
	public void reserveShow(Node head) {
		if(head.next==null) {
			return;
		}
		Stack<Node> stack=new Stack<Node>();
		Node temp=head.next;
		
		while(temp!=null) {
			stack.push(temp);
			temp=temp.next;
		}
		while(stack.size()>0) {
			System.out.println(stack.pop());
		}
	}

链表查找倒数第n个节点

1、首先获取链表的有效长度

//获取链表有效数据长度
	public int getLength(Node head) {
		if(head.next==null) {  //空链表
			return 0; 
		}
		
		int length=0;
		Node temp=head.next;
		
		while(temp!=null) {
			length++;
			temp=temp.next;
		}
		return length;
	}

2、从第一个节点遍历链表长度的size-n次

//查找倒数第k个节点
	//先遍历链表,求取链表长度,遍历size-k次
	public Node getIndexNode (Node head,int index) {
		if(head.next==null) {
			return null; //链表为空
		}
		
		int size=getLength(head);  //链表长度
		
		if(size<=0||index>size) {
			return null;
		}
		
		Node temp=head.next;  //第一个数据
		for(int i=0;i<size-index;i++) {
			temp=temp.next;
		}
		return temp;
	}

完整代码

public class SingleLinkedListDemo {
	
      public static void main(String[] args) {
    	  
    	  Node node1=new Node(1,"张三","小张");
    	  Node node2=new Node(3,"李四","小李");
    	  Node node3=new Node(4,"王五","小王");
    	  Node node4=new Node(2,"赵六","小赵");
    	  
    	  SingleLinkedList list=new SingleLinkedList();
    	  list.addByOrder(node1);
    	  list.addByOrder(node2);
    	  list.addByOrder(node3);
    	  list.addByOrder(node4);
    	  
    	  System.out.println("反转前:");
    	  list.showList();
    	  System.out.println("逆序输出(没有改变链表结构):");
    	  list.reserveShow(list.getHead());
    	  list.reserveLinkedList(list.getHead());
    	  System.out.println("反转后(改变链表结构):");
    	  list.showList();
    	  System.out.println("查找倒数第二个节点");
    	  Node n=list.getIndexNode(list.getHead(), 2);
    	  System.out.println("倒数第二个节点:"+n.toString());
      }
}

//定义Node, 每一个Node就是一个节点
class Node{
	
	public int num;
	public String name;
	public String nickName;
	public Node next;  //下一节点
	
	public Node(int num,String name,String nickName) {
		this.num=num;
		this.name=name;
		this.nickName=nickName;
	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return "num:"+this.num+" name:"+this.name+" nickName:"+this.nickName;
	}
	
}

//定义单链表
class SingleLinkedList{
	
	//初始化头节点
	private Node head=new Node(0,"","");
	
	//获取头结点
	public Node getHead() {
		return head;
	}
	
	//添加节点
	//找到最后的节点,在其后方添加新节点
	public void addNode(Node Node) {
		
		//head节点不能动,用temp辅助操作
		Node temp=head;
		
		//遍历列表
		while(true) {
			//找到退出
			if(temp.next==null) {
				break;
			}
			temp=temp.next;
		}
		
		temp.next=Node;
	}
	
	//按顺序添加
	public void addByOrder(Node Node) {
		//寻找的节点是要添加位置的前一个
		Node temp=head;
		boolean flag=false;  //添加的节点是否存在
		
		while(true) {
			//temp为最后一个
			if(temp.next==null) {
				break;
			}
			
			if(temp.next.num>Node.num) {  //位置找到
				break;
			}else if(temp.next.num==Node.num) {   //节点已存在
				flag=true;
				break;
			}
			
			temp=temp.next;
		}
		
		if(flag) {
			System.out.println(Node+"节点已存在");
		}else {
			Node.next=temp.next;
			temp.next=Node;
			System.out.println(Node+"节点添加成功");
		}
	}
	
	//修改节点
	public void updateNode(Node Node) {
		if(head.next==null) {
			System.out.println("链表为空");
			return;
		}
		
		Node temp=head.next;
		boolean flag=false;
		
		while(true) {
			if(temp==null) {  //已经遍历完
				break;
			}
			
			if(temp.num==Node.num) {  //找到数据
				flag=true;
				break;
			}
			
			temp=temp.next;
		}
		
		if(flag) {
			temp.name=Node.name;
			temp.nickName=Node.nickName;
			System.out.println(Node+"修改成功");
		}else {
			System.out.println("未找到节点");
		}
	}
	
	//获取链表有效数据长度
	public int getLength(Node head) {
		if(head.next==null) {  //空链表
			return 0; 
		}
		
		int length=0;
		Node temp=head.next;
		
		while(temp!=null) {
			length++;
			temp=temp.next;
		}
		
		return length;
	}
	
	//删除节点
	public void deleteNode(int num) {
		Node temp=head;
		
        boolean flag=false;
		
		while(true) {
			if(temp.next==null) {  //已经遍历完
				break;
			}	
			if(temp.next.num==num) {  //找到数据
				flag=true;
				break;
			}
			temp=temp.next;
		}
		
		if(flag) {
			//变换节点
			//要删除的节点(没有指向)会被jvm回收
			temp.next=temp.next.next;
			System.out.println("节点删除成功");
		}else {
			System.out.println("未找到节点");
		}
		
	}
	
	//查找倒数第k个节点
	//先遍历链表,求取链表长度,遍历size-k次
	public Node getIndexNode (Node head,int index) {
		if(head.next==null) {
			return null; //链表为空
		}
		
		int size=getLength(head);  //链表长度
		
		if(size<=0||index>size) {
			return null;
		}
		
		Node temp=head.next;  //第一个数据
		for(int i=0;i<size-index;i++) {
			temp=temp.next;
		}
		return temp;
	}
	
	//反转链表
	//遍历链表,把链表的节点前插
	public void reserveLinkedList(Node head) {
		//链表为空,或链表只有一个值
		if(head.next==null||head.next.next==null) {
			return;
		}
		
		Node temp=head.next;
		Node next=null;  //当前节点的下一节点
		Node reserveHead=new Node(0,"","");   //反转列表的头结点
		
		while(temp!=null) {
			next=temp.next;  //先存储链表的  下一节点
			
			//前插
			temp.next=reserveHead.next;
			reserveHead.next=temp;	
			
			//移到下一节点
			temp=next;
			
		}
		//实现列表反转
		head.next=reserveHead.next;
	}
	
	//显示列表
	public void showList() {
		if(head.next==null) {
			System.out.println("链表为空");
			return;
	    }
		
		Node temp=head;
		//遍历列表
		while(true) {
		  //找到退出
			if(temp.next==null) {
					break;
			}
			temp=temp.next;
			System.out.println(temp.toString());
		}
    }
	
	//逆序输出,通过栈的先进后出特性
	public void reserveShow(Node head) {
		if(head.next==null) {
			return;
		}
		
		Stack<Node> stack=new Stack<Node>();
		Node temp=head.next;
		
		while(temp!=null) {
			stack.push(temp);
			temp=temp.next;
		}
		
		while(stack.size()>0) {
			System.out.println(stack.pop());
		}
	}
}

结果如下
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值