Implementation of linear table in golang

Time：2021-11-30

Implementation of linear table in golang

• Type definition of linear table
• Sequential representation and implementation of linear table
• Chain representation and implementation of linear list

(I)Type definition of linear table

A linear table is an ordered sequence with N data elements. The data elements of a linear table can be of different types, but the data elements in the same linear table must have the same characteristics, such as int, string, float, bool, structure, etc. As shown in the figure below:

a1 a2 a3 a4 a5 a6 a7 a8 a9
0 1 2 3 4 5 6 7 8
1. A1 is the direct precursor element of A2 and A3 is the direct successor element of A2.
2. When the number of elements is 0, the linear table is empty.
3. The basic operation is the addition, deletion, modification and query of linear table. The average time complexity is O (n)

（2） Sequential representation and implementation of linear table

1. Sequential table definition: a set of storage units with continuous addresses are used to store the data elements of the linear table in turn.
2. Set l as the storage space size of the storage unit, then the storage location of the ith element: local (A1) + (i-1) × L, as shown below:
b a1 1
b+l a2 2
b+(3-1)l a3 3
b+(4-1)l a4 4
b+(5-1)l a5 5

basic operation 2. Delete element 3. Find elements 4. Code demonstration:

package main

import (
"errors"
"fmt"
)

const MaxSize int = 10

type SeqListClass struct {
data   []int
length int
}

//Allocate space
func NewList() *SeqListClass {
if MaxSize == 0 {
return nil
}
return &SeqListClass{
data:   make([]int, MaxSize, MaxSize),
length: 0,
}
}

//Fill in values for sequence table
func (this *SeqListClass) creatList(data []int, n int) (err error) {
for i := 0; i < n; i++ {
this.data[i] = data[i]
}
this.length = n
fmt.Println(this.data)
return nil
}

//Output sequence table
func (this *SeqListClass) dispList() (err error) {
if this.length == 0 {
FMT. Println ("sequence table is 0!")
}
for i := 0; i < this.length; i++ {
fmt.Printf("%d\t", this.data[i])
}
return nil
}

//Table length
func (this *SeqListClass) listLength() int {

return this.length
}

//Find by index
func (this *SeqListClass) getEleme(i int) (int, error) {
if i < 0 || i > this.length {
return -1, errors.New("out of range!")
}
return this.data[i-1], nil
}

//Find index by input element
func (this *SeqListClass) LocateElem(value int) (int, error) {
var i int
for i = 0; i < this.length; i++ {
if value == this.data[i] {
break
}
}
if i >= this.length {
return -1, errors.New("out of range")
}
return i + 1, nil
}

//Increase
func (this *SeqListClass) ListInsert(i, value int) error {
if i < 0 || i >= this.length {
return errors.New("out of range")
}
for j := this.length; j >= i; j-- {
this.data[j] = this.data[j-1]
}
this.data[i] = value
this.length++
return nil
}

//Delete
func (this *SeqListClass) ListDelete(i int) error {
if i < 0 || i >= this.length {
return errors.New("out of range")
}
for j := i; j < this.length; j++ {
this.data[j] = this.data[j+1]
}
this.length--
return nil
}

//Reverse list
func (this *SeqListClass) Reserve() {
for i := 0; i < this.length/2; i++ {
tmp := this.data[i]
this.data[i] = this.data[this.length-i-1]
this.data[this.length-i-1] = tmp
}
}

func main() {
//Create a new table first
lst := NewList()
//Create a data slice
data := []int{12, 2, 13, 4, 23, 10, 5, 8}
//Fill in values for sequence table
lst.creatList(data, 8)

lst.dispList()

n := lst.listLength()
FMT. Println ("table length is", n)
n, _ = lst.getEleme(5)
FMT. Println ("found element is", n)

n, _ = lst.LocateElem(5)
FMT. Println ("found location is", n)

lst.ListInsert(4, 5)
FMT. Println ("the list after inserting a new element is:", lst. Data)

lst.ListDelete(5)
FMT. Println ("the list after deleting elements is:", lst. Data)

lst.Reserve()
FMT. Println ("list is reversed to:", lst. Data)
}

The execution results are: （3） Chain representation and implementation of linear list

1. Definition of linear linked list: use a group of arbitrary storage units to store the data elements of the linear list (either continuous or discontinuous). For each unit, in addition to storing the information of the data itself, it also stores information indicating the successor (storage location of the successor), that is, data field and pointer field. As shown in the figure: 2. A single linked list is divided into a single linked list with a head node and a single linked list without a head node. A node is set up in the attachment of the first node of the single linked list. There is no data field, but the pointer field stores the address of the first node. This node is called the head node of the single linked list.

