【发布时间】:2018-01-28 20:38:30
【问题描述】:
我有一个 2D 数组,它有 4 列和 1921980 行 string array = new string[1921980, 4]。该数组应按第四列中的值排序。所以我从冒泡排序开始,它非常慢,甚至是并行的。它还会产生高 CPU 利用率。我切换到快速排序(递归),事情变得更快。问题是我在排序时调用了 2 个方法:
-
Console.Write显示进度 -
StringToInt32自定义方法,比Convert.ToInt32或Int32.Parse快
但这会在一段时间后产生 StackOverFlowException。所以我决定使用快速排序(迭代)。感觉就像冒泡排序。我猜我的代码有问题。
static int StringToInt32(string s)
{
int tmp = 0;
switch (s[0])
{
case '-':
for (int counter = 1; counter < s.Length; counter++)
{
tmp = tmp * 10 + (s[counter] - '0');
}
tmp *= -1;
return tmp;
break;
default:
for (int counter = 0; counter < s.Length; counter++)
{
tmp = tmp * 10 + (s[counter] - '0');
}
return tmp;
break;
}
}
static void QuickSort(ref string[,] array, int length)
{
Stack<int> stack = new Stack<int>();
stack.Push(length - 1);
stack.Push(0);
int percent = -1;
int look = 0;
while (stack.Count != 0)
{
/**
* Pop array or sub array start and end index
*/
int left = stack.Pop();
int right = stack.Pop();
int newPivotIndex = Partition(ref array, left, right);
/**
* divide right i.e. second sub array from newPivotIndex+1 to right
* here newPivotIndex+1 is index where right elements are greater or = than pivot
* use stack for storing array index and in while loop pop that right sub array indexes.
*/
if ((newPivotIndex + 1) < right)
{
stack.Push(right);
stack.Push(newPivotIndex + 1);
}
/**
* divide sub array from left to mid or newPivotIndex-1
* here newPivotIndex-1 is index where left elements are lesser or = than pivot
* use stack for storing array index and in while loop pop that left sub array indexes.
*/
if ((newPivotIndex - 1) > left)
{
stack.Push(newPivotIndex - 1);
stack.Push(left);
}
look++;
if (look * 100 / length != percent)
{
percent = look * 100 / length;
Console.Write("\r{0}%", percent);
}
}
Console.Write("\r100%");
}
static int GetMedianPivot(ref string[,] array, int left, int right)
{
int mid = ((left + right) / 2);
/** middle number of array is less than left number of array
* then Swap middle and left number
*/
if (StringToInt32(array[mid, 3]) < StringToInt32(array[left, 3]))
{
Swap(ref array, left, mid);
}
/** rightmost number of array is less than left number of array
* then Swap right and left number
*/
if (StringToInt32(array[right, 3]) < StringToInt32(array[left, 3]))
{
Swap(ref array, left, right);
}
/**
* now right number is less than mid then Swap number which
* shifts median of three numbers into mid position
*/
if (StringToInt32(array[right, 3]) < StringToInt32(array[mid, 3]))
{
Swap(ref array, mid, right);
}
/**
* Shift Median or pivot from mid to rightmost position
* i.e. out of partitioning index
*/
Swap(ref array, mid, right);
/**return pivot number value which is right most now.**/
return StringToInt32(array[right, 3]);
}
static int Partition(ref string[,] array, int left, int right)
{
int pivot = StringToInt32(array[right, 3]); ;
/**
* Initialize low = left i.e. start index of array or logical sub-array
* Initialize high = right-1 i.e. end index of array or logical sub array;
* becuase right is pivot element so start from right-1;
*/
int low = left;
int high = right - 1;
do
{
while (StringToInt32(array[low, 3]) < pivot && low < right - 1)
{
low++;
}
while (StringToInt32(array[high, 3]) >= pivot && high > left)
{
high--;
}
/**
* Swap elements when any left element is greater than pivot or
* any right element is less than pivot.
*/
if (low < high)
{
Swap(ref array, low, high);
low++;
high--;
}
} while (low < high);
/**
* Swap right most pivot to its right position i.e. at low, then
* left elements are lesser and right elements are greater than pivot.
*/
if (StringToInt32(array[low, 3]) > pivot)
{
Swap(ref array, low, right);
}
return low;
}
static void Swap(ref string[,] array, int i, int j)
{
string[] buffer = new string[4];
buffer[0] = array[i, 0];
buffer[1] = array[i, 1];
buffer[2] = array[i, 2];
buffer[3] = array[i, 3];
array[i, 0] = array[j, 0];
array[i, 1] = array[j, 1];
array[i, 2] = array[j, 2];
array[i, 3] = array[j, 3];
array[j, 0] = buffer[0];
array[j, 1] = buffer[1];
array[j, 2] = buffer[2];
array[j, 3] = buffer[3];
}
【问题讨论】:
-
每次交换创建新数组,在每次比较中将字符串转换为 int 等等......当然它会很慢。如果自定义 int 转换真的比框架中提供的更快,我会感到非常惊讶,但我猜这是可能的。
-
为什么不先将所有字符串转换为整数然后对其进行排序,而不是转换每个迭代/交换/枢轴/等?
int[,]会不会更合适?如果必须,请先转换为该格式,对其进行排序,然后使用 ToString 复制回字符串数组。每次你可以提前做一次时,你都会做很多额外的工作 -
这里没有问题。你写了一个非常糟糕的快速排序实现,它非常慢,而且......这是一个故事而不是一个问题。你有什么具体的、可以回答的问题?