大四了,准备投简历找工作,今天刚好遇到一道c#面试题,我一般自我感觉良好,本想三下五除二解决掉的,没想到花了近一个小时的时间才解决掉 。
题目如上描述,从题目中我们可以得出以下几个要求:
1、ID是自增的,第一级节点的FID为0
2、SHOW为1的节点才显示,否则隐藏
3、同一个父节点下的子节点,如果SHOWDER相同,则ID大的不显示
4、题目好像只输出了三级节点,但是我想四级、五级甚至N级都应该可以输出,所以应该采用递归的方法实现
综合考虑上述题目要求,我的解决方案如下,一下代码是在Visual Studio 2008中实现的,其它版本的vs请参考,数据库创建过程略。
1、C#既然是面向对象的,我们就应该充分发挥它面向对象的优势,所以我创建了一个类Node用于表示一个数据节点
代码
using
System.Collections.Generic;
namespace 面试OfferTest.Model
{
public class Node
{
public int ID { get ; set ; }
public int FID { get ; set ; }
public string nodeName { get ; set ; }
public int showder { get ; set ; }
public int show { get ; set ; }
public List < Node > childNodes { get ; set ; } // 这个Node下子节点列表
public bool flag { get ; set ; } // 指示该节点是否已经输出过
public Node()
{
childNodes = new List < Node > (); // 为列表分配空间
}
}
}
namespace 面试OfferTest.Model
{
public class Node
{
public int ID { get ; set ; }
public int FID { get ; set ; }
public string nodeName { get ; set ; }
public int showder { get ; set ; }
public int show { get ; set ; }
public List < Node > childNodes { get ; set ; } // 这个Node下子节点列表
public bool flag { get ; set ; } // 指示该节点是否已经输出过
public Node()
{
childNodes = new List < Node > (); // 为列表分配空间
}
}
}
2、读取数据初始化节点列表
代码
static
void
Main(
string
[] args)
{
var NodeList = new List < Node > (); // 整个节点列表
var connstr = @" Data Source=.\SQLEXPRESS;AttachDbFilename=F:\C#\面试OfferTest\面试OfferTest\MyTest.mdf;Integrated Security=True;User Instance=True " ; // 这里为了方便就把连接字符串写死了,您最好放到配置文件中……
if (String.IsNullOrEmpty(connstr))
return ;
using (var conn = new SqlConnection(connstr))
{
if (conn.State == ConnectionState.Closed)
conn.Open();
var sqlstr = " select * from TreeTest Order by ID " ;
var comm = new SqlCommand(sqlstr, conn);
var reads = comm.ExecuteReader();
while (reads.Read())
{
var node = new Node
{
ID = reads.GetInt32( 0 ),
FID = reads.GetInt32( 1 ),
nodeName = reads.GetString( 2 ),
showder = reads.GetInt32( 3 ),
show = reads.GetInt32( 4 ),
flag = false
};
NodeList.Add(node);
if (node.FID != 0 ) // 如果不是一级节点就应该有父节点,把该节点添加到父节点的子节点列表
{
var parentnode = NodeList.FirstOrDefault(p => p.ID == node.FID); // 查找父节点
if (parentnode == null ) return ;
if (parentnode.childNodes.FirstOrDefault(p => p.showder == node.showder) == null )
parentnode.childNodes.Add(node);
else
{ // 相同showder的设置为不显示
node.show = 0 ;
}
}
}
}
foreach (var row in NodeList.OrderBy(p => p.ID))
{
PrintTree(row, 0 ); // 递归输出节点信息
}
Console.Read();
}
{
var NodeList = new List < Node > (); // 整个节点列表
var connstr = @" Data Source=.\SQLEXPRESS;AttachDbFilename=F:\C#\面试OfferTest\面试OfferTest\MyTest.mdf;Integrated Security=True;User Instance=True " ; // 这里为了方便就把连接字符串写死了,您最好放到配置文件中……
if (String.IsNullOrEmpty(connstr))
return ;
using (var conn = new SqlConnection(connstr))
{
if (conn.State == ConnectionState.Closed)
conn.Open();
var sqlstr = " select * from TreeTest Order by ID " ;
var comm = new SqlCommand(sqlstr, conn);
var reads = comm.ExecuteReader();
while (reads.Read())
{
var node = new Node
{
ID = reads.GetInt32( 0 ),
FID = reads.GetInt32( 1 ),
nodeName = reads.GetString( 2 ),
showder = reads.GetInt32( 3 ),
show = reads.GetInt32( 4 ),
flag = false
};
NodeList.Add(node);
if (node.FID != 0 ) // 如果不是一级节点就应该有父节点,把该节点添加到父节点的子节点列表
{
var parentnode = NodeList.FirstOrDefault(p => p.ID == node.FID); // 查找父节点
if (parentnode == null ) return ;
if (parentnode.childNodes.FirstOrDefault(p => p.showder == node.showder) == null )
parentnode.childNodes.Add(node);
else
{ // 相同showder的设置为不显示
node.show = 0 ;
}
}
}
}
foreach (var row in NodeList.OrderBy(p => p.ID))
{
PrintTree(row, 0 ); // 递归输出节点信息
}
Console.Read();
}
3、递归函数的编写
代码
private static void PrintTree(Node node, int level)
{
// node表示待输出的节点,level表示它的深度,也就是它的级数-1
if (node == null ) return ;
if (node.show == 1 && node.flag == false )
{
var count = level;
while (count > 0 )
{
Console.Write( " | " );
count -- ;
}
Console.WriteLine( " |---- " + node.nodeName);
node.flag = true ; // 设置该节点已经输出过了
}
if (node.childNodes != null )
{
foreach (var item in node.childNodes.OrderBy(p => p.showder))
{
PrintTree(item,level + 1 ); // 递归下一个节点
}
}
}
private static void PrintTree(Node node, int level)
{
// node表示待输出的节点,level表示它的深度,也就是它的级数-1
if (node == null ) return ;
if (node.show == 1 && node.flag == false )
{
var count = level;
while (count > 0 )
{
Console.Write( " | " );
count -- ;
}
Console.WriteLine( " |---- " + node.nodeName);
node.flag = true ; // 设置该节点已经输出过了
}
if (node.childNodes != null )
{
foreach (var item in node.childNodes.OrderBy(p => p.showder))
{
PrintTree(item,level + 1 ); // 递归下一个节点
}
}
}
4、运行结果
1005-01-01-01是我为了测试递归添加的四级节点,由此说明递归取得的结果是正确的。
总结,由此看来面试题不容易,额,还需要狂补知识啊。呵呵,笑话,一笑而过……