单链表的增删改查,就地逆置、倒数第k个节点算法实现

前言唠叨一下

最近有点时间,总结了一下单链表的各种操作,包括增删改查,就地逆置、求倒数第k个节点等。工作之余重新回顾一下,虽然工作中很少用到,Java也封装了比较完善的链表实现,但对于自己的算法理解多多少少也有所帮助。

效果图

在这里插入图片描述

链表类实现逻辑

package com.list;

/** 
 * 单链表-带头结点
 */
public class SingleLinkedList<T> {
	private int size;
	private Node head;
	
	/** 
	 * 构造一个空的链表
	 */
	public SingleLinkedList() {
		this.size = 0;
		head = new Node();
	}
	
	/** 
	 * 创建大小为size的链表,元素默认值为JDK类加载时的默认值
	 * @param size, 链表大小
	 */
	public SingleLinkedList(int size) {
		this.size = size;
		head = createList(size);
	}

	/**
	 * 根据传入的数组,构造链表
	 * @param datas
	 */
	public SingleLinkedList(T[] datas) {
		this.size = datas.length;
		head = createList(datas);
	}
	
	/**
	 * 按照传入的数据元素创建链表
	 * @param datas
	 */
	private SingleLinkedList<T>.Node createList(T[] datas) {
		Node head = this.createList(datas.length);
		Node p = head.next;
		for (T d : datas) {
			p.data = d;
			p = p.next;
		}
		return head;
	}

	/**
	 * 创建大小为 size 带有JDK默认初始值的链表
	 * @param size
	 */
	private Node createList(int size) {
		if(size < 0) new Exception("参数异常");
		Node head = new Node();
		Node p = head;
		for(int i=0; i<size; i++){
			p.next = new Node();
			p = p.next;
		}
		return head;
	}
	
	/**
	 * 获取倒数第k个节点值
	 * @param k 元素位置
	 */
	public T getBackValue(int k){
		if(k <= 0 || k > size){
			return null;
		}
		
		Node p = head.next;
		Node cur = p;
		int count = 1;
		// cur先走
		while(cur.next != null && count++ != k){
			cur = cur.next;
		}
		
		// 一起走,cur.next走到最后为空时,p为倒数第k个节点
		while(cur.next != null){
			cur = cur.next;
			p = p.next;
		}
		
		return p.data;
	}
	
	/**
	 * 在第 pos个位置之前插入data
	 * @param pos 插入的位置
	 * @param data 插入元素
	 * @return 是否插入成功
	 */
	public boolean insert(int pos, T data){
		if(pos <=0 || pos > size) {
			// 不在范围内,直接插入在末尾
			insertLast(data);
			return true;
		}
		Node p = head;
		for(int i=1; i<pos; i++){
			p = p.next;
		}
		// 插入新节点
		Node newNode = new Node();
		newNode.data = data;
		newNode.next = p.next;
		p.next = newNode;
		size ++ ;
		return true;
	}
	
	/**
	 * 移除第 pos个位置元素
	 * @param pos 元素位置
	 */
	public void remove(int pos){
		if(pos <=0 || pos > size) {
			throw new NumberFormatException("number invaild position : " + pos) ;
		}
		
		Node p = head;
		for(int i=1; i<pos; i++){
			p = p.next;
		}
		
		// remove 
		Node q = p.next;
		p.next = q.next;
		size -- ;
	}
	
	
	/**
	 * 替换第 pos 号位置的元素为 data
	 * @param pos 元素位置
	 * @param data 要替换的元素
	 */
	public void replace(int pos, T data){
		if(pos <=0 || pos > size) {
			throw new NumberFormatException("number invaild position : " + pos) ;
		}
		
		Node p = head;
		for(int i=1; i<pos; i++){
			p = p.next;
		}
		
		// replace 
		p.next.data = data;
		size -- ;
	}
	
	/**
	 * @param data
	 * 在末尾插入元素
	 */
	public void insertLast(T data){
		Node p = head;
		while(p.next != null){
			p = p.next;
		}
		
		Node newNode = new Node();
		newNode.data = data;
		p.next = newNode;
		size ++;
	}
	
	/**
	 * 单链表就地逆置-只改变指针,不改变值
	 */
	public void reversList(){
		if(size == 0) return ;
		
		Node p = head.next;
		Node r = p.next;
		Node pre;
		// 第一个节点,next置空
		p.next = null;
		while(r != null){
			pre = p;
			p = r;
			r = r.next;
			p.next = pre;
		}
		
		// 头结点归位
		head.next = p;
	}
	
	/**
	 * @param sl
	 * 打印链表
	 */
	public void printList(){
		if(size > 0){
			Node p = head;
			while(p != null){
				if(p.next == null){
					System.out.print(p.data );
					break;
				}
				System.out.print(p.data + " -> ");
				p = p.next;
			}
			System.out.println();
		}
	}
	
	
	public int getSize() {
		return size;
	}

	public Node getHead() {
		return head;
	}

	class Node{
		T data;
		Node next;
	}
}

测试类

package com.list;

public class Test {
	public static void main(String[] args) {
		System.err.println("说明: \"null\" 表示头节点 , \"->\"表示两个节点的前驱后继关系。 ");
		System.out.println();
		System.out.println("第一种方式构造链表:{1, 2, 3, 4, 5}");
		Integer[] arr = {1, 2, 3, 4, 5};
		SingleLinkedList<Integer> s = new SingleLinkedList<>(arr);
		// 打印
		s.printList();
		System.out.println();
		
		System.out.println("=========== 华丽丽的分割线 ==============");
		System.out.println();
		
		System.out.println("第二种方式构造链表:从空链表开始构造");
		SingleLinkedList<Integer> list = new SingleLinkedList<>();
		System.out.println("分别在第 1, 2, 3,4 号位置插入元素 11, 22, 3344");
		list.insert(1, 11);
		list.insert(2, 22);
		list.insert(3, 33);
		list.insert(4, 44);
		list.printList();
		System.out.println();
		
		System.out.println("将第2个节点替换为7");
		list.replace(2, 7);
		list.printList();
		System.out.println();
		
		Integer v = list.getBackValue(3);
		System.out.println("获取倒数第3个节点的值 :" + v);
		System.out.println();
		
		int data2 = 0;
		System.out.println("在最后一个节点后面插入 : " + data2);
		list.insertLast(data2);
		list.printList();
		System.out.println();
		
		int pos = 2;
		System.out.println("移除第" + pos + "个节点 : " + pos);
		list.remove(pos);
		list.printList();
		System.out.println();
		
		System.out.println("反转链表:");
		list.reversList();
		list.printList();
		System.out.println();
	}
}

最后说明

使用了泛型,理论上可以支持所有引用类型。多线程下可能会出现线程安全问题。
算法项目代码:https://download.csdn.net/download/yanglong_blog_/12636522

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

longger_yang

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值