算法是计算机科学的灵魂,多说无益。
一 排序
1 简化版桶排序
1 思想:根据待排序数的取值范围建立数组,然后遍历每个待排序数,没出现一次i,对应相同下标i的数组元素就加1。
2 时间复杂度:O(M+N)。M:桶的个数,M:待排序数的个数。
3 缺点:第一,浪费空间,尤其是取值范围M很大,而待排序数的个数N又很小的时候;另外,对于待排序数为小数的情况,它也处理不了;最后,他只排列了数值,数值所对应的对象却没有考虑到。
4 示例代码:
#include <stdio.h>
int main()
{
int book[1001] = {0};
int i, j, n;
scanf("%d", &n);//输入待排序数的个数
for (i=1; i<=n; i++)
{
scanf("%d", &t);//输入每个待排序数并赋给t
book[t]++
}
for (i=1000; i>=0; i--) //依次判断编号1000~0的桶
for(j=1; j<=book[i]; j++)
printf("%d", i);
system("pause");//暂停程序,查看输出结果
return 0;
}
2 冒泡排序
1 思想:每次比较两个相邻元素,如果他们的顺序错误就把他们交换过来
2 原理:每一趟只确定一个数归位。对于N个待排序数,需要重复N-1趟。
3 时间复杂度:O(N^2)
4 缺点:双重嵌套循环,非常费时,用处不大。
5 示例代码:
#include <stdio.h>
struct student
{
char name[21];
char score;//创建结构体来存储姓名和分数,解决了前面简化版桶排序无法联系对象和数值的缺点。
}
int main ()
{
struct student a[100], t;
int i, j, n;
scanf("%d", &n);//输入待排序数的个数
for (i=1; i<=n; i++)
scanf("%s %d", a[i].name, &a[i].score);
//冒泡排序核心部分
for (i=1; i<=n-1; i++) //n个数排序,共进行n-1趟
{
for (j=1; j<=n-i; j++)//从第1位开始向后比较,要用这个来表示最后一个尚未归位的数,j只能留出一个数的空余,到n-i
if(a[j].score<a[j+1].score)//比较大小并交换
{
t = a[j]; a[j] = a[j+1]; a[j+1] = t;
}
}
for (i=1; i<=n; i++)//输出人名
printf("%s\n", a[j].name);
system("pause");
return 0;
}
3 快速排序
1 思想:二分,每次循环都缩短待排序数的序列长度。
2 原理:把每次选取的基准数归位。
3 最差时间复杂度:O(N^2),平均时间复杂度:O(N*logN)。
4 示例代码:
#include <stdio.h>
int a[101], n;//定义全局变量,这两个变量需要在子函数中使用
void quickshort (int left, int right)
{
int i, j, t, temp;
if(left>right)
return;
temp = a[left];//temp中存的就是基准数
i = left;
j = right;
while(i!=j)
{
//顺序很重要,要先从右往左找
while (a[j]>=temp && i<j)
j--;
while(a[i]<=temp && i<j)
i++;
//交换两个数在数组中的位置
if (i<j)//当哨兵i和哨兵j没有相遇时
{
t = a[i];
a[i] = a[j];
a[j] = t;
}
}
//最终将基准数归位
a[left] = a[i];
a[i] = temp;
quickshort(left, i-1);//继续处理左边的,这里是一个递归的过程
quickshort(i+1, right);//继续整理右边的,这里是一个递归的过程
}
int main()
{
int i, j, t;
//读入数据
scanf("%d", &n);
for (i=1; i<=n; i++)
scanf("%d", &a[i]);
quickshort(1, n);//快速排序调用
return 0;
}
4 小哼买书
1 任务:去重,排序
2 I/O:输入有2项。第一项为1个正整数,表示有n个同学参与调查。第二项是n个正整数,表示参与调查的书的ISBN号。输出也有2项。第一项表示去重之后要买多少本书,第2项是大小排好序的书的ISBN号。
3 思路
第一种:先去重,后排序。第二种:先排序,后去重。
4 步骤
排序:前面已经分析过,根据要处理的数据规模,算出时间复杂度(必要时还可以考虑空间复杂度),选择合理的算法。
去重:在输出前,预先判断当前数a[i]和前面一个数a[i-1]是否相同。如果相同,表示前面已经输出过了,不用再次输出。不同则表示这个数第一次出现,需要输出这个数。 I