单向链表的实现

1、实现目标

通过Java和Golang两种语言实现单向链表,此处的队列的满足的要求有:

  • 实现对链表节点的增、删、改、查操作
  • 存放的类型自定义,Java通过泛型实现,Golang暂定用interface{}

完整代码和测试代码,参考:https://github.com/lzj09/data-structure

2、实现逻辑

实现的重点即是链表中的节点,该节点主要包括具体的数据,以及指向下一个节点的引用。对于Java来说,要有一个Node类,该类中的数据属性,类型可以通过泛型来设置;以及下一个节点的Node属性,类型就是Node类型;对于Golang来说,通过Node结构体实现,其中一样包括数据属性,类型为interface{},下一个节点属性的类型为Node的引用 类型。单向链表的示意图,如下:在这里插入图片描述

3、代码实现

Java版本核心代码:

package com.github.lzj09.datastructure.linked;

/**
 * 单向链表
 * 
 * @author lzj
 * @date 2022-12-11
 */
public class SinglyLinkedList<T> {
	// 链表的表头,表头不存放数据
	private Node<T> head = new Node<T>();
	// 用于记录节点个数
	private int num;

	/**
	 * 往链表中加入数据,直接将数据挂在链表尾部
	 * 
	 * @param data
	 */
	public int add(T data) {
		// 当next为null时,则定位为尾部
		Node<T> tmp = head;
		while (tmp.next != null) {
			tmp = tmp.next;
		}
		
		tmp.next = new Node<T>(data);
		return num++;
	}

	/**
	 * 获取数据的索引,未找到则返回-1
	 * 
	 * @param data
	 * @return
	 */
	public int indexOf(T data) {
		Node<T> tmp = head;
		for (int i = 0; tmp.next != null; i++) {
			tmp = tmp.next;
			if (tmp.data.equals(data)) {
				return i;
			}
		}
		
		return -1;
	}
	
	/**
	 * 获取索引获取数据
	 * 
	 * @param i
	 * @return
	 */
	public T get(int i) {
		int n = i + 1;
		if (n > num || i < 0) {
			throw new RuntimeException("超出索引范围");
		}
		
		Node<T> tmp = head;
		for (int j = 0; j < n; j++) {
			tmp = tmp.next;
		}
		
		return tmp.data;
	}
	
	/**
	 * 根据索引位置删除数据
	 * 
	 * @param i
	 * @return
	 */
	public T remove(int i) {
		int n = i + 1;
		if (n > num || i < 0) {
			throw new RuntimeException("超出索引范围");
		}
		
		// 先找到该索引前一位节点
		Node<T> tmp = head;
		for (int j = 0; j < i; j++) {
			tmp = tmp.next;
		}
		// 需要删除的节点
		Node<T> delNode = tmp.next;
		tmp.next = delNode.next;
		num--;
		
		return delNode.data;
	}
	
	/**
	 * 根据索引更新节点数据
	 * 
	 * @param i
	 * @param data
	 * @return
	 */
	public void update(int i, T data) {
		int n = i + 1;
		if (n > num || i < 0) {
			throw new RuntimeException("超出索引范围");
		}
		
		// 先找到该索引前一位节点
		Node<T> tmp = head;
		for (int j = 0; j < i; j++) {
			tmp = tmp.next;
		}
		// 需要更新的节点
		Node<T> updateNode = tmp.next;
		updateNode.data = data;
	}
	
	/**
	 * 清空链表
	 */
	public void clear() {
		head.next = null;
		num = 0;
	}
	
	/**
	 * 判断链表是否为空
	 * 
	 * @return
	 */
	public boolean isEmpty() {
		return head.next == null;
	}
	
	/**
	 * 链表节点数
	 * 
	 * @return
	 */
	public int size() {
		return num;
	}
	
	/**
	 * 链表中的节点
	 *
	 * @param <E>
	 */
	class Node<E> {
		E data;
		Node<E> next;
		
		public Node() {
		}
		
		public Node(E data) {
			this.data = data;
		}
	}
}

Golang版本核心代码:

package linked

import "errors"

// SinglyLinkedList 单向链表
type SinglyLinkedList struct {
	// head 链表的表头,不存在数据
	head *node

	// num 记录节点个数
	num int64
}

// NewSinglyLinkedList 获取单向链表
func NewSinglyLinkedList() *SinglyLinkedList {
	return &SinglyLinkedList{
		head: &node{},
		num:  0,
	}
}

// Add 往链表中加入数据
func (sl *SinglyLinkedList) Add(data interface{}) int64 {
	tmp := sl.head
	for tmp.next != nil {
		tmp = tmp.next
	}

	tmp.next = &node{
		data: data,
	}
	res := sl.num
	sl.num++

	return res
}

// IndexOf 获取数据的索引,未找到则返回-1
func (sl *SinglyLinkedList) IndexOf(data interface{}) int64 {
	tmp := sl.head
	for i := 0; tmp.next != nil; i++ {
		tmp = tmp.next
		if tmp.data == data {
			return int64(i)
		}
	}

	return -1
}

// Get 获取索引获取数据
func (sl *SinglyLinkedList) Get(i int64) (interface{}, error) {
	n := i + 1
	if n > sl.num || i < 0 {
		return nil, errors.New("超出索引范围")
	}

	tmp := sl.head
	var j int64 = 0
	for ; j < n; j++ {
		tmp = tmp.next
	}

	return tmp.data, nil
}

// Remove 根据索引位置删除数据
func (sl *SinglyLinkedList) Remove(i int64) (interface{}, error) {
	n := i + 1
	if n > sl.num || i < 0 {
		return nil, errors.New("超出索引范围")
	}

	// 先找到该索引前一位节点
	tmp := sl.head
	var j int64 = 0
	for ; j < i; j++ {
		tmp = tmp.next
	}
	delNode := tmp.next
	tmp.next = delNode.next
	sl.num--

	return delNode.data, nil
}

// Update 根据索引更新节点数据
func (sl *SinglyLinkedList) Update(i int64, data interface{}) error {
	n := i + 1
	if n > sl.num || i < 0 {
		return errors.New("超出索引范围")
	}

	// 先找到该索引前一位节点
	tmp := sl.head
	var j int64 = 0
	for ; j < i; j++ {
		tmp = tmp.next
	}

	// 需要更新的节点
	updateNode := tmp.next
	updateNode.data = data

	return nil
}

// Clear 清空链表
func (sl *SinglyLinkedList) Clear() {
	sl.head.next = nil
	sl.num = 0
}

// ISEmpty 判断链表是否为空
func (sl *SinglyLinkedList) ISEmpty() bool {
	return sl.head.next == nil
}

// Size 链表节点数
func (sl *SinglyLinkedList) Size() int64 {
	return sl.num
}

// node 单向链表中的数据节点
type node struct {
	// data 节点中存储的数据
	data interface{}

	// next 指向下一个节点的地址
	next *node
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值