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:
address data Bit order
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


1. Add elements
Implementation of linear table in golang
2. Delete element
Implementation of linear table in golang
3. Find elements
Implementation of linear table in golang
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:
Implementation of linear table in golang

(3) Chain representation and implementation of linear list

  1. Single linked list
  2. Double linked list
  3. Circular single linked list
  4. Circular double linked list

Single linked 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:Implementation of linear table in golang
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


1. Add elements
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:
Implementation of linear table in golang

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:Implementation of linear table in golang
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 {
    Headnode * node // headnode
}

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

//Judge table length
func (this *List) Length() int {
    //Get chain header node
    cur := this.headNode
    //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
}

//Add elements from the head of the linked list
func (this *List) Add(data Object) *Node {
    node := &Node{Data: data}
    node.Next = (*this).headNode
    (*this).headNode = node
    return node
}

//Add elements from the end of the linked list
func (this *List) Append(data Object) {
    //Create a new element and assign a value through data
    node := &Node{Data: data}
    if this.isEmpty() {
        this.headNode = node
    } else {
        Cur: = this. Headnode // get the header
        for cur.Next != nil {
            Cur = cur. Next // linked list displacement
        }
        cur.Next = node
    }
}

//Add an element after the specified position in the linked list
func (this *List) Insert(index int, data Object) {
    if index < 0 {
        this.Add(data)
    } else if index > this.Length() {
        this.Append(data)
    } else {
        count := 0
        pre := this.headNode
        for count < (index - 1) {
            pre = pre.Next
            count++
        }
        node := &Node{Data: data}
        Node.next = pre.next // the address of the new linked list element points to the storage address of the previous linked list
        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) {
    pre := this.headNode
    if pre.Data == data {
        this.headNode = pre.Next
    } 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) {
    pre := this.headNode
    if index <= 0 {
        //In header
        this.headNode = pre.Next
    } else if index > this.Length() {
        //Out of linked list
        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 {
    cur := this.headNode
    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 {
        cur := this.headNode
        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() {
    //First initialize a linked list
    lst := List{}

    //Append element
    for i := 0; i < 10; i++ {
        lst.Append(i)
    }
    //Add from header
    new := lst.Add("newNode")
    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)
    //Display linked list elements
    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:Implementation of linear table in golang

Double linked list

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:
Implementation of linear table in golang
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:
Implementation of linear table in golang

basic operation


package main

import (
    "fmt"
)

type object interface{}

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

//Judged to be empty
func (this *DelinkList) isEmpty() bool {
    if this.head == nil {
        return true
    }
    return false
}

//Judge table length
func (this *DelinkList) length() int {
    count := 0
    head := this.head
    for head != nil {
        count++
        head = head.next
    }
    return count
}

//Head insertion
func (this *DelinkList) addData(value object) {
    newNode := &node{data: value}
    if this.head == nil {
        this.head = newNode
    } else {
        Newnode. Next = this. Head // after adding, the pointer points to the original head node
        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() {
        this.head = newNode
    } else {
        head := this.head
        for head.next != nil {
            head = head.next
        }
        newNode.pre = head
        head.next = newNode
    }
}

//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) {
    head := this.head
    //Delete header
    if head.data == value {
        head = head.next
    }
    for head != nil {
        if head.data == value {
            //The previous tail pointer before modifying an element points to the next element
            head.pre.next = head.next //
            if head.next != nil {
                Head.next.pre = head.pre // the front pointer of the tail element points to the third element
            }
            break
        } else {
            Head = head. Next // continue scanning
        }
    }
}

//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 {
        this.addData(value)
    } else if index > this.length() {
        this.appendData(value)
    } else {
        count := 0
        cur := this.head
        //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
        Cur.pre = newnode // head
    }
}

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

func main() {
    //Initialization
    lst := &DelinkList{}
    for i := 0; i < 10; i++ {
        lst.appendData(i)
    }
    //Head insertion数据
    lst.addData("newNode")
    //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:
Implementation of linear table in golang

Circular single linked list

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:
Implementation of linear table in golang

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
}

type cLinkList struct {
    Num Uint64 // quantity
    Head * node // head node
}

//Initialize linked list
func newList() *cLinkList {
    return &cLinkList{
        num:  0,
        head: nil,
    }
}

//Get header node
func (this *cLinkList) getHead() *node {
    return this.head
}

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

//Adding footer data has the same effect as adding data at the head and tail
func (this *cLinkList) appenData(data object) {
    newNode := &node{data: data}

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

}

//Add data after index
func (this *cLinkList) insertData(index int, data object) {
    newNode := &node{data: data}
    if index < 0 || uint64(index) > this.getNum() {
        this.appenData(data)
    } else {
        cur := this.getHead()
        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!")
    }
    cur := this.getHead()
    //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
func (this *cLinkList) showList() {
    if this.getNum() == 0 {
        FMT. Println ("currently empty table!")
    } else {
        cur := this.head
        FMT. Println ("current element is:", cur. Data)
        for cur.next != this.getHead() {
            if cur.next == this.getHead() {
                break
            }
            cur = cur.next
            FMT. Println ("current element is:", cur. Data)
        }
    }
}

func main() {
    //Initialize linked list
    lst := newList()
    //Add data
    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()!

Circular double linked list
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:
Implementation of linear table in golang

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() {
    //Create header and tail
    head := &list{data: 1}
    tail := &list{data: 2}
    //Link head and tail
    head.next = tail

    func() {
        header := list{data: 0}
        temp := &header
        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() {
        header := list{data: 0}
        temp := &header
        for i := 0; i < 10; i++ {
            headerlast := list{data: i}
            Temp.next = & headerlast // set the next field of the previous structure as the address of the current circular structure instance because it is tail interpolation.
            Temp = & headerlast // perform a loop to change the instance of the previous structure to the instance of the structure of this loop
        }
    }()
}

This chapter is partially reproduced!

Recommended Today

Game case | application evolution and practice of service mesh in happy games

author Chen Zhiwei, Tencent level 12 background expert engineer, is now responsible for the public background technology research and development and team management of happy game studio. Rich experience in micro service distributed architecture and game background operation and maintenance research and development. preface The background of happy game studio is a distributed micro service […]