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
}