1.Go-copy函数、sort排序、双向链表、list操作和双向循环链表

1.1.copy函数

通过copy函数可以把一个切片内容复制到另一个切片中

(1)把长切片拷贝到短切片中

package main

import "fmt"

func main() {
	s1 := []int {1,2}
	s2 := []int{3,4,5,6}
	//copy的是角标,不会增加元切片的长度
	copy(s1,s2)
	fmt.Println(s1)        //[3 4]
	fmt.Println(s2)		   //[3 4 5 6]
}

(2)把短切片拷贝到长切片中 

package main

import "fmt"

func main() {
	s1 := []int {1,2}
	s2 := []int{3,4,5,6}
	//copy的是角标,不会增加元切片的长度
	copy(s2,s1)
	fmt.Println(s1)        //[1 2]
	fmt.Println(s2)		   //[1 2 5 6]
}

(3)把切片片段拷贝到切片中

package main

import "fmt"

func main() {
	s1 := []int {1,2}
	s2 := []int{3,4,5,6}
	//copy的是角标,不会增加元切片的长度
	copy(s1,s2[1:3])
	fmt.Println(s1)        //[[4 5]
	fmt.Println(s2)		   //[3 4 5 6]
}

1.2.sort排序

package main

import (
	"fmt"
	"sort"
)

func main() {
	num := []int{1,7,3,5,2}
	//升序排序
	sort.Ints(num)
	fmt.Println(num)      //[1 2 3 5 7]

	//降序排序
	sort.Sort(sort.Reverse(sort.IntSlice(num)))
	fmt.Println(num)     //[7 5 3 2 1]
}

1.3.双向链表

 (1)双向链表的结构

双向链表结构中元素在内存中不是紧邻空间,而是每个元素中存放上一个元素和后一个元素的地址

  • 第一个元素称为(头)元素,前连接(前置指针域)为nil
  • 最后一个元素称为 尾(foot)元素,后连接(后置指针域)尾nil

双向链表的优点

  • 在执行新增元素或删除元素时效率高,获取任意一个元素,可以方便的在这个元素前后插入元素
  • 充分利用内存空间,实现内存灵活管理
  • 可实现正序和逆序遍历
  • 头元素和尾元素新增或删除时效率较高

双向链表的缺点

  • 链表增加了元素的指针域,空间开销比较大
  • 遍历时跳跃性查找内容,大量数据遍历性能低

(2)双向链表容器List

在Go语言标准库的container/list包提供了双向链表List

List结构体定义如下

  • root表示根元素
  • len表示链表中有多少元素
// List represents a doubly linked list.
// The zero value for List is an empty list ready to use.
type List struct {
	root Element // sentinel list element, only &root, root.prev, and root.next are used
	len  int     // current list length excluding (this) sentinel element
}

 其中Element结构体定义如下

  • next表示下一个元素,使用Next()可以获取到
  • prev表示上一个元素,使用Prev()可以获取到
  • list表示元素属于哪个链表
  • Value表示元素的值,interface()在Go语言中表示任意类型 
// Element is an element of a linked list.
type Element struct {
	// Next and previous pointers in the doubly-linked list of elements.
	// To simplify the implementation, internally a list l is implemented
	// as a ring, such that &l.root is both the next element of the last
	// list element (l.Back()) and the previous element of the first list
	// element (l.Front()).
	next, prev *Element

	// The list to which this element belongs.
	list *List

	// The value stored with this element.
	Value interface{}
}

1.4.操作List

(1)直接使用container/list包下的New()新建一个空的List

添加,遍历,取首尾,取中间元素

package main

import (
	"container/list"
	"fmt"
)

func main() {
	//实例化
	mylist := list.New()
	fmt.Println(mylist)

	//添加
	mylist.PushFront("a")                        //["a"]
	mylist.PushBack("b")                         //["a","b"]
	mylist.PushBack("c")                         //["a","b","c"]
	//在最后一个元素的前面添加
	mylist.InsertBefore("d",mylist.Back())       //["a","b","d","c"]
	mylist.InsertAfter("e",mylist.Front())       //["a","e","b","d","c"]

	//遍历
	for e := mylist.Front(); e != nil; e = e.Next(){
		fmt.Print(e.Value, " ")     //a e b d c
	}
	fmt.Println("")

	//取首尾
	fmt.Println(mylist.Front().Value)     //a
	fmt.Println(mylist.Back().Value)      //c

	//取中间的元素,通过不断的Next()
	n := 3
	var curr *list.Element
	if n > 0 && n <= mylist.Len(){
		if n == 1 {
			curr = mylist.Front()
		}else if n == mylist.Len(){
			curr = mylist.Back()
		}else {
			curr = mylist.Front()
			for i := 1; i < n; i++{
				curr = curr.Next()
			}
		}
	}else {
		fmt.Println("n的数值不对")
	}
	fmt.Println(curr.Value)        //b
}

(2)移动元素 

package main

import (
	"container/list"
	"fmt"
)

