排序是通过元素位置的调整使得数组的所有元素按特定顺序存放,如数组中的元素按非递增或非递减的顺序排列。排序算法是数组中的常用经典算法。
目录
1. 第一种方法是最容易理解的,写得最详细的,但是它的局限性就在于每次比较都要遍历整个数组,一共要遍历n-1趟,这样会使得整个代码的效率变得极低。
排序可以用很多种方法实现,我们先来介绍其中的一种——冒泡排序。
冒泡排序的算法思想是:
在排序过程中对元素进行两两比较,越小的元素会经由交换慢慢“浮”到数组的前面(低下标处),像气泡一样慢慢浮起,由此得名。假设对长度为n的数组进行冒泡排序,算法可以描述如下:
①第1趟冒泡:从数组n-1下标的元素到0下标元素遍历,比较相邻元素对,如果后一个元素小于前一个元素,则交换。第一趟结束时,最小元素“浮起”到达0下标位置。
②第2趟冒泡:从数组n-1下标的元素到1下标元素遍历(因为0下标的已是最小元素,已经到位,无需再参加比较),比较相邻元素对,如果后一个元素小于前一个元素,则交换。第二趟结束时,本趟最小元素到达1下标位置。
依此类推,最多n-1趟冒泡(n是元素个数),便可以完成排序。
【例】从键盘上输入n(1≤n<10)个整数,用冒泡法将元素按从小到大的顺序排房,然后输出排序后元素。
1.
第一种方法是最容易理解的,写得最详细的,但是它的局限性就在于每次比较都要遍历整个数组,一共要遍历n-1趟,这样会使得整个代码的效率变得极低。
#include <stdio.h>
#define SIZE 10
/*函数功能: 完成一维数组的输出
函数参数:表示待输出的数组、实际输出的元素个数
函数返回值:无返回值*/
void print(int a[], int n)
{
int i;
printf("The array is:\n");
for (i = 0; i < n; i++)
printf("%5d", a[i]);
printf("\n");
}
/*函数功能: 完成一维数组的冒泡排序算法
函数参数:两个参数分别是待排序数组及当前元素个数
函数返回值:无返回值*/
void BubbleSort(int a[], int n)
{
int i, j, temp;
for (i = 0; i < n - 1; i++) /*共进行n-1趟排序*/
for (j = n - 1; j > i; j--) /*递减循环,从后往前比较*/
if (a[j] < a[j - 1]) /*两两比较,若后一个元素小则交换该组相邻元素*/
{
temp = a[j - 1];
a[j - 1] = a[j];
a[j] = temp;
}
}
int main()
{
int array[SIZE], i = 0, n;
do
{
printf("Please input n(1<=n<=%d):", SIZE);
scanf("%d", &n);
} while (n<1 || n>SIZE); /*保证读入的n满足1≤n≤SIZE*/
printf("Please input %d elements:", n);
for (i = 0; i < n; i++)
scanf("%d", &array[i]); /*读入数组元素*/
BubbleSort(array, n); /*调用函数完成排序*/
print(array, n);
return 0;
}
2.
冒泡排序算法中,对每一趟排序无论数据是否有序都会进行比较,算法效率,试着改进算法以减少排序趟数,并输出算法中排序的总趟数。
【分析与解答】 冒泡排序中,无论数列是否有序,都会一直比较直到最后两个元素。可以设置一个标志, 如果这一趟发生了交换,将 flag 赋值为1,否则将flag赋值为0。因为如果有一趟没有发生交换,说明排序已经完成。
冒泡排序函数修改如下:
void BubbleSort(int a[], int n)
{
int j, k;
int flag = 1;
int temp;
k = n;
while (flag)
{
flag = 0;
for (j = 1; j < k; j++)
if (a[j - 1] > a[j])
{
temp = a[j - 1];
a[j - 1] = a[j];
a[j] = temp;
flag = 1;
}
k--;
}
}
3.
程序还可以做进一步的优化。
如果有100个数的数组,仅前面 10个无序,后面 90 个都已排好序且都大于前面10个数字,那么在第1趟遍历后最后发生交换的位置必定小于10,且这个位置之后的数据必定已经有序了,用 flag 变量记录下这位置,第2次只要从数组头部遍历到这个位置就可以了。
排序函数可以进一步修改如下:
void BubbleSort(int a[], int n)
{
int j, k;
int flag,temp;
flag = n;
while (flag > 0)
{
k = flag;
flag = 0;
for (j = 1; j < k; j++)
if (a[j - 1] > a[j])
{
temp = a[j - 1];
a[j - 1] = a[j];
a[j] = temp;
flag = j; /*全部过一遍.用flag记住了*/
}
}
}
二、选择法排序
排序是一维数组中最经典的常见操作,排序方法有很多种。
我们刚刚介绍了冒泡排序的实现,现在来介绍一下简单选择排序。
通过介绍该排序方法我们还可以顺便复习一下指针形参与数组实参的用法
【例】从键盘输人n(1<=n<=10)个整数,定排序函数(按升序排列)以及输出函数。
分析:
选择法排序的算法思想如下:
1、有n个元素的数组一共需要进行 n-1趟排序,为了方便地与数组下标一致,控制趟数的外层循环控制变量的值从0变化到n-2
2、每一趟的任务是找出本趟参加比较元素中最小元素所在的位置。第 i 趟进行时,默认最小元素位置为 i 。然后通过一个内层循环,从 i +1下标一直扫描到 n-1下标,逐个比较得到最小元素的下标值。
3、每趟结束时判断本趟得到的最小元素下标是否在 i 下标处,如果不在,则将这两个位置的元素做交换,保证本趟的最小元素到位。
例如: 将98,34,-4573这几个数用选择法排序,即n=4,排序过程如表 7.4所示,其中k控制排序的趟序号,index存储本趟最小元素的下标。
k | index | a[0] | a[1] | a[2] | a[3] | 说明 |
---|---|---|---|---|---|---|
98 | 34 | -45 | 72 | 输人的数组元素初值 | ||
0 | 2 | -45 | 34 | 98 | 72 | 第0趟在a[0]~a[3]中找到最小元素下标为2将a[2]与a[0]交换 |
1 | 1 | -45 | 34 | 98 | 72 | 第1趟在a[1]~a[3]中找到最小元素下标为1dex 等于k不交换 |
2 | 3 | -45 | 34 | 72 | 98 | 第2趟在a[2]~a[3]中找到最小元素下标为3,将a[3]与a[2]交换 |
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
/*函数功能:输入数组元素
函数参数:第1个形式参参数是指向数组的指针,
第2个是数维组元素个数
函数返回值:无返回值*/
void Input(int* pa, int n)
{
int i;
printf("Please input %d elements:\n", n);
for (i = 0; i < n; i++) /*用for语句控制输人n个元素*/
scanf("%d", pa + i);/*可以用&pa[i]代替pa+I*/
}
/*函数功能: 对n个数组元素排序
函数参数: 第1个形式参数是指向数组的指针,
第2个是数组元素个数
函数返回值:无返回值*/
void sort(int* pa, int n)
{
int index, i, k, temp;
for (k = 0; k < n - 1; k++) /*k控制排序的趟数,以0到n-2 表示所有趟*/
{
index = k;/*本趟最小位置存于index,开始时为k*/
for (i = k + 1; i < n; i++) /*通过内层循环找出本趟真正的最小元素*/
if (pa[i] < pa[index]) /*将本趟最小元素的下标赋给index*/
index = i;
if (index != k) /*如果本趟最小元素没有到位*/
{
temp = pa[index];/*则通过交换使本趟最小元素到k下标处*/
pa[index] = pa[k];
pa[k] = temp;
}
}
}
/*函数功能:输出排序后的数组元素
函数参数:第1个形式参数是指向数组的指针,
第2个是数组元素个数
函数返回值:无返回值*/
void Output(const int* pa, int n)/*输出数组元素*/
{
int i;
for (i = 0; i < n; i++) /*用for语句控制输出n个初始元素*/
printf("%5d", *(pa + i)); /*可以用pa[i]代替*[pa+i]*/
printf("\n");
}
int main()
{
int a[10], n; /*定义数组,n控制元素个数*/
do /*保证读人的n满足1≤n≤10*/
{
printf("Please input n(1<=n<=10):\n");
scanf("%d", &n);
} while (n < 1 || n>10);
Input(a, n); /*调用函数,完成输入*/
printf("The original array is:\n");
Output(a, n);/*调用函数,输出原始数组*/
sort(a, n); /*调用函数,完成排序*/
printf("The sorted array is:\n");
Output(a, n);/*调用函数,输出排序后的数组*/
return 0;
}
注意,Output函数中的第1个参数前用const限定,这是因为本函数不能通过指针形参修改数组元素的值,加了const可以从语法上保证参数组内容不被修改。