3. Single linked list lookup. Unlike the sequential table, the adjacent nodes are close in physical location, and the location of each node can be calculated by the head node. In the single linked table, the connection between the node and the next node is only a pointer field, so it must start from the node. Therefore, the single linked table is a non random storage structure.

basic operation

Assuming that a P element is inserted into nodes a and B, the pointer field of node a needs to point to node P, and the pointer field of node P needs to point to node B. As shown in the figure: 2. Delete element:
Suppose you want to delete the B element in nodes a and C, you need to change the pointer field of node a to point to node C. As shown in the figure: 3. Find elements
The loop starts from the first node and continues until the pointer field of the next node points to nil.

Code demonstration:

package main

import (
"fmt"
)

type Object interface{}

type Node struct {
Data object // define a data field
Next * node // define the address field (the address to the next table)
}

type List struct {
}

//To judge whether it is an empty table, you only need to judge the header node
func (this *List) isEmpty() bool {
return true
} else {
return false
}
}

//Judge table length
func (this *List) Length() int {
//Define a counter with an initial value of 0
count := 0

for cur != nil {
//If the header node is not empty, count++
count++
//Shift the addresses one by one
cur = cur.Next
}
return count
}

func (this *List) Add(data Object) *Node {
node := &Node{Data: data}
return node
}

func (this *List) Append(data Object) {
//Create a new element and assign a value through data
node := &Node{Data: data}
if this.isEmpty() {
} else {
for cur.Next != nil {
Cur = cur. Next // linked list displacement
}
cur.Next = node
}
}

func (this *List) Insert(index int, data Object) {
if index < 0 {
} else if index > this.Length() {
this.Append(data)
} else {
count := 0
for count < (index - 1) {
pre = pre.Next
count++
}
node := &Node{Data: data}
Pre.next = node // the storage address of the previous linked list points to the address of the new element
}
}

//Delete the element with the specified value in the linked list
func (this *List) Remove(data Object) {
if pre.Data == data {
} else {
for pre.Next != nil {
if pre.Next.Data == data {
//The data of pre.next is equal to data, which points to pre.next.next
pre.Next = pre.Next.Next
} else {
//Otherwise, continue to move pre = pre.nxt
Pre = pre. Next // continue
}
}
}
}

//Deletes the element at the specified location
func (this *List) RemoveIndex(index int) {
if index <= 0 {
} else if index > this.Length() {
fmt.Println("out of index!")
} else {
count := 0
for count < index-1 && pre.Next == nil {
Pre = pre. Next // start traversal. If you continue to reach index, the loop will jump out. Pre. Next = = nil
count++
}
pre.Next = pre.Next.Next
}
}

func (this *List) Contain(data Object) bool {
for cur.Next != nil {
if cur.Data == data {
return true
}
cur = cur.Next
}
return false
}

//Traverse all nodes
func (this *List) ShowList() {
if this.isEmpty() == true {
FMT. Println ("the traversal linked list is empty!")
} else {
FMT. Printf ("current element is:% d \ T", cur)
for cur.Next != nil {
cur = cur.Next
FMT. Printf ("current element is:% d \ T", cur. Data)
}
}
}
func main() {
lst := List{}

//Append element
for i := 0; i < 10; i++ {
lst.Append(i)
}
fmt.Println(new.Data)
//Insert element at specified location
lst.Insert(4, 33)
//Delete element
lst.Remove(5)
//Deletes the element at the specified location
lst.RemoveIndex(7)
//Whether to include the specified element
n := lst.Contain(9)
FMT. Println ("the list contains 9:", n)
lst.ShowList()
//Judge whether the table is empty
t := lst.isEmpty()
FMT. Println ("the current table is empty:", t)
//Judge table length
length := lst.Length()
FMT. Println ("table length:", length)

}

Operation results: 1. Similar to a single linked list, it has a data field and a pointer field, but the pointer field has two parts, the front pointer field and the rear pointer field. As shown below: 2. To add node p to nodes B and C in the double linked list, the rear pointer of node B should point to P, the front pointer of node C should point to P, the front pointer of P should point to B, and the rear pointer should point to C. As shown below: basic operation

package main

import (
"fmt"
)

type object interface{}

type node struct {
Data object // data field
Pre * node // front pointer
Next * node // post pointer
}
}

//Judged to be empty
func (this *DelinkList) isEmpty() bool {
return true
}
return false
}

//Judge table length
func (this *DelinkList) length() int {
count := 0
count++
}
return count
}

newNode := &node{data: value}
} else {
This.head.pre = newnode // the pointer in front of the original header pointer points to the new node
This.head = newnode // the original header pointer becomes a new pointer
}
}

//Tail insertion
func (this *DelinkList) appendData(value object) {
newNode := &node{data: value}
if this.isEmpty() {
} else {
}
}
}

