"六度空间"的应用——找出两个陌生人之间的关系(二)

终于"完工"

      哎, 熬了好几个夜, 掉了好多根头发, 终于接近完工, 如果真的要拿给别人用还需要修补很多东西. 先发几张程序运行的图片吧:) 第一张是找出两人关系, 我试了很多人, 几乎都只需要通过一个人就能找到另一个人, 第二张是寻找XML文件中某个人有哪些好友.

存储内容的改进

      在写上篇博客的时候程序一直在运行(在保存人和人之间的完整对应关系), 我估算还需要好几个小时才能停下来, 所存储的XML文件也会大的惊人, 估算达到1GB以上, 其实运算之前这个时候的XML中已经包含了所有的人, 只不过暂时是一种类似"有向图"(A是B的好友, B不是A的好友)的关系, 现在运算的也只是把有向图的关系完全拓展开, 变成无向图(A是B的好友, B也是A的好友而已). 在发现完整关系的情况下, 存储所需要的空间如此之大时, 我放弃了这种方法. 在下载完所有人的头像照片(4万多张)后, 我把XML中每个节点的school和faceUri删除掉了, 这样存储人与人的关系只用了15.8MB.

      现在的存储结构如下:

<? xml version="1.0"?>
<Relations>
	<Person id="" name="">
		<Friend id="" name=""/>
		<Friend id="" name=""/>
		........
	</Person>
	<Person id="" name="">
		<Friend id="" name=""/>
		<Friend id="" name=""/>
		........
	</Person>
</Relations>

      从这个XML中通过一些XML的操作方法可以就可以得到很多信息了.

RelationOperate类

1. 每次定义一个RelationOperate类, 需要传进一个XML文件地址, 以对它进行操作

private XmlDocument xmlDoc = new XmlDocument();
public RelationOperate(string xmlDocPath)
{
    xmlDoc.Load(xmlDocPath);
}

2. 通过一个id找到他的好友列表

/// <summary>
/// 获取一个id的好友
/// </summary>
/// <param name="id">要查找的id</param>
/// <returns>该id的好友id列表</returns>
public List<string> getFriend(string id)
{
List<string> friendList = new List<string>();
var PersonList = xmlDoc.SelectNodes("//Person"); //所有的Person节点
foreach (XmlNode xmlNode in PersonList)
    //若果Person节点已经包含了该id的用户
    if (xmlNode.Attributes["id"].InnerText == id)
    {
        //则增加这个Person节点的每一个子节点到friendList中
        //因为他的每一个子节点都是他的好友
        foreach (XmlNode node in xmlNode.ChildNodes)
            friendList.Add(node.Attributes["id"].InnerText);
        return friendList;
    }
//上面的条件不满足时, 就查找哪些Person的子节点(朋友)里边包含这个id
foreach (XmlNode xmlNode in PersonList)
    foreach (XmlNode node in xmlNode.ChildNodes)
    {
        if (node.Attributes["id"].InnerText == id)
        {
            friendList.Add(xmlNode.Attributes["id"].InnerText);
            break;
        }
    }
return friendList;
}

3. 获取一个id的姓名

public string getName(string id)
{
var PersonList = xmlDoc.SelectNodes("//Person"); //所有的Person节点
foreach (XmlNode xmlNode in PersonList)
    //若果Person节点已经包含了该id的用户
    if (xmlNode.Attributes["id"].InnerText == id)
    {
        return xmlNode.Attributes["name"].InnerText;
    }
//上面的条件不满足时, 就查找哪些Person的子节点(朋友)里边包含这个id
string name = "";
foreach (XmlNode xmlNode in PersonList)
    foreach (XmlNode node in xmlNode.ChildNodes)
    {
        if (node.Attributes["id"].InnerText == id)
        {
            name = node.Attributes["name"].InnerText;
            return name;
        }
    }
return name;
}

4. 获取一个姓名的id号码

public string getID(string name)
{
    var PersonList = xmlDoc.SelectNodes("//Person"); //所有的Person节点
    foreach (XmlNode xmlNode in PersonList)
        //若果Person节点已经包含了该id的用户
        if (xmlNode.Attributes["name"].InnerText.Contains(name))
        {
            return xmlNode.Attributes["id"].InnerText;
        }
    //上面的条件不满足时, 就查找哪些Person的子节点(朋友)里边包含这个id
    foreach (XmlNode xmlNode in PersonList)
        foreach (XmlNode node in xmlNode.ChildNodes)
        {
            if (node.Attributes["name"].InnerText.Contains(name))
            {
                string id = node.Attributes["id"].InnerText;
                return id;
            }
        }
    return null;
}

5. 获取两个id之间的关系(广度优先)

public List<string> getRelation(string A, string B)
{
    //A直接认识B 0层关系
    var Afriend = getFriend(A);
    List<string> relation = new List<string>();
    foreach (string id in Afriend)
        if (id == B)
        {
            relation.Add(A);
            relation.Add(B);
            return relation;
        }
    //A的好友是B的好友  1层关系
    var Bfriend = getFriend(B);
    foreach (string friendA in Afriend)
        foreach (string friendB in Bfriend)
        {
            //A的某个朋友也是B的某个朋友
            if (friendA == friendB)
            {
                relation.Add(A);
                relation.Add(friendA);
                relation.Add(B);
                return relation;
            }
        }
    //A的好友的好友是B的好友 2层关系
    List<FriendFriend> AFriendFriend = new List<FriendFriend>();
    foreach (string friend in Afriend)
    {
        if (friend != B)    //涉及两层关系时, A的Friend不直接是B
        {
            FriendFriend ff = new FriendFriend();
            ff.parent = friend;
            ff.friend = getFriend(friend);
            AFriendFriend.Add(ff);
        }
    }
    foreach (FriendFriend ff in AFriendFriend)
    {
        foreach (string friend in ff.friend)
            //涉及两层关系时,A的Friend的Friend不直接是B
            if (friend != A)
            {
                foreach (string friendB in Bfriend)
                {
                    //B的朋友也不直接是A, B的朋友也不直接是A的朋友
                    if ((friendB != A) && (friendB != ff.parent))
                    {
                        if (friend == friendB)
                        {
                            relation.Add(A);
                            relation.Add(ff.parent);
                            relation.Add(friend);
                            relation.Add(B);
                            break;
                        }
                        return relation;
                    }
                }
            }
    }
    //涉及3层关系  A的好友的好友C 是 B的好友的好友
    //C一定是那个种子节点
    //还没写3层关系
    return relation;
}

总结

      结合上边的类操作已经保存好了的XML, 可以用WPF或者其它做出一些找关系的程序, 在自己的网站上加上这么一个功能, 很绚丽的哦. 另外我还发现应该用手机人人网的协议接口, 那个页面下载的内容精简, 没有很复杂的CSS, Javascript等等, 以后真正要做出应用的话应该研究手机版的协议. 本文也只是提供一个思路, 可以做出一个这个东西. 另外真正了解"六度空间"的威力也是很好的, 如果一个产品被20个人看到, 每个人推荐给了另外的20个人...循环下去, 这个对产品的推广是十分有好处的. 当下很多东西正是基于"六度空间"的这个理论, 用户群变得超级庞大.

posted @ 2011-01-17 23:10  Create Chen  阅读(...)  评论(...编辑  收藏