func main() {
	//实例化
	mylist := list.New()
	fmt.Println(mylist)

	//添加
	mylist.PushFront("a")                        //["a"]
	mylist.PushBack("b")                         //["a","b"]
	mylist.PushBack("c")                         //["a","b","c"]
	//在最后一个元素的前面添加
	mylist.InsertBefore("d",mylist.Back())       //["a","b","d","c"]
	mylist.InsertAfter("e",mylist.Front())       //["a","e","b","d","c"]

	//移动,把第一个元素一道最后一个元素的前面
	mylist.MoveBefore(mylist.Front(),mylist.Back())
	//mylist.MoveAfter(mylist.Back(),mylist.Front())

	//把最后一个元素移动到最前面
	//mylist.MoveToFront(mylist.Back())
	//把第一个元素移动到最后面
	//mylist.MoveToBack(mylist.Front())

	for e := mylist.Front(); e != nil; e = e.Next(){
		fmt.Print(e.Value, " ")     //e b d a c
	}
}

(3)删除

mylist.Remove(mylist.Front())

1.5.双向循环列表

(1)循环链表特点是没有节点的指针域为nil,通过任何一个元素都可以找到其它元素

环形链表结构如下

双向循环链表和双向链表区别

  • 双向循环链表没有严格意义上的头元素和尾元素
  • 没有元素的前连接和后连接为nil
  • 一个长度为n的双向循环链表,通过某个元素向某个方向移动,在查找最多n-1次,一定会找到另一个元素

(2)在container/ring包下结构体Ring源码如下

  • 官方明确说明了Ring是循环链表的元素,又是环形链表
  • 实际使用时Ring遍历就是环形链表第一个元素
// A Ring is an element of a circular list, or ring.
// Rings do not have a beginning or end; a pointer to any ring element
// serves as reference to the entire ring. Empty rings are represented
// as nil Ring pointers. The zero value for a Ring is a one-element
// ring with a nil Value.
//
type Ring struct {
	next, prev *Ring
	Value      interface{} // for use by client; untouched by this library
}

(3)创建和查看  

package main

import (
	"container/ring"
	"fmt"
)

func main() {
	//r代表整个循环链表,又代表第一个元素
	r := ring.New(5)
	r.Value = 0
	r.Next().Value = 1
	r.Next().Next().Value = 2
	//r.Next().Next().Next().Value = 3
	//r.Next().Next().Next().Next().Value = 4
	r.Prev().Value = 4
	r.Prev().Prev().Value = 3
	//查看元素内容
	//循环链表有几个元素,func就执行几次,i当前执行元素的内容
	r.Do(func(i interface{}) {
		fmt.Print(i, " ")      //0 1 2 3 4
	})
	fmt.Println("")
	//取中间元素,用移动
	fmt.Println(r.Move(3).Value)   //3

}

(4)增加

package main

import (
	"container/ring"
	"fmt"
)

func main() {
	//r代表整个循环链表,又代表第一个元素
	r := ring.New(5)
	r.Value = 0
	r.Next().Value = 1
	r.Next().Next().Value = 2
	//r.Next().Next().Next().Value = 3
	//r.Next().Next().Next().Next().Value = 4
	r.Prev().Value = 4
	r.Prev().Prev().Value = 3

	//增加
	r1 := ring.New(2)
	r1.Value = 5
	r1.Next().Value = 6
	r.Link(r1)

	r.Do(func(i interface{}) {
		fmt.Print(i, " ")    //0 5 6 1 2 3 4
	})
}

(5)删除

package main

import (
	"container/ring"
	"fmt"
)

func main() {
	//r代表整个循环链表,又代表第一个元素
	r := ring.New(5)
	r.Value = 0
	r.Next().Value = 1
	r.Next().Next().Value = 2
	//r.Next().Next().Next().Value = 3
	//r.Next().Next().Next().Next().Value = 4
	r.Prev().Value = 4
	r.Prev().Prev().Value = 3

	//删除
	r.Unlink(1)

	r.Do(func(i interface{}) {
		fmt.Print(i, " ")    //0 2 3 4
	})
}

删除后面两个

//删除
	r.Unlink(2)

	r.Do(func(i interface{}) {
		fmt.Print(i, " ")    //0 3 4
	})

r.Next()删除

//删除
	r.Next().Unlink(2)

	r.Do(func(i interface{}) {
		fmt.Print(i, " ")    //0 1 4
	})qu  

超出范围,取5的余数

//删除
	r.Unlink(6)

	r.Do(func(i interface{}) {
		fmt.Print(i, " ")    //0 2 3 4
	})

  

原文地址:https://www.cnblogs.com/gaidy/p/11757358.html

时间: 2024-08-10 13:51:28

1.Go-copy函数、sort排序、双向链表、list操作和双向循环链表的相关文章

算法学习 - STL的p排序函数(sort)使用