//Todo needs to handle the deletion of elements at any position: the deleted elements are in the head, middle and tail
func (this *DelinkList) deletData(value object) {
}
//The previous tail pointer before modifying an element points to the next element
Head.next.pre = head.pre // the front pointer of the tail element points to the third element
}
break
} else {
}
}
}

//To insert data at any position, todo needs to deal with three cases: the deleted elements are in the head, middle and tail
func (this *DelinkList) insertData(index, value int) {
if index <= 0 {
} else if index > this.length() {
this.appendData(value)
} else {
count := 0
//The inserted data is in the middle of the linked list
for count < index {
count++
cur = cur.next
}
newNode := &node{data: value}
Newnode.pre = cur.pre // the new front is the front of the head
Newnode.next = cur // head after new
Cur.pre.next = Xin before and after newnode // head
}
}

//Show all elements
if this.isEmpty() {
FMT. Println ("the linked list is empty!")
} else {
FMT. Println ("current element is:", cur. Data)
for cur.next != nil {
cur = cur.next
FMT. Println ("current element is:", cur. Data)
}
}
}

func main() {
//Initialization
for i := 0; i < 10; i++ {
lst.appendData(i)
}
//Insert element at specified location
lst.insertData(7, 100)
//Delete element
lst.deletData(4)
n := lst.length()
FMT. Println ("table length:", n)

//Show all elements
lst.showList()
}

Operation results: 1. The circular single linked list is roughly the same as the single linked list, but the difference is that the tail pointer does not point to nil, but to the header. As shown in the figure: Basic operation:

Its basic operation is roughly the same as that of a single linked list, except that adding data at the head and tail is slightly different. You need to point the pointer field of the tail element to the head element! I won’t draw a demonstration.

2. Code demonstration:

package main

import (
"fmt"
)

type object interface{}

type node struct {
Data object // data field
Next * node // pointer field
}

Num Uint64 // quantity
}

num:  0,
}
}

}

//Get the number of nodes
func (this *cLinkList) getNum() uint64 {
return (*this).num
}

func (this *cLinkList) appenData(data object) {
newNode := &node{data: data}

if this.getNum() == 0 {
//If there is no data, take data as the header
} else {
//Tail
for ; (*cur).next != this.getHead(); cur = (*cur).next {
}
(*cur).next = newNode
}
(*this).num++

}

func (this *cLinkList) insertData(index int, data object) {
newNode := &node{data: data}
if index < 0 || uint64(index) > this.getNum() {
this.appenData(data)
} else {
count := 0
for count < index-1 {
cur = cur.next
count++
}
newNode.next = cur.next
cur.next = newNode

}

}

//Delete element
func (this *cLinkList) removeData(data object) {
elem := &node{data: data}
if elem == nil {
FMT. Println ("wrong input element!")
}
//Before traversing to the element node
for ; (*cur).next != elem; cur = (*cur).next {
}

(*cur).next = (*elem).next
this.num--

}

//Get next node
func (this *node) getTail() object {
return this.next
}

//Show all elements of the list
if this.getNum() == 0 {
FMT. Println ("currently empty table!")
} else {
FMT. Println ("current element is:", cur. Data)
break
}
cur = cur.next
FMT. Println ("current element is:", cur. Data)
}
}
}

func main() {
lst := newList()
for i := 0; i < 9; i++ {
lst.appenData(i)
}
//Insert element at specified location
lst.insertData(6, 100)
//Deletes the specified element
lst.removeData(6)
//Show all elements
lst.showList()
}

Operation results:Due to computer failure, the console can’t output all the time, so there is a problem with the result. There is a problem with the method insertdata()!

1. The circular double linked list is similar to the double linked list, but the rear pointer field of the tail pointer points to the head element, and the front pointer field of the head element points to the tail element. As shown in the figure: 2. The basic operation is similar to the double linked list, but the operation is more difficult and the author’s level is limited. The code here is reproduced in:https://studygolang.com/artic…Author:JimPangTime: August 30, 2018 11:10:32

Others: head insertion and tail insertion

package main

import (
"fmt"
)

type object interface{}

type list struct {
data object
Next * list // point to 1 the next address
}

//Traverse full table
func (l *list) showall() {
for l.next != nil {
fmt.Println(l.data)
}
}

func main() {
tail := &list{data: 2}

func() {
for i := 0; i < 10; i++ {
Headernext: = list {data: I, next: temp} // create a structure instance. Because it is a header insertion method, the address of the previous node should be passed in as the next value. The default is the storage address of the head node for the first time
Temp = & headernext // during the next insertion, because it is a header insertion method, the structure instance is used as the next value, so change temp
}
}()
func() {
for i := 0; i < 10; i++ {