Personal Blog

数据结构

04-静态链表实现

本节主要针对线性表这个逻辑概念,介绍如何使用静态链表的存储形式来实现。

静态链表

线性表的静态链表:使用一维数组来描述线性链表,同样每个数组的元素包含数据域、指针域,不同的是指针域不再是元素的地址值, 而是通过存储指向的目标元素在数组中的索引来实现。

静态链表对线性表的实现

依然采取类似链表小节中的链表对线性表的实现所述的链表结构进行组织。

类型的定义

表示结点的结构体

type StaticLinkedListNode struct {
	Next   int
	Data   any
	isHead bool
}

表示链表的结构体

type StaticLinkedList struct {
	head     []*StaticLinkedListNode
	length   int
	capacity int
	//isCircular bool
	gcPool map[int]any // store deleted  element index, and reuse it in InsertByIndex func
}

对线性表接口的实现

前面列出了线性表的基础操作,这里会对其一一进行实现,但是在实现任何一个方法前,我 们需要先实现其初始化方法。

0. NewSingleLinkedList

// 初始化
func NewStaticLinkedList(cap int) (l *StaticLinkedList) {
	list := new(StaticLinkedList)
	list.capacity = cap
	list.gcPool = make(map[int]any)
	list.head = make([]*StaticLinkedListNode, 1, cap+1)
	list.head[0] = &StaticLinkedListNode{
		Next:   0,
		isHead: true,
	}

	return list
}

1. ClearList

// 清空线性表中的数据
func NewStaticLinkedList(cap int) (l *StaticLinkedList) {
	list := new(StaticLinkedList)
	list.capacity = cap
	list.gcPool = make(map[int]any)
	list.head = make([]*StaticLinkedListNode, 1, cap+1)
	list.head[0] = &StaticLinkedListNode{
		Next:   0,
		isHead: true,
	}

	return list
}

2. IsEmpty

func (s *StaticLinkedList) IsEmpty() bool {
	return s.length == 0
}

3. GetLength

func (s *StaticLinkedList) GetLength() int {
	return s.length
}

4. GetElementByIndex

// 获取线性表中位于指定索引的元素
func (s *StaticLinkedList) GetElementByIndex(index int) (any, error) {
	if index >= s.length || index < 0 {
		return nil, fmt.Errorf("index out of range")
	}

	var curr = 0
	for i := 0; i <= index; i++ {
		curr = s.head[curr].Next
	}

	return s.head[curr].Data, nil
}

5. GetElementIndexByValue

// 获取线性表中与指定值相等元素的索引
func (s *StaticLinkedList) GetElementIndexByValue(element any) (int, error) {
	var curr = s.head[0].Next

	for i := 0; i < s.length; i++ {
		if s.head[curr].Data == element {
			return i, nil
		}
		curr = s.head[curr].Next
	}

	return 0, fmt.Errorf("can't find element %s in data", element)
}

6. GetPriorElement

// 获取线性表中与指定值相等元素的前一个元素
func (s *StaticLinkedList) GetPriorElement(element any) (any, error) {
	var previous, current = 0, 0

	for i := 0; i < s.length+1; i++ {
		if i == 0 { // skip head node
			previous = current
			current = s.head[current].Next
			continue
		}

		if s.head[current].Data == element {
			if i == 1 {
				return 0, fmt.Errorf("element %s has been found, but it's already the first element", element)
			}
			return s.head[previous].Data, nil
		}

		previous = current
		current = s.head[current].Next
	}

	return 0, fmt.Errorf("can't find element %s in data", element)
}

7. GetNextElement

// 获取线性表中与指定值相等元素的后一个元素
func (s *StaticLinkedList) GetNextElement(element any) (any, error) {
	var current = 0

	for i := 0; i < s.length+1; i++ {
		if i == 0 { // skip head node
			current = s.head[current].Next
			continue
		}

		if s.head[current].Data == element {
			if i == s.length {
				return 0, fmt.Errorf("element %s has been found, but it's already the last element", element)
			}

			nextIndex := s.head[current].Next
			return s.head[nextIndex].Data, nil
		}

		current = s.head[current].Next
	}

	return 0, fmt.Errorf("can't find element %s in data", element)
}

8. InsertByIndex

// 在线性表中指定索引处插入元素
// InsertByIndex you can insert element into the list, between head and tail, or you will get over range error
func (s *StaticLinkedList) InsertByIndex(index int, element any) error {
	if index >= s.length+1 || index < 0 {
		return fmt.Errorf("index is out of range")
	}

	// if new length great than cap, just return err
	if s.length+1 > s.capacity {
		return fmt.Errorf("new length can't longer than capacity")
	}

	var previous = 0
	var curr = 0
	for i := 0; i <= index; i++ {
		previous = curr
		curr = s.head[curr].Next
	}

	node := &StaticLinkedListNode{
		Data: element,
	}

	gcIndex := -1
	if len(s.gcPool) > 0 {
		for gcIndex = range s.gcPool {
			break
		}
	}

	realIndex := s.length + 1 // default there isn't gc element
	if gcIndex >= 0 {
		realIndex = gcIndex // There is gc element, set to real index
		s.head[gcIndex] = node
		delete(s.gcPool, gcIndex)
	} else {
		s.head = append(s.head, node) // There isn't gc element
	}

	s.head[previous].Next = realIndex
	s.head[realIndex].Next = curr

	s.length += 1

	return nil
}

9. DeleteByIndex

// 获在线性表中指定索引处删除元素
// DeleteByIndex you can delete element by index, between head and tail, or you will get over range error
func (s *StaticLinkedList) DeleteByIndex(index int) (deletedElement any, err error) {
	if index >= s.length || index < 0 {
		return nil, fmt.Errorf("index is out of range")
	}

	var previous, curr = 0, 0
	for i := 0; i <= index; i++ {
		previous = curr
		curr = s.head[curr].Next
	}

	deletedElement = s.head[curr].Data
	s.gcPool[curr] = deletedElement
	s.head[previous].Next = s.head[curr].Next

	s.length -= 1

	return deletedElement, nil
}

10. Traverse

// 遍历打印所有元素
func (s *StaticLinkedList) Traverse(f func(data any)) {
	current := s.head[0].Next
	for i := 0; i < s.length; i++ {
		f(s.head[current].Data)
		current = s.head[current].Next
	}
}

其他同类文章

DATA-STRUCTURE · CHAPTER02
data structure chapter02