C# 经典实例 第二章 集合、枚举器和迭代器 #2.2 保持List<T>有序

问题:

你将使用List<T>的BinarySearch方法定期查找List<T>中的特定元素。在查找过程中,将穿插进行添加、修改和删除的操作。不过,BinarySearch方法预先假设数组是有序的。如果List<T>是无序的,BinarySearch方法可能返回不正确的结果。你不希望必须记住在调用List<T>.BinarySearch方法之前调用List<T>.Sort方法。更不必说会引入与该调用关联的所有开销。你需要采用一种方法保持List<T>有序,而不必总是调用List<T>.Sort方法。

解决方案:

下面SortedList泛型类增强了在List<T>内添加和修改元素的操作。在向其添加数据项或修改数据项时,这些方法可以保持数组有序。注意,这里并不需要DeleteSorted方法,因为删除数据项不会干扰剩余数据项的排序顺序。


        public class SortedList<T> : List<T>
        {
            public new void Add(T item)
            {
                int position = this.BinarySearch(item);
                if (position < 0)
                    position = ~position;

                this.Insert(position, item);
            }

            public void ModifySorted(T item, int index)
            {
                this.RemoveAt(index);

                int position = this.BinarySearch(item);
                if (position < 0)
                    position = ~position;

                this.Insert(position, item);
            }
        }

讨论:

在保持List<T>有序的同时使用Add方法添加元素。Add方法接受一个泛型类型(T)以添加到有序列表中。

不要直接使用List<T>索引器修改元素,而是使用ModifySorted方法修改元素,同时保持List<T>有序。调用这个方法,传入泛型类型T以替换现有的对象(item),并且传入要修改对象的索引(index)。

下面的代码演示了SortedList<T>类:

   public static void TestSortedList()
        {
            // Create a SortedList and populate it with 
            //    randomly choosen numbers
            SortedList<int> sortedList = new SortedList<int>();
            sortedList.Add(200);
            sortedList.Add(20);
            sortedList.Add(2);
            sortedList.Add(7);
            sortedList.Add(10);
            sortedList.Add(0);
            sortedList.Add(100);
            sortedList.Add(-20);
            sortedList.Add(56);
            sortedList.Add(55);
            sortedList.Add(57);
            sortedList.Add(200);
            sortedList.Add(-2);
            sortedList.Add(-20);
            sortedList.Add(55);
            sortedList.Add(55);

            // Display it
            foreach (var i in sortedList)
                Console.WriteLine(i);

            // Now modify a value at a particular index
            sortedList.ModifySorted(0, 5);
            sortedList.ModifySorted(1, 10);
            sortedList.ModifySorted(2, 11);
            sortedList.ModifySorted(3, 7);
            sortedList.ModifySorted(4, 2);
            sortedList.ModifySorted(2, 4);
            sortedList.ModifySorted(15, 0);
            sortedList.ModifySorted(0, 15);
            sortedList.ModifySorted(223, 15);

            // Display it
            Console.WriteLine();
            foreach (var i in sortedList)
                Console.WriteLine(i);

            // Doing it the hard way
            List<int> testList = new List<int>();
            testList.Add(200);
            testList.Sort();
            testList.Add(20);
            testList.Sort();
            testList.Add(2);
            testList.Sort();
            testList.Add(7);
            testList.Sort();
            testList.Add(10);
            testList.Sort();
            testList.Add(0);
            testList.Sort();
            testList.Add(100);
            testList.Sort();
            testList.Add(-20);
            testList.Sort();
            testList.Add(56);
            testList.Sort();
            testList.Add(55);
            testList.Sort();
            testList.Add(57);
            testList.Sort();
            testList.Add(200);
            testList.Sort();
        }

该方法在保持List<T>排序顺序的同时自动把新数据项置于其中;执行该操作时,无需显式调用List<T>.Sort。其原因是,Add方法首先调用BinarySearch方法,并把要添加到List<T>中的对象传递给它。BinarySearch方法将返回在其中找到相同数据项的索引或者返回一个负数,可以用返回值来确定查找的数据项应该位于什么位置。如果BinarySearch方法返回一个正数,就可以使用List<T>.Insert方法在那个位置插入一个新元素,保持List<T>内的排序顺序。如果BinarySearch方法返回一个负数,就可以使用按位求补运算符~来确定数据项应该位于什么位置,假定它存在于一个有序列表中。使用这个数字,可以使用List<T>.Insert方法把数据项添加到有序列表中的正确位置,同时保持正确的排序顺序。

可以在不干扰排序顺序的情况下从有序列表中删除元素,但是在List<T>中修改元素的值则极有可能导致有序列表变得无序。ModifySorted方法缓解了这个问题。该方法的工作方式类似于Add方法,只不过它首先从List<T>中删除元素,然后把新元素插入正确的位置。

参考:

MSDN文档中的"List<T>类”主题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值