C#插入和删除下半部分最有效的数据结构
假设我有一个大的整数排序列表(>1000项)。我需要能够对这个列表执行两个操作:删除下半部分,并通过插入随机整数再次填充列表到其原始大小。因为我做这些操作大约一百万次,所以我需要它尽可能的高效 我做的第一件事就是使用一个C#插入和删除下半部分最有效的数据结构,c#,data-structures,binary-search-tree,avl-tree,C#,Data Structures,Binary Search Tree,Avl Tree,假设我有一个大的整数排序列表(>1000项)。我需要能够对这个列表执行两个操作:删除下半部分,并通过插入随机整数再次填充列表到其原始大小。因为我做这些操作大约一百万次,所以我需要它尽可能的高效 我做的第一件事就是使用一个列表,通过在正确的位置添加新项目来保持排序。虽然删除排序列表的下半部分非常容易,但插入要花费相当多的时间 我尝试实现一个跳过列表,但是在一些测试之后,似乎列表的大小必须至少为10000才能真正起作用,否则它的性能甚至比我的正常列表还要差 这就是为什么我决定使用AVL树,这样我可以
列表
,通过在正确的位置添加新项目来保持排序。虽然删除排序列表的下半部分非常容易,但插入要花费相当多的时间
我尝试实现一个跳过列表,但是在一些测试之后,似乎列表的大小必须至少为10000才能真正起作用,否则它的性能甚至比我的正常列表还要差
这就是为什么我决定使用AVL树,这样我可以更快地插入项目。但问题是,我不知道任何有效的方法来删除这样一个二叉搜索树的下半部分
我的问题是:有没有一种有效的方法来做到这一点?是否有其他更易于使用的数据结构
编辑
我做了一个小测试,显示了列表、跳过列表和AVL树之间的性能差异。我使用msdn上的本教程制作了跳过列表:。AVL树来自此处:。我将测试上传到Pastebin:
在测试中,我在计时时向每个数据结构添加了100000项。在我的电脑上,列表耗时约1秒,跳过列表耗时0.5秒,AVL树耗时0.045秒。如果我想这样做一百万次,列表将需要大约11.5天,但是AVL树只需要大约半天。这个时差清楚地说明了我为什么希望它高效。为什么假设您需要不同的数据结构?说: 我做的第一件事就是使用一个列表,通过在正确的位置添加新项目来保持排序。虽然删除排序列表的下半部分非常容易,但插入要花费相当多的时间 我很担心,因为您可能使用了正确的[1]数据结构,但算法很差。我强烈建议你看一看,并把它包括在你的问题中 但是列表插入很慢O(n)强> 不要插入 正如@usr所解释的,更好的算法可能是:
我想你想一直保持列表的排序。用随机整数替换下半部分的最佳方法如下:
O(n*logn)
。以前它是O(n^2)
您可以通过不删除前半部分的恒定因子对此进行优化。相反,用随机数替换它,然后进行排序。关于这个问题,我想指出一些事情。首先,让我们了解一些关于性能和C#的事情,因为在仍然存在误解的情况下,很难解释这些东西 接下来,我将把我要讨论的所有问题都应用到这里的具体问题上 一般来说,C#中的性能 大O符号
Testing performance of filling a list to 10000 items 1000 times, discarding 1/2
of items after every fill!
Old list: 3248ms
New list: 547ms
DONE
void set(int[] array, int index)
{
array[index] = 0;
}
if (index < 0 || index >= array.Length)
{
throw new IndexOutOfRangeException();
}
static void Main(string[] args)
{
Random rnd = new Random(12839);
SortedSet<int> list = new SortedSet<int>();
for (int i = 0; i < 5000; ++i)
{
list.Add(rnd.Next());
}
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 10000; ++i)
{
for (int j = 0; j < 5000; ++j)
{
list.Add(rnd.Next());
}
int n = 0;
list.RemoveWhere((a) => n++ < 5000);
}
Console.WriteLine(sw.ElapsedMilliseconds);
Console.ReadLine();
}
static void Main(string[] args)
{
Random rnd = new Random(12839);
List<int> list = new List<int>();
for (int i = 0; i < 5000; ++i)
{
list.Add(rnd.Next());
}
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 10000; ++i)
{
for (int j = 0; j < 5000; ++j)
{
list.Add(rnd.Next());
}
list.Sort((a, b) => a.CompareTo(b)); // #1
list.RemoveRange(0, 5000);
}
Console.WriteLine(sw.ElapsedMilliseconds);
Console.ReadLine();
}
list.Sort((a, b) => a - b);
list.Sort((a, b) => (int)((float)a - (float)b));
static void Main(string[] args)
{
Random rnd = new Random(12839);
int[] list = new int[10000];
for (int i = 0; i < 5000; ++i)
{
list[i] = rnd.Next();
}
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 10000; ++i)
{
for (int j = 0; j < 5000; ++j)
{
list[j + 5000] = rnd.Next();
}
Array.Sort(list, (a, b) => b - a);
}
Console.WriteLine(sw.ElapsedMilliseconds);
Console.ReadLine();
}
list.Sort();
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 10000; ++i)
{
for (int j = 0; j < 5000; ++j)
{
list.Add(rnd.Next());
}
// Sort the second half:
list.Sort(5000, 5000, Comparer<int>.Default);
// Both the lower and upper half are sorted. Merge-join:
int lhs = 0;
int rhs = 5000;
while (list.Count < 15000)
{
int l = list[lhs];
int r = list[rhs];
if (l < r)
{
list.Add(l);
++lhs;
}
else if (l > r)
{
list.Add(r);
++rhs;
}
else
{
while (list.Count < 15000 && list[lhs] == l)
{
list.Add(l);
++lhs;
}
while (list.Count < 15000 && list[rhs] == r)
{
list.Add(r);
++rhs;
}
}
}
list.RemoveRange(0, 10000);
}
list.Clear();
var tmp = list;
list = list2;
list2 = tmp;
public static List<int> orig()
{
Random rnd = new Random(12839);
List<int> list = new List<int>(10000);
for (int i = 0; i < 5000; ++i)
{
list.Add(rnd.Next());
}
for (int i = 0; i < 10000; ++i)
{
for (int j = 0; j < 5000; ++j)
{
list.Add(rnd.Next());
}
// Sort the second half:
list.Sort(5000, 5000, Comparer<int>.Default);
// Both the lower and upper half are sorted. Merge-join:
int lhs = 0;
int rhs = 5000;
while (list.Count < 15000)
{
int l = list[lhs];
int r = list[rhs];
if (l < r)
{
list.Add(l);
++lhs;
}
else if (l > r)
{
list.Add(r);
++rhs;
}
else
{
while (list.Count < 15000 && list[lhs] == l)
{
list.Add(l);
++lhs;
}
while (list.Count < 15000 && list[rhs] == r)
{
list.Add(r);
++rhs;
}
}
}
list.RemoveRange(0, 10000);
}
return list;
}
public static int[] altered()
{
Random rnd = new Random(12839);
int HALFSIZE = 5000;
int SIZE = 2 * HALFSIZE;
int TESTLOOPS = 10000;
int[] list = new int[SIZE];
int[] list2 = new int[SIZE];
for (int i = 0; i < HALFSIZE; ++i)
{
list[i] = rnd.Next();
}
for (int i = 0; i < TESTLOOPS; ++i)
{
for (int j = HALFSIZE; j < list.Length; ++j)
{
list[j] = rnd.Next();
}
// Sort the second half:
Array.Sort(list, HALFSIZE, HALFSIZE, Comparer<int>.Default);
// Both the lower and upper half are sorted. Merge-join:
int lhs = 0;
int rhs = HALFSIZE;
int i2 = 0;
while (i2 < HALFSIZE)
{
int l = list[lhs];
int r = list[rhs];
if (l <= r)
{
list2[i2++] = l;
++lhs;
}
if (l >= r)
{
list2[i2++] = r;
++rhs;
}
}
var tmp = list;
list = list2;
list2 = tmp;
}
return list;
}
public static int[] altered2()
{
Random rnd = new Random(12839);
int HALFSIZE = 5000;
int SIZE = 2 * HALFSIZE;
int TESTLOOPS = 10000;
int[] list = new int[SIZE];
int[] list2 = new int[SIZE];
for (int i = 0; i < HALFSIZE; ++i)
{
list[i] = rnd.Next();
}
for (int i = 0; i < TESTLOOPS; ++i)
{
for (int j = HALFSIZE; j < list.Length; ++j)
{
list[j] = rnd.Next();
}
// quicksort one level to skip values >= maxValue
int maxValue = list[HALFSIZE - 1];
int ll = HALFSIZE;
int rr = SIZE - 1;
do
{
while (ll <= rr && list[ll] < maxValue) { ++ll; }
while (ll < rr && list[rr] >= maxValue) { --rr; }
if (ll < rr)
{
int swap = list[ll];
list[ll] = list[rr];
list[rr] = swap;
++ll;
--rr;
}
}
while (ll < rr);
// Sort the second half:
Array.Sort(list, HALFSIZE, ll - HALFSIZE, Comparer<int>.Default);
// Both the lower and upper half are sorted. Merge-join:
int lhs = 0;
int rhs = HALFSIZE;
int i2 = 0;
while (i2 < HALFSIZE)
{
int l = list[lhs];
int r = list[rhs];
if (l <= r)
{
list2[i2++] = l;
++lhs;
}
if (l >= r)
{
list2[i2++] = r;
++rhs;
}
}
var tmp = list;
list = list2;
list2 = tmp;
}
return list;
}
public static int[] random()
{
Random rnd = new Random(12839);
int HALFSIZE = 5000;
int SIZE = 2 * HALFSIZE;
int TESTLOOPS = 10000;
int[] list = new int[SIZE];
for (int i = 0; i < HALFSIZE; ++i)
{
list[i] = rnd.Next();
}
for (int i = 0; i < TESTLOOPS; ++i)
{
for (int j = HALFSIZE; j < list.Length; ++j)
{
list[j] = rnd.Next();
}
}
return list;
}
static void Main(string[] args)
{
int HALFSIZE = 5000;
var origTest = orig();
Stopwatch sw = Stopwatch.StartNew();
orig();
sw.Stop();
Console.WriteLine("Orig time: " + sw.ElapsedMilliseconds);
var alteredTest = altered();
sw = Stopwatch.StartNew();
altered();
sw.Stop();
Console.WriteLine("Altered time: " + sw.ElapsedMilliseconds);
Console.WriteLine("Test: " + (origTest.Take(HALFSIZE).SequenceEqual(alteredTest.Take(HALFSIZE)) ? "OK" : "BAD"));
var altered2Test = altered2();
sw = Stopwatch.StartNew();
altered2();
sw.Stop();
Console.WriteLine("Altered2 time: " + sw.ElapsedMilliseconds);
Console.WriteLine("Test: " + (origTest.Take(HALFSIZE).SequenceEqual(altered2Test.Take(HALFSIZE)) ? "OK" : "BAD"));
sw = Stopwatch.StartNew();
random();
sw.Stop();
Console.WriteLine("Just random time: " + sw.ElapsedMilliseconds);
Console.ReadKey();
}