《啊哈!算法》第一章读书笔记

第一章(一大波数正在靠近——排序)

第 1 节 最快最简单的排序——桶排序

  1. 问题描述 :将同学们的分数从高到底进行排序,总共有5个同学,分别考了5 分、 3 分、5 分、 2 分和 8 分(满分是 10 分)。
  2. 提出问题: 有没有什么好方法编写一段程序,让计算机随机读入 5 个数然后将这 5 个数从大到小输出?
  3. 解决问题 :先申请一个大小为 11 的数组 int a[11],编号从a[0]-a[10],并初始化为0,接下来处理每个人的分数,如果5分出现一次则把a[5]的值在原来的基础上增加1。这种排序方法暂且叫它“桶排序”,真正的桶排序要比这个复杂一些。
  4. 编码思路:循环初始化数组,再把每一个数读到变量t中,通过a[t]++;进行计数,最后依次判断a[0]-a[10],出现了几次就打印几次。时间复杂度为桶的个数和待排序数的个数之和。

第 2 节 邻居好说话——冒泡排序

  1. 问题描述 :简化版的桶排序不仅仅有上一节所遗留的问题, 更要命的是:它非常浪费空间!还有,
    如果现在需要排序的不再是整数而是一些小数,比如将 5.56789、 2.12、 1.1、 3.123、 4.1234
    这五个数进行从小到大排序又该怎么办呢?
  2. 编码思路:循环读入n个数到数组a中,再对n个数进行排序,只用进行n-1趟,从第1位开始比较直到最后一个尚未归位的数,比较大小并交换,最后输出排好序的数组。实际问题分析时,可以创建一个结构体来存储学生的姓名和分数。

第 3 节 最常用的排序——快速排序

  1. 问题描述 :冒泡排序解决了桶排序浪费
    空间的问题,但在算法的执行效率上却牺牲了很多,它的时间复杂度达到了 O(N2)。有没有既不浪费空间又可以快一点的排序算法呢?对“ 6 1 2 7 9 3 4 5 10 8”这 10 个数进行排序。
  2. 解决问题 :首先在这个序列中选择一个基准数,作者把第一个数6作为基准数,先从右往左找一个小于 6 的数,再从左往右找一个大于 6 的数,然后交换它们。这里用两个变量 i 和 j,分别指向序列最左边和最右边。作者形象化了两个哨兵,左边的哨兵先出动,找到小于基准数的数之后停下,然后右边的哨兵找到大于基准数的数之后停下,两两交换,直到两个哨兵碰头为止,接下来重复刚才的动作做多次探测。
  3. 编码思路:用一个变量存储那个基准数,再用两个变量存储那两个哨兵,进入循环后,先从右往左找,当a[j]大于等于基准数temp并且i<j(两个哨兵不碰头)时,j–,再从左往右找,当a[i]小于等于基准数temp并且i<j(两个哨兵不碰头)时,i++。函数里最后一步是将基准数归位(两个哨兵碰头),接下来继续处理左边的,这是一个递归调用函数的过程,再继续处理右边的,处理完后,最后合并成排好序的数组。

附代码

//第1节 简化版的“桶排序”
#include <stdio.h>
int main()
{
	int a[11],i,j,t;
	for(i=0;i<=10;i++)
	a[i]=0; //初始化为0
	for(i=1;i<=5;i++) //循环读入5个数
	{
		scanf("%d",&t); //把每一个数读到变量t中
		a[t]++; //进行计数
	}
	for(i=0;i<=10;i++) //依次判断a[0]~a[10]
		for(j=1;j<=a[i];j++) //出现了几次就打印几次
			printf("%d ",i);
	getchar();getchar();
	//这里的getchar();用来暂停程序,以便查看程序输出的内容
	//也可以用system("pause");等来代替
	return 0;
}
//第2节冒泡排序
#include <stdio.h>
struct student
{
	char name[21];
	char score;
};//这里创建了一个结构体用来存储姓名和分数
int main()
{
	struct student a[100],t;
	int i,j,n;
	scanf("%d",&n); //输入一个数n
	for(i=1;i<=n;i++) //循环读入n个人名和分数
		scanf("%s %d",a[i].name,&a[i].score);
		//按分数从高到低进行排序
	for(i=1;i<=n-1;i++)
	{
		for(j=1;j<=n-i;j++)
		{
			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[i].name);
	getchar();getchar();
	return 0;
}
//第三节 快速排序
#include <stdio.h>
#include <stdlib.h>
int a[101],n;//定义全局变量,这两个变量需要在子函数中使用
void quicksort(int left,int right)
{
	int i,j,t,temp;
	if(left>right) return;
	random=rand()%(right-left)+left; 
	temp=a[random]; //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;
	quicksort(left,i-1);//继续处理左边的,这里是一个递归的过程
	quicksort(i+1,right);//继续处理右边的,这里是一个递归的过程
}
int main()
{
	int i,j,t;
	//读入数据
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		scanf("%d",&a[i]);
	quicksort(1,n); //快速排序调用
	//输出排序后的结果
	for(i=1;i<=n;i++)
		printf("%d ",a[i]);
	getchar();getchar();
	return 0;
}

注:代码未做检查,如果有问题自行调试。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值