排序函数sort() 这个函数是STL自带的,功能很强大~ 这里教下使用方法. sort()有三个参数,第一个是排序的起始位置,第二个是排序的结束位置,第三个是排序的判断函数.函数原型为: sort(<#_RandomAccessIterator __first#>, <#_RandomAccessIterator __last#>, <#_Compare __comp#>) 这个就是原型了~ 使用方法 首先假设我们有一个vector<int> vec;向量

泛型编程与C++标准模板库 : 浅谈sort()排序函数

以前用sort排序的时候,只知道sort函数有如下两种重载方式. template< class RandomIt > void sort( RandomIt first, RandomIt last ); template< class RandomIt, class Compare > void sort( RandomIt first, RandomIt last, Compare comp ); 当时对这些参数也不是很懂,只知道一些简单的用法. 1).比如: 如下代码可以使

C++ 排序函数 sort(),qsort()的使用方法

想起来自己天天排序排序,冒泡啊,二分查找啊,结果在STL中就自带了排序函数sort,qsort,总算把自己解脱了~ 所以自己总结了一下,首先看sort函数见下表: 函数名 功能描写叙述 sort 对给定区间全部元素进行排序 stable_sort 对给定区间全部元素进行稳定排序 partial_sort 对给定区间全部元素部分排序 partial_sort_copy 对给定区间复制并排序 nth_element 找出给定区间的某个位置相应的元素 is_sorted 推断一个区间是否已经排好序 p

排序函数sort用法简介

排序算法有很多,冒泡排序,选择排序,堆排序,快速排序,归并排序,基数排序-- 其中平均复杂度O(nlogn)的排序算法或者在某方面有特殊优势的算法在ACM中才有实际使用价值,所以上述提到的前2种大家以后就不要用了.其他排序算法大家会慢慢接触,本文主要介绍使用最多的排序函数 sort.大家可能会遇到qsort,qsort比较复杂,逐渐淡出ACMer的视线,所以不用管它. sort函数是C++标准库函数,需要包含头文件 #include <algorithm> 并声明命名空间 using name

python排序函数sort()与sorted()区别

sort是容器的函数:sort(cmp=None, key=None, reverse=False) sorted是python的内建函数:sorted(iterable, cmp=None, key=None, reverse=False) 参数解析: cmp:比较函数,比较什么参数由key决定.例如:cmp(e1, e2) 是具有两个参数的比较函数,返回值:负数(e1 < e2):0(e1 == e2):正数( e1 > e2).key:用列表元素的某个属性或函数作为关键字.reverse

c++标准库里的sort()排序函数

Sort()函数是c++一种排序方法之一,学会了这种方法也打消我学习c++以来使用的冒泡排序和选择排序所带来的执行效率不高的问题!因为它使用的排序方法是类似于快排的方法,时间复杂度为n*log2(n),执行效率较高!一,sort()排序函数的使用方法I)Sort函数包含在头文件为#include<algorithm>的c++标准库中,调用标准库里的排序方法可以不必知道其内部是如何实现的,只要出现我们想要的结果即可!II)Sort函数有三个参数:Sort(start,end,排序方法)(1)第一

PHP排序函数sort底层实现分析

线性表(即线性数据结构,如数组和链表)的常规排序算法,包括冒泡.插入.选择.归并和快排,其中综合性能最好的就是快排(快速排序),所以快排在工程实践中也有大量的应用,比如很多编程语言都提供了排序函数,而这些排序函数基本都是基于快速排序实现的,比如 PHP 的数组排序函数 sort 就是如此. 今天我们将以此函数的底层实现为例,为大家展示如何基于快速排序来实现 PHP 的 sort 函数(准确的说,是综合运用了插入排序和快速排序). PHP 数组排序函数 sort 底层实现分析 首先我们来给大家介绍

STL源代码分析——STL算法sort排序算法

前言 因为在前文的<STL算法剖析>中,源代码剖析许多,不方便学习,也不方便以后复习.这里把这些算法进行归类,对他们单独的源代码剖析进行解说.本文介绍的STL算法中的sort排序算法,SGI STL中的排序算法不是简单的高速排序,而是交叉利用各种排序:堆排序.插入排序和高速排序:这样做的目的是提高效率.针对数据量比較大的採用高速排序,数据量比較小的能够採用堆排序或插入排序. 本文介绍了有关排序的算法random_shuffle.partition.stable_partition.sort.s

STL源码剖析——STL算法之sort排序算法

前言 由于在前文的<STL算法剖析>中,源码剖析非常多,不方便学习,也不方便以后复习,这里把这些算法进行归类,对他们单独的源码剖析进行讲解.本文介绍的STL算法中的sort排序算法,SGI STL中的排序算法不是简单的快速排序,而是交叉利用各种排序:堆排序.插入排序和快速排序:这样做的目的是提高效率,针对数据量比较大的采用快速排序,数据量比较小的可以采用堆排序或插入排序.注意:STL的sort排序算法的迭代器必须是随机访问迭代器. sort排序算法剖析 // Return a random n