【GO语言】练习:泛型类型

题目

除了泛型函数之外,Go 还支持泛型类型。 类型可以使用类型参数进行参数化,这对于实现通用数据结构非常有用。

此示例展示了能够保存任意类型值的单链表的简单类型声明。

作为练习,请为此链表的实现添加一些功能。

package main

// List represents a singly-linked list that holds
// values of any type.
type List[T any] struct {
	next *List[T]
	val  T
}

func main() {
}

解答

为了增强泛型链表的功能,我们为List[T]类型添加了多个方法,包括追加元素、插入头部、获取长度、转换为字符串、获取元素、插入元素、删除元素和反转链表。以下是完整的实现代码:

package main

import (
	"fmt"
	"strings"
)

// List 表示一个可以保存任何类型的值的单链表。
type List[T any] struct {
	next *List[T]
	val  T
}

// Append 将值追加到链表末尾,返回新的头节点。
func (l *List[T]) Append(val T) *List[T] {
	if l == nil {
		return &List[T]{val: val, next: nil}
	}
	current := l
	for current.next != nil {
		current = current.next
	}
	current.next = &List[T]{val: val, next: nil}
	return l
}

// PushFront 将值插入到链表头部,返回新的头节点。
func (l *List[T]) PushFront(val T) *List[T] {
	return &List[T]{val: val, next: l}
}

// Length 返回链表的长度。
func (l *List[T]) Length() int {
	count := 0
	current := l
	for current != nil {
		count++
		current = current.next
	}
	return count
}

// String 返回链表的字符串表示。
func (l *List[T]) String() string {
	var sb strings.Builder
	sb.WriteString("[")
	current := l
	for current != nil {
		sb.WriteString(fmt.Sprint(current.val))
		current = current.next
		if current != nil {
			sb.WriteString(", ")
		}
	}
	sb.WriteString("]")
	return sb.String()
}

// Get 获取指定位置的元素,如果位置有效返回元素和true,否则返回零值和false。
func (l *List[T]) Get(pos int) (T, bool) {
	var zero T
	current := l
	for i := 0; i < pos; i++ {
		if current == nil {
			return zero, false
		}
		current = current.next
	}
	if current == nil {
		return zero, false
	}
	return current.val, true
}

// Insert 在指定位置插入元素,返回新的头节点。
// 如果位置大于链表长度,不插入。
func (l *List[T]) Insert(pos int, val T) *List[T] {
	if pos == 0 {
		return &List[T]{val: val, next: l}
	}
	prev := l
	for i := 0; i < pos-1; i++ {
		if prev == nil {
			return l // 位置无效,不插入
		}
		prev = prev.next
	}
	if prev == nil {
		return l
	}
	newNode := &List[T]{val: val, next: prev.next}
	prev.next = newNode
	return l
}

// Remove 删除指定位置的元素,返回新的头节点。
// 如果位置无效,返回原链表。
func (l *List[T]) Remove(pos int) *List[T] {
	if l == nil {
		return nil
	}
	if pos == 0 {
		return l.next
	}
	prev := l
	for i := 0; i < pos-1; i++ {
		if prev.next == nil {
			return l // 无效位置
		}
		prev = prev.next
	}
	if prev.next != nil {
		prev.next = prev.next.next
	}
	return l
}

// Reverse 反转链表,返回新的头节点。
func (l *List[T]) Reverse() *List[T] {
	var prev *List[T]
	current := l
	for current != nil {
		next := current.next
		current.next = prev
		prev = current
		current = next
	}
	return prev
}

func main() {
	var list *List[int]
	list = list.Append(1)
	list = list.Append(2)
	list = list.Append(3)
	fmt.Println(list.String()) // [1, 2, 3]

	list = list.PushFront(0)
	fmt.Println(list.String()) // [0, 1, 2, 3]

	fmt.Println("Length:", list.Length()) // 4

	val, ok := list.Get(2)
	fmt.Printf("Get(2): %v, %v\n", val, ok) // 2, true

	list = list.Insert(2, 99)
	fmt.Println(list.String()) // [0, 1, 99, 2, 3]

	list = list.Remove(1)
	fmt.Println(list.String()) // [0, 99, 2, 3]

	list = list.Reverse()
	fmt.Println(list.String()) // [3, 2, 99, 0]
}

说明

  1. Append:将元素追加到链表末尾。处理空链表情况。
  2. PushFront:在链表头部插入元素,返回新头节点。
  3. Length:遍历链表计算长度。
  4. String:生成链表的字符串表示,便于调试。
  5. Get:根据索引获取元素,处理越界情况。
  6. Insert:在指定位置插入元素,处理头部插入和越界。
  7. Remove:删除指定位置元素,处理头部删除和越界。
  8. Reverse:反转链表,返回新头节点。

这些方法增强了链表的功能,使其支持基本操作,并处理了空链表和边界条件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值