我们之前在课本上学习过一般的排序方法,如冒泡,快排,插入,归并。其中时间复杂度有O(N), 和O(Nlogn), 以及O(N2)的。今天我们在这里看一些特定情况下的排序,并否所有的排序都是基于大小的,有时待排序的数大小范围是已知的,我们分别看两个典型的例子:
我们今天先看第一个问题。还是按照之前的六部曲。
题目当中已经把需求给细化了,没有任何一个偶数排在奇数的前面。举个例子 {1,2,3,4,5}会排成 {1,3,5,4,2}。 当然这里还有一个问题需要确认清楚,我们关心它的大小吗?即奇数和偶数部分都需要时升序的吗? 这里可以告诉大家,我们可以忽略这个,这道题目中中只关心奇偶。
拿到这道题,我们首先想到的是如何判断奇偶数。但这其实不是本题的重点。一个很简单的方法出来了,我申明两个数组,一个保存奇数,另一个保存偶数,再把两个数组做一个合并并返回就好了。这个方法是可行的,再挑奇偶时,其实我们只需要扫描数组一遍,不过我们浪费了存储空间,至少我们需要另外申明两个临时的数组。而且,我们还无法事先知道奇数和偶数的数组应该是多长。是不是有更好的办法呢?
我们再看下之前的例子,看能不能找到什么蹊跷的地方? {1,2,3,4,5} 从前往后,其实1是不用动的,2确定要往后挪动,放到哪里呢?具体位置无所谓,但是保证它的后面没有奇数就好了。再从后往前,5是奇数,确定要往前放。到目前为止,如果我们能交换2和5问题就完美的解决了。没错,我们就是要从前往后依次找出偶数, 再从后往前找到奇数,再交换。再找下一个。如果采取这种方法的话,我们扫描数组一遍就可以解决问题了。
从上面的分析看,我们只需要定个两个临时变量就好了。一个从前往后,一个从后往前,终止的条件是他们相遇。 再定义一个临时变量,负责交换就好了。
那我们就直接上代码啦。
public static void Switch(int[] array)
{
if (array != null && array.Length > 1)
{
int begin = 0;
int end = array.Length - 1;
while (begin < end)
{
if (array[begin] % 2 == 0) // 偶数
{
if (array[end] % 2 == 1) //奇数
{
//交换
int temp = array[end];
array[end] = array[begin];
array[begin] = temp;
begin++;
end--;
}
else
{
end--;
}
}
else
{
begin++;
}
}
}
}
在上面的代码中有一个地方可以优化,当我们找到前面待交换的偶数,再确定后面是否有奇数时,我们总是会将后面的指针往前移动。所以end -- 可以移出来,将外面的else也删掉。
static void Main(string[] args)
{
int[] array = new int[] { 1, 2, 3, 4, 5 };
Switch(array);
foreach (var a in array)
{
Console.WriteLine(a);
}
}
大功告成了哈。欢迎大家关注我的公众号,还有我的系列专题课程
大家有什么更好的解法,也欢迎讨论哈。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。