某树状结构排序

13 篇文章 0 订阅
7 篇文章 0 订阅

对象Q有pk,亲pk和表示顺3个属性,它的实例组成list,现在需要按树状结构(按亲->子,同级再按表示顺小到大)排序。

逻辑部分:

function testNum(qs,orderedList){					//非逻辑部分,简单测试用
	console.log('length-->',qs.length,orderedList.length)
	if(qs.length!=orderedList.length){
		for(let i in qs){
			let pk=qs[i].pk
			var flg=false
			for(let j in orderedList){
				if(orderedList[j].pk==pk){flg=true;break}
			}
			if(!flg){console.log(pk,'not found in orderedList')}
		}
	}
}

function print(orderedList){						//非逻辑部分,简单测试用
	let split='->'
	for(let i in orderedList){
		let q=orderedList[i]
		var prefix=''
		let depth=q.depth
		delete q.depth
		for(j=0;j<depth;j++){
			prefix=prefix+split
		}
		console.log(prefix,q)
	}
}

/*
qs.sort可以在sql文里进行,目的是使同级别的对象按表示顺逆序排列。
marked是搜索时用来标识已经走过的点,防止重复走。此例不存在一个pk对应两个ppk的情况,所以不需要。
//--------------标记的代码是记录深度,如果只排序不需要。
思路是遍历list,生成有向图,所有点加入图中,没有亲的点(顶点)还要入栈,之后dfs。
时间空间复杂度都是线性,和list.length成正比。
*/
function getOrderedList(qs){
	function sortByOrderDesc(a,b){
		return b.order-a.order
	}
	qs.sort(sortByOrderDesc)
	var stack=[]
	var graph={}
	//var marked={}
	var orderedList=[]
	for(let i in qs){
		let q=qs[i]
		let pk=q.pk
		let ppk=q.ppk
		//marked[pk]=false
		if(ppk=='null'){
			q.depth=0					//--------------
			stack.push(q)
		}else{
			if(graph[ppk]==undefined){
				graph[ppk]=[]
			}
			graph[ppk].push(q)
		}
	}

	while(stack.length>0){
		let q=stack.pop()
		let pk=q.pk
		//if(marked[pk])continue
		orderedList.push(q)
		//marked[pk]=true
		if(graph[pk]!=undefined){	
			let depth=q.depth+1			//--------------
			for(let i in graph[pk]){		//--------------
				graph[pk][i].depth=depth	//--------------	
			}								//--------------
			stack=stack.concat(graph[pk])
		}
	}
	return orderedList
}



var qs=[{pk:1,ppk:"null",order:1,},{pk:3,ppk:"null",order:3,},
{pk:5,ppk:"null",order:5,},{pk:7,ppk:"null",order:7,},pk:8,ppk:"null",order:8,},
{pk:9,ppk:"null",order:9,},{pk:17,ppk:1,order:7,},{pk:37,ppk:3,order:7,},
{pk:55,ppk:5,order:5,},{pk:77,ppk:7,order:7,},{pk:80,ppk:8,order:19,},
{pk:91,ppk:9,order:1,},{pk:93,ppk:9,order:3,},{pk:171,ppk:17,order:1,},
{pk:379,ppk:37,order:9,},{pk:550,ppk:55,order:19,},{pk:774,ppk:77,order:15,},
{pk:913,ppk:91,order:3,},{pk:937,ppk:93,order:7,},]
let orderedList=getOrderedList(qs)
testNum(qs,orderedList)
print(orderedList)

sql部分:@tmp用来防止找不到@p对应的数据时@p不变,出现死循环。
思路是在@str里找分隔符’,’,找不到说明str里只有一个pk,lp:loop查询完后退出,否则找到就分割出一个pk给lp:loop查询,查询完后把该’,'后的字符串赋给@str,重复上述操作。

delimiter $
select * from q$
drop   procedure if exists p1$
create  procedure p1(in str varchar(99))
begin
	set @str=str;	
	drop  table if exists tmp;
    CREATE table tmp like q;
    lp:loop
		set @i1=instr(@str,',');
		if @i1=0 then
			set @tmp= @str;
		else
			set @tmp=substr(@str,1,@i1-1);
		end if;
   
		set @p=0+@tmp;
		ilp:loop
			set @tmp=@p;
			insert ignore  tmp  select pk,@p:=ppk,`order` from q where pk=@p;
            #select @p,sleep(3);
            
			if @p is null or @tmp=@p then
				leave ilp;
			end if;
		end loop;
        
		if @i1=0 then
			leave lp;
		else
            set @str=substr(@str,@i1+1);
		end if;
    end loop;
    select * from tmp;
end;
$

delimiter  ;
SELECT * FROM jd.q;
truncate q;
call p1('937,913,774,550,171,80,379');
call p1('11111');

vba部分:
用来生成有规律的数据方便测试,并用数据生成json字符串保存到剪切板供js代码使用

'[{pk:1,ppk:1,order:1},{pk:1,ppk:1,order:1},****]
Public Sub generate_test_json()
    json = "["
    With ActiveSheet
        col_count = .Cells(1, 222).End(1).Column        '3
        row_count = .Cells(55555, 1).End(3).Row         '??
        arrField = .Range(.Cells(1, 1), .Cells(1, col_count)).Value
        arr = .Range(.Cells(2, 1), .Cells(row_count, col_count)).Value
        For i = LBound(arr, 1) To UBound(arr, 1)
            json = json & "{"
            For j = LBound(arr, 2) To UBound(arr, 2)
                v = arr(i, j)
                If LCase(v) = "null" Then
                    v = """null"""
                End If
                json = json & arrField(1, j) & ":" & v & ","
            Next j
            json = json & "},"
        Next i
    End With
    json = json & "]"
    Debug.Print json
    With CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
        .SetText json
        .PutInClipboard
    End With
End Sub

'生成row_num个数据,每个亲下有jinzhi个子,除非数据量不够。
'表示顺pk按mod jinzhi后,奇数递增偶数递减的规则给值。
Public Sub generateData()
    row_num = CLng(InputBox("please insert your row_num", Default:=100))
    col_num = 3
    Dim arr()
    '这么设置arr并在后面转置是因为二维数组redim时只能redim最后一维。
    ReDim arr(1 To col_num, 1 To row_num)
    jinzhi = CLng(InputBox("please insert your jinzhi", Default:=10))
    For i = 1 To row_num
        arr(1, i) = i
        arr(2, i) = (i - i Mod jinzhi) / jinzhi
        arr(3, i) = getOrder(i, jinzhi)
    Next i
    For i = 1 To jinzhi
        arr(2, i) = "null"
    Next i
    
    With ActiveSheet
        .Cells.ClearContents
        .Cells(1, 1) = "pk"
        .Cells(1, 2) = "ppk"
        .Cells(1, 3) = "order"
        .Cells(2, 1).Resize(row_num, col_num) = Application.Transpose(arr)
    End With

End Sub



Function getOrder(ByVal pk As Long, Optional ByVal jinzhi As Long)
    o = pk Mod jinzhi
    If o Mod 2 = 0 Then
        o = jinzhi * 2 - 1 - o
    End If
    getOrder = o
End Function
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值