Gale Shapely算法的实现

来源:互联网 发布:mac倍速看视频 编辑:程序博客网 时间:2024/05/01 08:47

算法的第一趟课,老师将Gale Shapely算法作为课程的开始。听下来觉得这个算法蛮有趣的,课下自己用c#实现了一下。

“盖尔-沙普利算法”是实现稳定配对的一个算法。参与匹配的对象分为两组,主动匹配和被动匹配。每个对象都维护了自己的一个偏好列表,喜欢程度依次递减。开始时所有主动匹配组内的对象均设置为未配对。

算法的思想就是从主动匹配的组中挑选一个为匹配的对象,从他的偏好列表中依次查找,如果找到的对象未配对,则配对。

如果已配对,但是对方的偏好列表中更偏好你,那么你们配对,对方原先配对的对象被标注为未配对。
如果已配对,但是对方的偏好列表中你不如他当前配对的,那么你就继续从自己的偏好列表中往下找。
直到所有的主动匹配组中的对象都已配对,或者所有的偏好列表都找了一遍(没有找到稳定匹配)。

代码如下:

/// <summary>    /// 匹配对象    /// </summary>    public class GSMatchingItem    {        private GSMatchingItem matchingItem;        public GSMatchingItem(string name)        {            this.Name = name;            this.ID = Guid.NewGuid();            LastMathingIndex = 0;            matchingItem = null;        }        public string Name { get; set; }        public Guid ID { get; set; }        /// <summary>        /// 偏好列表        /// </summary>        public List<Guid> PreferenceList { get; set; }        public GSMatchingItem MatchingItem { get { return matchingItem; } set { matchingItem = value; } }        public bool IsMatched { get { return matchingItem != null; } }        //上一次从偏好列表匹配的索引        public int LastMathingIndex { get; set; }    }     /// <summary>    /// 匹配算法类    /// </summary>    public class GSMatching    {        private List<Guid> freeList;        public GSMatching()        {            PositiveMathingItemList = new List<GSMatchingItem>();            NegativeMathingItemList = new List<GSMatchingItem>();        }        public List<GSMatchingItem> PositiveMathingItemList { get; set; }        public List<GSMatchingItem> NegativeMathingItemList { get; set; }        public void AddPositiveMathingItem(List<GSMatchingItem> items)        {            PositiveMathingItemList.AddRange(items);        }        public void AddPositiveMathingItem(GSMatchingItem item)        {            PositiveMathingItemList.Add(item);        }        public void AddNegativeMathingItem(List<GSMatchingItem> items)        {            NegativeMathingItemList.AddRange(items);        }        public void AddNegativeMathingItem(GSMatchingItem item)        {            NegativeMathingItemList.Add(item);        }        private void Reset()        {            freeList = new List<Guid>();            freeList.AddRange(PositiveMathingItemList.Select(p => p.ID).ToArray());            foreach (var item in PositiveMathingItemList)            {                item.MatchingItem = null;            }            foreach (var item in NegativeMathingItemList)            {                item.MatchingItem = null;            }        }        public List<GSMatchingItem> Match()        {            Reset();            int totalCount = PositiveMathingItemList.Sum(p => p.PreferenceList.Count);            int count = 0;            while (!(freeList.Count == 0 || count == totalCount))            {                var pItem = PositiveMathingItemList.Where(p => p.ID == freeList[0]).FirstOrDefault();                //所有的偏好都找过了                if (pItem.PreferenceList.Count <= pItem.LastMathingIndex) continue;                //找到可用的最喜欢的                var pItemTo = NegativeMathingItemList.Where(p => p.ID == pItem.PreferenceList[pItem.LastMathingIndex]).FirstOrDefault();                count++;                //如果目标没有配对,则直接配对                if (!pItemTo.IsMatched)                {                    pItemTo.MatchingItem = pItem;                    pItem.MatchingItem = pItemTo;                    freeList.Remove(pItem.ID);                    pItem.LastMathingIndex++;                }                else                {                    var pItemPreferIndex = pItemTo.PreferenceList.IndexOf(pItem.ID);                    var pItemToMatchingItemPreferIndex = pItemTo.PreferenceList.IndexOf(pItemTo.MatchingItem.ID);                    //已配对,且目标偏好列表中当前配对的不如你                    if (pItemPreferIndex != -1 && pItemPreferIndex < pItemToMatchingItemPreferIndex)                    {                        //已配对的那个扔回空闲队列                        var matchedItem = pItemTo.MatchingItem;                        matchedItem.MatchingItem = null;                        freeList.Add(matchedItem.ID);                        pItem.MatchingItem = pItemTo;                        pItemTo.MatchingItem = pItem;                        freeList.Remove(pItem.ID);                        pItem.LastMathingIndex++;                    }                    //已配对的看不上你,继续找下一个                    else                    {                        pItem.LastMathingIndex++;                    }                }            }            List<GSMatchingItem> result = new List<GSMatchingItem>();            foreach (var item in PositiveMathingItemList)            {                if (item.IsMatched)                {                    result.Add(item);                }            }            return result;        }    }    static void Main(string[] args)        {            GSMatching gsMatching = new GSMatching();            //主动匹配的对象            var p1 = new GSMatchingItem("A");            var p2 = new GSMatchingItem("B");            var p3 = new GSMatchingItem("C");            var p4 = new GSMatchingItem("D");            //被动匹配的对象            var n1 = new GSMatchingItem("1");            var n2 = new GSMatchingItem("2");            var n3 = new GSMatchingItem("3");            var n4 = new GSMatchingItem("4");            //p1,p2,p3...的偏好列表            p1.PreferenceList = new List<Guid>() { n3.ID, n4.ID, n2.ID, n1.ID };            p2.PreferenceList = new List<Guid>() { n3.ID, n2.ID, n4.ID, n1.ID };            p3.PreferenceList = new List<Guid>() { n1.ID, n3.ID, n4.ID, n2.ID };            p4.PreferenceList = new List<Guid>() { n2.ID, n4.ID, n3.ID, n1.ID };            //n1,n2,n3...的偏好列表            n1.PreferenceList = new List<Guid>() { p1.ID, p4.ID, p3.ID, p2.ID };            n2.PreferenceList = new List<Guid>() { p1.ID, p2.ID, p3.ID, p4.ID };            n3.PreferenceList = new List<Guid>() { p1.ID, p3.ID, p4.ID, p2.ID };            n4.PreferenceList = new List<Guid>() { p2.ID, p1.ID, p4.ID, p3.ID };            gsMatching.AddPositiveMathingItem(new List<GSMatchingItem>() { p1, p2, p3, p4 });            gsMatching.AddNegativeMathingItem(new List<GSMatchingItem>() { n1, n2, n3, n4 });            var result = gsMatching.Match();            foreach (var item in result)            {                Console.WriteLine("{0} hook up {1}", item.Name, item.MatchingItem.Name);            }            Console.Read();        }
0 0
原创粉丝点击