本文目录一览:
- 1、golang如何创建目录
- 2、golang变量(二)——map和slice详解
- 3、怎么将数据库中存的树转化为树形列表
- 4、怎么用递归实现1-10的求和 golang
- 5、golang结构体组合与“多态” 2021-08-06
- 6、Linq To Sql 如何实现递归查询 树形结构
golang如何创建目录
golang中关于目录与文件名等操作都在os这个包中,具体的创建目录都是通过Mkdir和MkdirAll这2个函数来实现的,这两个函数用法一致
os.Mkdir(dirName string, perm FileMode)
dirName即要创建的目录(文件夹路径),可以是绝对路径,也可以是相对路径(相对于GOPATH)
perm表示创建的目录的权限,如0777(读r权限值为4,写权限w值为2,执行权限x值为1)
如:我要在/data/program/goapp这个目录下创建一个golang这个子目录,示例如下:
package main
import (
"os"
"fmt"
)
func main() {
err := os.Mkdir("/data/program/goapp/golang", 0666)
if err != nil {
fmt.Println(err)
}
}
注:Mkdir和MkdirAll的区别
Mkdir创建目录,它的父级目录必须是存在的,不然创建会失败
MkdirAll可以递归创建目录,即只要根目录存在即可,如下:
err := os.MkdirAll("/data/program/goapp/golang/test/hello", 0766)
if err != nil {
fmt.Println(err)
}
本例中:/data/program/goapp是已经存在的目录,而子目录golang/test/hello是不存在,此时要使用MkdirAll来创建
golang变量(二)——map和slice详解
衍生类型,interface{} , map, [] ,struct等
map类似于java的hashmap,python的dict,php的hash array。
常规的for循环,可以用for k,v :=range m {}. 但在下面清空有一个坑注意:
著名的map[string]*struct 副本问题
结果:
Go 中不存在引用传递,所有的参数传递都是值传递,而map是等同于指针类型的,所以在把map变量传递给函数时,函数对map的修改,也会实质改变map的值。
slice类似于其他语言的数组(list,array),slice初始化和map一样,这里不在重复
除了Pointer数组外,len表示使用长度,cap是总容量,make([]int, len, cap)可以预申请 比较大的容量,这样可以减少容量拓展的消耗,前提是要用到。
cap是计算切片容量,len是计算变量长度的,两者不一样。具体例子如下:
结果:
分析:cap是计算当前slice已分配的容量大小,采用的是预分配的伙伴算法(当容量满时,拓展分配一倍的容量)。
append是slice非常常用的函数,用于添加数据到slice中,但如果使用不好,会有下面的问题:
预期是[1 2 3 4 5 6 7 8 9 10], [1 2 3 4 5 6 7 8 9 10 11 12],但实际结果是:
注意slice是值传递,修改一下:
输出如下:
== 只能用于判断常规数据类型,无法使用用于slice和map判断,用于判断map和slice可以使用reflect.DeepEqual,这个函数用了递归来判断每层的k,v是否一致。
当然还有其他方式,比如转换成json,但小心有一些异常的bug,比如html编码,具体这个json问题,待后面在分析。
怎么将数据库中存的树转化为树形列表
树状结构的数据保存在数据库中的常用方法有一下两种:
1、邻接表(adjacency list model)
2、预排序遍历树算法(modified preorder tree traversal algorithm)
用一下的例子讨论这两种方法的差异:
现有一棵树如下:
邻接表模式:
这种模式我们经常用到,很多的教程和书中也介绍过。我们通过给每个节点增加一个属性 parent 来表示这个节点的父节点从而将整个树状结构通过平面的表描述出来。根据这个原则,例子中的数据可以转化成如下的表:
我们看到 Pear 是Green的一个子节点,Green是Fruit的一个子节点。而根节点'Food'没有父节点。 为了简单地描述这个问题, 这个例子中只用了name来表示一个记录。 在实际的数据库中,你需要用数字的id来标示每个节点,数据库的表结构大概应该像这样:id, parent_id, name, description。
以下是代码:
?php
// $parent is the parent of the children we want to see
// $level is increased when we go deeper into the tree,
// used to display a nice indented tree
function display_children($parent, $level)
{
// 获得一个 父节点 $parent 的所有子节点
$result = mysql_query('SELECT name FROM tree '.
'WHERE parent="'.$parent.'";');
// 显示每个子节点
while ($row = mysql_fetch_array($result))
{
// 缩进显示节点名称
echo str_repeat(' ',$level).$row['name']."n";
//再次调用这个函数显示子节点的子节点
display_children($row['name'], $level+1);
}
}
?
对整个结构的根节点(Food)使用这个函数就可以打印出整个多级树结构,由于Food是根节点它的父节点是空的,所以这样调用: display_children('',0)。将显示整个树的内容:
Food
Fruit
Red
Cherry
Yellow
Banana
Meat
Beef
Pork
如果你只想显示整个结构中的一部分,比如说水果部分,就可以这样调用:display_children('Fruit',0);
几乎使用同样的方法我们可以知道从根节点到任意节点的路径。比如 Cherry 的路径是 "Food ; Fruit ; Red"。 为了得到这样的一个路径我们需要从最深的一级"Cherry"开始, 查询得到它的父节点"Red"把它添加到路径中, 然后我们再查询Red的父节点并把它也添加到路径中,以此类推直到最高层的"Food"
以下是代码:
?php
// $node 是那个最深的节点
function get_path($node)
{
// 查询这个节点的父节点
$result = mysql_query('SELECT parent FROM tree '.
'WHERE name="'.$node.'";');
$row = mysql_fetch_array($result);
// 用一个数组保存路径
$path = array();
// 如果不是根节点则继续向上查询
// (根节点没有父节点)
if ($row['parent']!='')
{
// the last part of the path to $node, is the name
// of the parent of $node
$path[] = $row['parent'];
// we should add the path to the parent of this node
// to the path
$path = array_merge(get_path($row['parent']), $path);
}
// return the path
return $path;
}
?
如果对"Cherry"使用这个函数:print_r(get_path('Cherry')),就会得到这样的一个数组了:
Array
(
[0] =; Food
[1] =; Fruit
[2] =; Red
)
接下来如何把它打印成你希望的格式,就是你的事情了。
缺点:
这种方法很简单,容易理解,好上手。但是也有一些缺点。主要是因为运行速度很慢,由于得到每个节点都需要进行数据库查询,数据量大的时候要进行很多查询才能完成一个树。另外由于要进行递归运算,递归的每一级都需要占用一些内存所以在空间利用上效率也比较低。
预排序遍历树算法
现在让我们看一看另外一种不使用递归计算,更加快速的方法,这就是预排序遍历树算法(modified preorder tree traversal algorithm) 这种方法大家可能接触的比较少,初次使用也不像上面的方法容易理解,但是由于这种方法不使用递归查询算法,有更高的查询效率。
我们首先将多级数据按照下面的方式画在纸上,在根节点Food的左侧写上 1 然后沿着这个树继续向下 在 Fruit 的左侧写上 2 然后继续前进,沿着整个树的边缘给每一个节点都标上左侧和右侧的数字。最后一个数字是标在Food 右侧的 18。 在下面的这张图中你可以看到整个标好了数字的多级结构。(没有看懂?用你的手指指着数字从1数到18就明白怎么回事了。还不明白,再数一遍,注意移动你的手指)。
这些数字标明了各个节点之间的关系,"Red"的号是3和6,它是 "Food" 1-18 的子孙节点。 同样,我们可以看到 所有左值大于2和右值小于11的节点 都是"Fruit" 2-11 的子孙节点
这样整个树状结构可以通过左右值来存储到数据库中。继续之前,我们看一看下面整理过的数据表。
注意:由于"left"和"right"在 SQL中有特殊的意义,所以我们需要用"lft"和"rgt"来表示左右字段。 另外这种结构中不再需要"parent"字段来表示树状结构。也就是 说下面这样的表结构就足够了。
SELECT * FROM tree WHERE lft BETWEEN 2 AND 11;
看到了吧,只要一个查询就可以得到所有这些节点。为了能够像上面的递归函数那样显示整个树状结构,我们还需要对这样的查询进行排序。用节点的左值进行排序:
SELECT * FROM tree WHERE lft BETWEEN 2 AND 11 ORDER BY lft ASC;
那么某个节点到底有多少子孙节点呢?很简单,子孙总数=(右值-左值-1)/2
descendants = (right – left - 1) / 2 ,如果不是很清楚这个公式,那就去翻下书,我们在上数据结构写的很清楚!
添加同一层次的节点的方法如下:
LOCK TABLE nested_category WRITE;
SELECT @myRight := rgt FROM nested_category WHERE name = 'Cherry';
UPDATE nested_category SET rgt = rgt + 2 WHERE rgt @myRight;
UPDATE nested_category SET lft = lft + 2 WHERE lft @myRight;
INSERT INTO nested_category(name, lft, rgt) VALUES('Strawberry', @myRight + 1, @myRight + 2);
UNLOCK TABLES;
添加树的子节点的方法如下:
LOCK TABLE nested_category WRITE;
SELECT @myLeft := lft FROM nested_category WHERE name = 'Beef';
UPDATE nested_category SET rgt = rgt + 2 WHERE rgt @myLeft;
UPDATE nested_category SET lft = lft + 2 WHERE lft @myLeft;
INSERT INTO nested_category(name, lft, rgt) VALUES('charqui', @myLeft + 1, @myLeft + 2);
UNLOCK TABLES;
每次插入节点之后都可以用以下SQL进行查看验证:
SELECT CONCAT( REPEAT( ' ', (COUNT(parent.name) - 1) ), node.name) AS name
FROM nested_category AS node,
nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.name
ORDER BY node.lft;
删除节点的方法,稍微有点麻烦是有个中间变量,如下:
LOCK TABLE nested_category WRITE;
SELECT @myLeft := lft, @myRight := rgt, @myWidth := rgt - lft + 1
FROM nested_category WHERE name = 'Cherry';
DELETE FROM nested_category WHERE lft BETWEEN @myLeft AND @myRight;
UPDATE nested_category SET rgt = rgt - @myWidth WHERE rgt @myRight;
UPDATE nested_category SET lft = lft - @myWidth WHERE lft @myRight;
UNLOCK TABLES;
这种方式就是有点难的理解,但是适合数据量很大规模使用,查看所有的结构只需要两条SQL语句就可以了,在添加节点和删除节点的时候略显麻烦,不过相对于效率来说还是值得的。
怎么用递归实现1-10的求和 golang
1、打出主函数defs(n):ifn=1。
2、在打出条件函数return1else:result=n+s(n-1)return.result。
3、最后结尾返回函数的值result=s(10)print(result)。
golang结构体组合与“多态” 2021-08-06
如:
核心思想就是, 外层实现接口,通过递归嵌套将被实现的接口实例置于内层,从而达到外层定义,内层使用的效果 :
BaseBase和Derived都是外层结构体,在它们这一层实现了F2()。ori_impl_1以及ori_impl_2都是外层结构体实现的B接口实例,置于内层完成调用
struct中的字段可以不用给名称,这时称为匿名字段。匿名字段的名称强制和类型相同。例如:
如果struct中嵌套的struct类型是自己的指针类型,可以用来生成链表或二叉树等数据结构
例如,定义一个单链表数据结构
Linq To Sql 如何实现递归查询 树形结构
--构造测试数据: 只作演示用
CREATE TABLE [dbo].[Tim_LinqTable](
[Id] int PRIMARY KEY IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL,
[Parent] int NOT NULL,
)
GO
INSERT INTO [Tim_LinqTable]
SELECT 'A',0 UNION ALL
SELECT 'A1',1 UNION ALL
SELECT 'A2',1 UNION ALL
SELECT 'B1',2 UNION ALL
SELECT 'B2',3 UNION ALL
SELECT 'C1',4 UNION ALL
SELECT 'C2',4 UNION ALL
SELECT 'D1',5 UNION ALL
SELECT 'D2',5 UNION ALL
SELECT 'D3',5
GO
WITH temp
AS
(
SELECT * FROM [Tim_LinqTable] WHERE Parent = 3
UNION ALL
SELECT m.* FROM [Tim_LinqTable] AS m
INNER JOIN temp AS child ON m.Parent = child.Id
)
SELECT * FROM temp
GO
--查询 Parent=3 的所有子数据结果如下:
Id Name Parent
----------- -------------------------------------------------- -----------
5 B2 3
8 D1 5
9 D2 5
10 D3 5
(4 row(s) affected)
//好,下边来看看用C#怎么实现上边的SQL语句吧:
void Main()
{
var query=GetClassID(3);
Console.WriteLine("Id\tName\tParent");
query.ToList().ForEach(q=Console.WriteLine("{0}\t{1}\t{2}",q.Id,q.Name,q.Parent));
/*
Id Name Parent
5 B2 3
8 D1 5
9 D2 5
10 D3 5
*/
}
public IEnumerableTim_LinqTable GetClassID(int p_id)
{
var query = from c in this.Tim_LinqTables
where c.Parent == p_id
select c;
return query.ToList().Concat(query.ToList().SelectMany(t = GetClassID(t.Id)));
}