其实我使用选择法已经有很多次啦,只是每次使用的时候都要重新看一遍。所以我想在这里总,结一下自己的一点想法。,
选择法升序:
用选择法把具有N个数的一位数组升序排序,排序过程可以分为N-1轮。
第一轮:从1---N个数中找出最小的数与第一个数交换,第一个数排好;
第二轮:从2---N个数中找出最小的数与第二个数交换,第二个数排好;
第三轮:从3---N个数中找出最小的数与第三个数交换,第三个数排好;
。。。。。。
第i轮:从i--N个数中找出最小的数与第i个数交换,第i个数排好;
。。。。。。
第N-1轮:从N-1---N个数中找出最小的数与第N-1个数交换,第N-1个数排好;
外循环是1---N-1;内循环是i+1---N;
内循环中使用一个数记录下第i个数和下标。
问题1:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace _1
{
class Program
{
static void Main(string[] args)
{
//这是选择法排序
const int N = 10;
int[] a = new int[N]{23,45,97,69,92,71,29,72,41,63};
Console.WriteLine("排序前:");
for (int i = 0; i < N; i++)
{
Console.Write("{0} ",a[i]);
}
int min, min_i;
for (int i = 0; i < N - 1; i++) //外循环
{
min = a[i];
min_i = i;
for (int j = i + 1; j < N; j++) //内循环
{
if (a[j] < min)
{
min = a[j];
min_i = j;
}
}
if (min_i != i) { int temp = a[i]; a[i] = min; min= temp; }
}
Console.WriteLine();
Console.WriteLine("排序后:");
for (int i = 0; i < N; i++)
{
Console.Write("{0} ",a[i]);
}
Console.Read();
}
}
}
这样不行,现在分析一下:
现在这样一组数:
23 | 45 | 97 | 69 | 92 | 71 | 29
| 72 | 41 | 63
|
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
如果是上面的代码:
当i=0时,min=a[0]=23,min_i=0;
执行for(int j=i+1;j<N;j++)内的语句后,min=23,min_i=0;a[0]=23;
当i=1时,min=a[1]=45,min_i=1,
执行for(int j=i+1;j<N;j++)内的语句后,min=29,min_i=6;
执行if (min_i != i) { int temp = a[i]; a[i] = min; min= temp; }后,a[1]=29;
当i=2时,min=97,min_i=2,
执行for(int j=i+1;j<N;j++)内的语句后,min=29,min_i=6;
执行if (min_i != i) { int temp = a[i]; a[i] = min; min= temp; }后,a[2]=29;
当i=3时,min=67,min_i=3,
执行for(int j=i+1;j<N;j++)内的语句后,min=29,min_i=6;
执行if (min_i != i) { int temp = a[i]; a[i] = min; min= temp; }后,a[3]=29;
当i=4时,min=92,min_i=4,
执行for(int j=i+1;j<N;j++)内的语句后,min=29,min_i=6;
执行if (min_i != i) { int temp = a[i]; a[i] = min; min= temp; }后,a[4]=29;
当i=5时,min=71,min_i=5,
执行for(int j=i+1;j<N;j++)内的语句后,min=29,min_i=6;
执行if (min_i != i) { int temp = a[i]; a[i] = min; min= temp; }后,a[5]=29;
当i=6时,min=29,min_i=6,
执行for(int j=i+1;j<N;j++)内的语句后,min=29,min_i=6;
执行if (min_i != i) { int temp = a[i]; a[i] = min; min= temp; }后,a[6]=29;
当i=7时,min=72,min_i=7,
执行for(int j=i+1;j<N;j++)内的语句后,min=41,min_i=8;
执行if (min_i != i) { int temp = a[i]; a[i] = min; min= temp; }后,a[7]=41;
当i=8时,min=41,min_i=8,
执行for(int j=i+1;j<N;j++)内的语句后,min=41,min_i=8
执行if (min_i != i) { int temp = a[i]; a[i] = min; min= temp; }后,a[8]=41;
a[9]=63
所以程序结果为:
如果是这样的程序就可以
for (int i = 0; i < N - 1; i++) //外循环
{
min = a[i];
min_i = i;
for (int j = i + 1; j < N; j++) //内循环
{
if (a[j] < min)
{
min = a[j];
min_i = j;
}
}
if (min_i != i) { int temp = a[i]; a[i] =a[min_i]; a[min_i]= temp; }
}
小结:那么这样交换就是对应下标的数组元素的值,主要是在于a[min_i]与a[i]的交换,
问题2:
for (int i = 0; i < N - 1; i++) //外循环
{
min = a[i];
min_i = i;
for (int j= i + 1; j < N; j++) //内循环
{
if (a[j] < min)
{
min = a[j];
min_i = j;
}
if (min_i != i) { int temp = a[i]; a[i] =a[min_i]; a[min_i]= temp; }
}
}
这是把交换放在内循环里面,
当i=0时,min=a[0]=23,min_i=0;
当i=1时,min=a[1]=45,min_i=1,
执行for(int j=i+1;j<N;j++)内的语句后,
① 当j=6时,min=29,min_i=6;
执行if (min_i != i) { int temp = a[i]; a[i] = min; min= temp; }后,a[1]=29;a[6]=45,
② 当j=7时,a[1]=45,a[6]=29;
③ 当j=8时,a[1]=29,a[6]=45;
④ 当j=9时,a[1]=45,a[6]=29;
当i=2时,min=97,min_i=2,
执行for(int j=i+1;j<N;j++)内的语句后,
① 当j=3时,min=69,min_i=3;
执行if (min_i != i) { int temp = a[i]; a[i] = min; min= temp; }后,a[2]=69;a[3]=97,
② 当j=4时,a[2]=97,a[3]=69;
③ 当j=5时,a[2]=69,a[3]=97;
④ 当j=6时,min=29,min_i=6, a[2]=29,a[6]=69;
⑤ 当j=7时,a[2]=69,a[6]=29;
⑥ 当j=8时,a[2]=29,a[6]=69;
⑦ 当j=9时,a[2]=69,a[6]=29;
当i=3时,如此类推,所以程序运行结果为:
小结:这里是把括号放在外面了,所以才有这样的错误。
这里是正确的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace _1
{
class Program
{
static void Main(string[] args)
{
//这是选择法排序
const int N = 10;
int[] a = new int[N]{23,45,97,69,92,71,29,72,41,63};
Console.WriteLine("排序前:");
for (int i = 0; i < N; i++)
{
Console.Write("{0} ",a[i]);
}
int min, min_i;
for (int i = 0; i < N - 1; i++)
{
min = a[i];
min_i = i;
for (int j = i + 1; j < N; j++)
{
if (a[j] < min)
{
min = a[j];
min_i = j;
}
}
if (min_i != i) { int temp = a[i]; a[i] = a[min_i]; a[min_i] = temp; }
}
Console.WriteLine();
Console.WriteLine("排序后:");
for (int i = 0; i < N; i++)
{
Console.Write("{0} ",a[i]);
}
Console.Read();
}
}
}
综上所述:选择法注意事项,一不要把min与a[i]交换,可以用a[min_i]与a[i]进行交换,
二不要把括号放在外面,若这样的话,在找到最小值时,同时min_i也变了,同时在以后就会不断进行交换.