数据结构 の go语言实现

数组

快排的经典写法(挖坑)

func sort(nums []int) {
	if len(nums) <= 1 {
		return
	}
	pivot := nums[0]
	i, j := 0, len(nums)-1
	for i < j {
		/*
			为什么要先循环j,再循环i? 因为下面要 j>i ,才能继续循环,如果j先--了,下面就执行不了了
			比如 i=2,j=3; 并且nums[i]<nums[j]; j在前,最后结果是, j=2,i=2; 如果是 i在前边,结果就是 j=3,i=3
		*/

		for ; i < j && nums[j] >= pivot; j-- {
		}
		//  为什么等于也可以?因为 nums[0]一定是等于 pivot 的,必须要等于,才能跳过
		for ; i < j && nums[i] <= pivot; i++ {
		}
		nums[i], nums[j] = nums[j], nums[i]
	}
	nums[0], nums[i] = nums[i], nums[0]
	sort(nums[:i])
	sort(nums[i+1:])
}
func main() {
	rand.New(rand.NewSource(time.Now().UnixNano()))
	nums := make([]int, 10)
	for i := range nums {
		nums[i] = rand.Intn(100)
	}
	fmt.Println(nums)
	sort(nums)
	fmt.Println(nums)
}

k路并归

func main() {
	a := [][]int{
		{1, 12, 15, 24, 29},
		{19, 25, 36, 38, 33},
		{4, 9, 14, 16, 23},
	}
	ksort := func(numbs [][]int) []int {
		n, m := len(a), len(a[0])
		indexlist := make([]int, n)
		ret := []int{}
		for {
			index := -1
			minub := 1 << 32
			for i := 0; i < n; i++ {
				if indexlist[i] < m && numbs[i][indexlist[i]] < minub {
					minub = numbs[i][indexlist[i]] //最小的数
					index = i
				}
			}
			if index == -1 {
				break
			}
			indexlist[index]++
			ret = append(ret, minub)
		}
		return ret
	}
	ret := ksort(a)
	fmt.Println(ret)
}

堆排序

// 从 R[low]到R[high]的范围内对位置在low上的节点进行调整
// 没执行一直这个函数,就相当于位于 low 的这个点彻底调完,hight就是后来帮忙的。
func Sift(R []int, low, high int) {
	i, j := low, 2*low // 树的节点,默认是从1开始的。
	temp := R[i]
	for j <= high {
		if R[j] < R[j+1] && j < high { // 从左右节点中挑出来一个最大的
			j++ // 变成右节点
		}
		if temp < R[j] {
			R[i] = R[j] // 把j调整到双亲节点上
			i = j       // i是要放的节点 继续往下调整
			j = i * 2
		} else {
			break
		}
	}
	R[i] = temp // 把调整后的节点放在最终位置
}

func heapSort(R []int) {
	// 调整顺序,先下后上,先右后左
	n := len(R) - 1               // 因为序号要比次数-1,比如第5个节点,应该是 R[4]
	for i := n / 2; i >= 1; i-- { // 叶子节点肯定都是堆,所以从 n/2 开始,应是从下到上,从右往左切换
		Sift(R, i, n) // 循环调整完以后,最大的肯定在最上面。
	}
	for i := n; i >= 2; i-- {
		R[1],R[i]=R[i],R[1]
		Sift(R, 1, i-1) //把最大的和最后面的进行替换调整
	}
}

func main() {
	rand.Seed(time.Now().UnixNano())
	r := make([]int, 20)
	r[0] = 0
	for i := 1; i < 20; i++ {
		r[i] = rand.Intn(100)
	}
	fmt.Println(r)
	heapSort(r)
	fmt.Println(r)
}

双向链表

双向链表的插入和遍历输出

package main

import (
	"fmt"
	"math/rand"
	"time"
)

type Node struct {
	Data     int
	PrePoint *Node
	NextPont *Node
}

type LinkList struct {
	head    *Node
	current *Node
	tail    *Node
}

func main() {
	rand.New(rand.NewSource(time.Now().UnixNano()))
	datas := make([]int, 10)
	for i := range 10 {
		datas[i] = rand.Intn(100)
	}
	fmt.Println(datas)

	linklists := new(LinkList)
	for _, v := range datas {
		node := new(Node)
		node.Data = v
		linklists.Insert(node)
	}
	linklists.ShowLinkList()
}
func (l *LinkList) Insert(node *Node) {
	if l.head == nil {
		l.head = node
		l.current = node
		l.tail = node
	} else {
		l.tail.NextPont = node
		node.PrePoint = l.tail
		l.tail = node // 只移动尾,头指针一直不动,中间的指针也一直不动
	}
}

func (l *LinkList) ShowLinkList() {
	for c := l.head; c != nil; c = c.NextPont {
		fmt.Println(c.Data)
	}
}

合并两个递增链表

package main

import (
	"fmt"
	"math/rand"
	"time"
)

type Node struct {
	Data     int
	PrePoint *Node
	NextPont *Node
}

type LinkList struct {
	head    *Node
	current *Node
	tail    *Node
}

func main() {
	rand.New(rand.NewSource(time.Now().UnixNano()))
	l1, l2 := new(LinkList), new(LinkList)
	n1, n2 := 0, 0
	for range 10 {
		n1 += rand.Intn(10)
		n2 += rand.Intn(10)
		l1.Insert(&Node{Data: n1})
		l2.Insert(&Node{Data: n2})
	}
	l1.ShowLinkList()
	l2.ShowLinkList()
	fmt.Println("===================================")
	m := merge(l1, l2)
	m.ShowLinkList()

}
func (l *LinkList) Insert(node *Node) {
	if l.head == nil {
		l.head = node
		l.current = node
		l.tail = node
	} else {
		l.tail.NextPont = node
		node.PrePoint = l.tail
		l.tail = node // 只移动尾,头指针一直不动,中间的指针也一直不动
	}
}

func (l *LinkList) ShowLinkList() {
	values := make([]int, 0)
	for c := l.head; c != nil; c = c.NextPont {
		values = append(values, c.Data)
	}
	fmt.Println(values)
}
func merge(l1, l2 *LinkList) (m *LinkList) {
	m = new(LinkList)
	c1, c2 := l1.head, l2.head
    // 如果l1 和 l2 可以改变原有结构的话,其实可以用 m.Insert 的时候,可以直接插入 c1 或者 c2
	for c1 != nil && c2 != nil {
		// 这里是合并递增链表,所以排小的在前面
		if c1.Data < c2.Data {
			m.Insert(&Node{Data: c1.Data})
			c1 = c1.NextPont
		} else {
			m.Insert(&Node{Data: c2.Data})
			c2 = c2.NextPont
		}
	}
	for c1 != nil {
		m.Insert(&Node{Data: c1.Data})
		c1 = c1.NextPont
	}
	for c2 != nil {
		m.Insert(&Node{Data: c2.Data})
		c2 = c2.NextPont
	}
	return m
}

posted @ 2025-10-28 04:12  沧海一声笑rush  阅读(7)  评论(0)    收藏  举报