特殊排序之红白球

特殊排序之红白球

今天去面试,做了一道上机题,感觉有点意思,记录一下。
设有红色、白色两种球若干,放在一个数组里,请实现算法:把红球排到白球前面。

先设置好要操作的类:

红白球Ball
 1     enum EBallColor
 2     {
 3         Red,
 4         White,
 5     }
 6     class Ball : IComparable<Ball>
 7     {
 8         public EBallColor BallColor { get; set; }
 9         public Ball(EBallColor color)
10         {
11             this.BallColor = color;
12         }
13         public override string ToString()
14         {
15             return string.Format("{0}", BallColor);
16             //return base.ToString();
17         }
18 
19         /// <summary>
20         /// Red &gt; White
21         /// </summary>
22         /// <param name="other"></param>
23         /// <returns></returns>
24         public int CompareTo(Ball other)
25         {
26             if (other == null)
27             {
28                 return -1;
29             }
30 
31             if (this.BallColor == other.BallColor)
32             {
33                 return 0;
34             }
35 
36             if (this.BallColor == EBallColor.Red)
37             {
38                 return 1;
39             }
40 
41             return -1;
42         }
43     }

当然用排序的方式是可以的:

插入排序实现
 1         private static void BallArrange(Ball[] ballList)
 2         {
 3             if (ballList == null || ballList.Length < 2)
 4             {
 5                 return;
 6             }
 7 
 8             for (int i = 0; i < ballList.Length; i++)
 9             {
10                 int p = i;
11 
12                 for (int j = i + 1; j < ballList.Length; j++)
13                 {
14                     if (ballList[p].CompareTo(ballList[j]) < 0)
15                     {
16                         p = j;
17                     }
18                 }
19 
20                 if (p != i)
21                 {
22                     var tmp = ballList[p];
23                     ballList[p] = ballList[i];
24                     ballList[i] = tmp;
25                 }
26             }
27         }

写的时候就想到排序是很浪费的,各个球没有大小,只有两个值,然后就想到直接把白球放到最后就可以了。于是又写了一种算法。(名字很猥琐)

抽插实现
 1         static void BallArrange2(IList<Ball> ballList)
 2         {
 3             if (ballList == null || ballList.Count < 2)
 4             {
 5                 return;
 6             }
 7 
 8             int arranged = 0, index = 0;
 9 
10             while (index < ballList.Count - arranged)
11             {
12                 var ball = ballList[index];
13                 if (ball.BallColor == EBallColor.White)
14                 {
15                     ballList.Remove(ball);
16                     ballList.Add(ball);
17                     arranged--;
18                 }
19                 else
20                 {
21                     index++;
22                 }
23             }
24         }

要是就这么简单,我觉得面试官不会拿来考我。所以应该有优化的算法。在人家明确提出用一次循环搞定问题之后。我想出了下面的算法。

左右交换实现
 1          static void BallArrange3(Ball[] ballList)
 2          {
 3              if (ballList == null || ballList.Length < 2)
 4              {
 5                  return;
 6              }
 7  
 8              int left = 0, right = ballList.Length - 1;
 9  
10              while (left < right)
11              {
12                  if (ballList[left].BallColor == EBallColor.Red)
13                  {
14                      if (ballList[right].BallColor == EBallColor.Red)
15                      {
16                          left++;
17                      }
18                      else
19                      {
20                          left++;
21                          right--;
22                      }
23                  }
24                  else
25                  {
26                      if (ballList[right].BallColor == EBallColor.White)
27                      {
28                          right--;
29                      }
30                      else
31                      {
32                          var tmp = ballList[left];
33                          ballList[left] = ballList[right];
34                          ballList[right] = tmp;
35                          left++;
36                          right--;
37                      }
38                  }
39              }
40          }

写出来就觉得是对了,果然面试官说想要的就是这种“交换”的思路。
这个算法的思路是:从左开始,发现是红球的,说明符合条件,抛弃之不再管(left++);从右开始,发现是白球的,符合条件,抛弃之不再管(right--),只有左白右红时,交换,然后抛弃之不再管。直到left >= right时,左右都符合条件,结束。

最后面试官又问了一下Main函数里的测试代码的问题,说能不能只写一个BallArrange函数就实现多种排序算法的测试?我听明白了他想问什么,但是脑子一时堵塞,没有想起那个名词来,于是pardon了一下,然后就明白了,说可以对每个算法分别设置一个类,使其继承一个基类,BallArrange方法继承自基类的虚方法。后来回想起来,这个好像是策略模式吧。然后面试官就说没问题了,想问的就是这个了。

测试用例
 1         static void Main(string[] args)
 2         {
 3             Ball[] ballList = new Ball[]
 4             {
 5                 new Ball(EBallColor.Red),
 6                 new Ball(EBallColor.White),
 7                 new Ball(EBallColor.White),
 8                 new Ball(EBallColor.Red),
 9                 new Ball(EBallColor.Red),
10             };
11 
12             Console.WriteLine("Before arrange: ");
13             foreach (var item in ballList)
14             {
15                 Console.WriteLine(item);
16             }
17 
18             //BallArrange(ballList);
19             //BallArrange2(ballList);
20             BallArrange3(ballList);
21 
22             Console.WriteLine("After arrange: ");
23             foreach (var item in ballList)
24             {
25                 Console.WriteLine(item);
26             }
27         }
原文地址:https://www.cnblogs.com/bitzhuwei/p/Red_White_Ball_Arrangement.html