在c#中实现快速排序有困难
本文关键字:快速排序 实现 | 更新日期: 2023-09-27 18:04:00
我有一点麻烦,试图让这个快速排序算法工作100%。到目前为止,当它试图交换两个相同的数字时,它会有点挂起(试图补救,正如您将在代码中看到的那样)。
那该死的东西就快到了。我只是不确定我错过了什么。我花了几个小时想弄明白,但无济于事。
我正在为课堂做这个,不幸的是我的老师说他不能帮助我,因为我在做泛型(额外的学分),他只能在c#中拉动字符串或整数(他主要是java/c++老师....他使用c#的时间并不长)。
快速排序静态类
class QuickSort<T> where T : IComparable<T>
{
//No variables or properties, more of a helper class
//This is the method that will be called by the user.
//It ties the internal methods into one to sort the
//array. It needs an array passed into it, As well as
//the size of the array.
public static void QSort(T[] array,int size)
{
//If array is empty, or has 1 element, it is sorted.
//Return immediatly.
if (size == 1 || size == 0)
{ return; }
else
{
//Time to sort, pass in the array, the left bounds of 0,
//and the right bounds of high - 1 (the last element).
Partition(array, 0, size);
}
}
//This method splits the work area in half, putting lower
//values left of the pivot, and greater values right of
//the pivot.
private static void Partition(T[] array, int lower, int upper)
{
//If upper is less 1, then there is no
//sorting that can be done.
if ((upper - lower) < 2)
{ return; }
//Get the right bound -1, to make sure it stays
//within actual array bounds
int left = lower;
int right = upper-1;
//Set pivot to equal the middle most array. I used this
//expression because wikipedia mentions it will stop
//overflow and invalid pivot position that can come
//with exceptionally large arrays using the basic
//(a+b)/2 equation.
int pivot_index = left + (right - left) / 2;
T pivot = array[pivot_index];
while (left < right)
{
//array[left] < pivot
while ((array[left].CompareTo(pivot) <= 0) && (left < right))
{
left++;
}
//array[right] > pivot
while ((array[right].CompareTo(pivot) >= 0)&& (left < right))
{
right--;
}
if (left != right)
{
Swap(array, left, right);
left++;
right--;
}
}
//Send in the lower bound, and the pivot point.
Partition(array, lower, right);
//Send in the pivot point as lower bound, and upper
Partition(array, right+1, upper);
}
//This method simply swaps the first position with the second.
private static void Swap(T[] array, int position1, int position2)
{
T tempHolder = array[position1];
array[position1] = array[position2];
array[position2] = tempHolder;
}
}
主类
class Tester
{
static void Main(string[] args)
{
ContiguousList<int> tester = new ContiguousList<int>(100);
Random rand = new Random(5433);
for (int ii = 0; ii < tester.Size; ii++)
{
tester.SetElement(ii, rand.Next(0, 100));
}
for (int ii = 0; ii < tester.Size; ii++)
{
Console.WriteLine(tester.GetElement(ii).ToString());
}
Console.WriteLine();
tester.Sort();
for (int ii = 0; ii < tester.Size; ii++)
{
Console.WriteLine(tester.GetElement(ii).ToString());
}
}
}
这对我来说相当困难,因为我能遵循的唯一在线实现要么是c++(找到一个很好的伪代码解释,如果我能使用指针>.<),要么是它们仅用于整数排序。
我想也许交换是缺失的,或者我的逻辑处理如果数组[左]==数组[右]是错误的。
(哦,不要介意main中的continuouslist…我们的老师让我们编写了自己的智能数组,并告诉我们使用它,这样我们就可以看到智能数组是如何工作的。
谢谢大家的帮助。我的脑子被这个问题难住了。
——编辑我改变了循环,一个检查>= 0,另一个检查<0去掉不需要的支票
——编辑我又调整了一下,现在它似乎仍然是有序的,但不是完全有序,我的前10个元素是1,1,2,3,2,3,6,5,4,5所以不知怎的,当值相同时,有些东西没有被交换。
编辑—只是重读了一下我使用的快速排序解释/伪代码,并注意到一个小的"这个版本将只适用于具有唯一元素的数组"警告…所以我是对的,因为当2个元素持有相同的值时,它必须这样做,有些东西不起作用……
由于第一个循环,左元素不能小于枢轴。右边的元素不能大于主元,因为有第二个循环。所以如果它们相等,那么它们一定都等于主轴,因此它们最终在数组的哪一半都无关紧要。
无论如何,我认为你需要做的就是稍微调整一下这些行:
if (array[left].CompareTo(array[right]) == 0)
{
left++;
right--;
}
else if (left != right)
{
Swap(array, left, right);
left++;
right--;
}
但是这里有几个简化:
- 因为
left == right
意味着array[left].CompareTo(array[right]) == 0)
,你的left != right
测试是多余的。 - 作为推论,你总是以左递增和右递减结束。所以你可以把它移到条件语句之外。
if (array[left].CompareTo(array[right]) != 0)
{
Swap(array, left, right);
}
left++;
right--;
您应该更改swap方法以交换实际数据,而不是访问数组。在c#中,你需要'ref',所以任何数据都会作为引用发送:
private static void Swap(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}