从后向前,比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
冒泡排序是一种比较简单的算法,但是第一次看还是觉得有些繁琐。
它应用了双重嵌套循环,外面的循环是确定本次循环的范围,内部循环是在确定的范围里找到最大的数放到最前。
这里涉及到有序序列和无序序列,简单来说,就是排好顺序的就是有序的,没排好的就是无序的。
从它的工作机理来看就是“交换”,从最后那个数开始,和旁边的数比较大小,谁大谁往前,其实就是交换一下,然后就是倒数第二个和倒数三个比较,最后,这个数组的第一个数就是本数组最大的数,那么,我们的有序序列就有了一个数!就是最大那个数!
这时候,外部循环进行了一次,内部循环整个循环一圈~
然后外部循环的范围就会减1,其实它一直在确定无序序列的范围。然后内循环是找最大。
总之,就这样,循环往复........
举个例子~
如果有10个数,第一次从10个数中(外循环确定)找最大的数放在第一的位置(内循环整体循环一次可得到);
第二次从9个数中(还是外循环确定的范围,第一个数已经是最大的了)找最大的数放在这9个数的第一的位置(内循环再次整体循环)
就这样一直排下去....
设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。
一趟快速排序的算法是:
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]互换;
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
快速排序是对冒泡排序的一种改进。
冒泡排序通常不会使用,但是学习它可以帮助理解快速排序,那么快速排序到底改进了哪些???
在冒泡排序中,我们是和旁边的数比较,然后让大数一步步的从后面换到前面,这样,未免有些笨,因为在日常生活中,如果我们给学生排队的话,肯定是让高个子的直接排到前面,低的排在后面,然后再微调,没人会让最高的那个一次一次的从后面“交换”上来,太慢了。。。
所以,这里引入一个二分法的理念。
简单来说,就是把大的放一块,小的放一块。然后继续划分,这样做的好处就是相比冒泡排序有种一步到位的感觉,因为它一下就把大数和小数分到差不多的位置,而不是笨笨的一点点移上去。
下面是冒泡排序和快速排序的代码(C#版)
static void Main(string[] args)
{
int numberCount;
int[] numbers;
Console.WriteLine("请问您要对多少个数字进行排序?");
numberCount = Convert.ToInt32(Console.ReadLine());
//生成指定数量的随机数
numbers = new int[numberCount];
System.Random rnd = new System.Random();
for (int i = 0; i < numberCount; i++)
{
numbers[i] = rnd.Next(1, numberCount); ;
}
Console.WriteLine();
//冒泡排序
System.Diagnostics.Stopwatch watch1 = new System.Diagnostics.Stopwatch();
watch1.Start();
for (int i = 0; i < numbers.Length - 1; i++)
{
for (int j = 0; j < numbers.Length - 1 - i; j++)
{
if (numbers[j] > numbers[j + 1])
{
int temp = numbers[j];
numbers[j] = numbers[j + 1];
numbers[j + 1] = temp;
}
}
}
watch1.Stop();
Console.WriteLine("冒泡排序 耗费时间为: {0} 毫秒", watch1.ElapsedMilliseconds);
Console.WriteLine();
//快速排序
System.Diagnostics.Stopwatch watch5 = new System.Diagnostics.Stopwatch();
watch5.Start();
sort(numbers, 0, numbers.Length - 1);
watch5.Stop();
Console.WriteLine("快速排序 耗费时间为: {0} 毫秒", watch5.ElapsedMilliseconds);
Console.WriteLine();
Console.ReadKey();
}
private static int sortUnit(int[] array, int low, int high)
{
int key = array[low];
while (low < high)
{
/*从后向前搜索比key小的值*/
while (array[high] >= key && high > low)
--high;
/*比key小的放左边*/
array[low] = array[high];
/*从前向后搜索比key大的值,比key大的放右边*/
while (array[low] <= key && high > low)
++low;
/*比key大的放右边*/
array[high] = array[low];
}
/*左边都比key小,右边都比key大。//将key放在游标当前位置。//此时low等于high */
array[low] = key;
return high;
}
public static void sort(int[] array, int low, int high)
{
if (low >= high)
return;
/*完成一次单元排序*/
int index = sortUnit(array, low, high);
/*对左边单元进行排序*/
sort(array, low, index - 1);
/*对右边单元进行排序*/
sort(array, index + 1, high);
}
}
输入的结果为:
在这里要涉及到空间复杂度和时间复杂度的问题,简单来说就是需要多少内存来处理和需要多少时间来处理。
通常情况下,降低空间复杂度会引起时间复杂度的上升。其实这也很好理解,同样的任务量,人少时间用的就多,人多时间用的就少。当然,这也不是绝对的,如果你的方法上升到更高的维度,说不定你所用的空间和时间都会减少。
对算法的研究还会继续进行下去,他们可以很好帮助我们优化我们的代码。
这些凝结的智慧会对我们有很大启发,站在巨人之上,学习并超越。