当前课程知识点:数据结构(上) > 第一章 绪论(上) > (a)计算 > 01a-5 : 有穷性
考察所谓的Hailstone sequence
对于任何一个自然数n 都可以定义这样一个序列
实际上这个序列是以递归的形式来定义的
具体来讲 如果是不超过1的平凡情况
我们就直接将它对应的这个Hailstone sequence
取做由单个的一个元素1
所构成的一个长度为1的一个序列
一般的情况 如果n至少是2
那么我们就视它是偶数或者是奇数分别处理
如果它是偶数 那么我们就对它做一个除2处理
使它数值变小 折半
然后计算出它所对应的Hailstone序列
再它的前边添加一个长度为1的前缀
只包含一个元素就是原来的那个数n
通过这个union操作使得这两个序列串接起来
构成最终的序列
如果n是奇数 那么就通过对n乘3再加1
得到更大的一个数
然后同样递归的得到它所对应的Hailstone序列
并且也是同样的在它前面增加一个长度为1的前缀
从而构成我们所需要计算得到的最终的那个序列
我们来看一下一个具体的实例
比如说n=42
我们可以看到42是非退化的情况
所以按照偶数的规则 它应该折半
所以我们先把42记在这 相当于它转换为21
再接下来呢 我们要考虑的是奇数的一个问题
根据刚才的规则 这个21应该乘3加1
所以从而转换为64 也就是说又变成了一个偶数
接下来我们对偶数折半 并且继续折半 点点点点
那么 敏锐的同学可能已经发现了
之所以我们这里用点点点
是因为后面的故事情节是一目了然的
原因在于64是一个很特殊的数
它除了2以外 没有其他的素因子
所以它可以不断的除2除2除2
直接了当不断的除2 直到最终得到平凡的1
在这个过程中 我们注意到
确实这个序列中各项的数值
有的时候会折半下降
也有的时候会因为乘3加1上升
也有的时候会连续的下降
所以总体来说
它体现出一种飘忽不定琢磨不透的形式
有一点我们可以补充说明一下
就是说 虽然它有可能持续的下降
但它绝对不会持续的上升
原因在于任何一个奇数乘以3再加1以后
它必然会回到偶数的状态
所以它接下来必然会紧接着除2折半
而不会连续的乘3加1
但是即便如此 我们也待会会看到
更复杂的一些例子里头
它会变化确实很捉摸不定
呈一个上下起伏动荡的过程
整个这个过程与冰雹运动的过程非常相像
有时候会偶尔上升 但是紧接下来总体会下降
有时候又会偶尔上升
接下来又会间或的不断的下降
直到它最终 如果确实有这样的情况发生的话
落到地面
程序设计略有基础的同学
都不难写出下面这样一段程序来计算这个序列
当然这里与其说是计算确切的大写的Hailstone序列
不如说这个小写的程序实际上是计算这个序列的长度
我们说其实这已经足够说明问题了
所以我们不必把这个事情搞得更复杂
简单来看 小写的这个hailstone是如何来计算
大写的Hailstone序列的长度的呢
按照刚才的定义 我们这个计数器的初值取做1
接下来呢 我们要把刚才那样递归定义的过程
转换为一个循环
也就说不断的视当前的n的奇偶性来分别做处理
经过模2做一个测试以后 奇数就按乘3加1处理
如果是偶数就按折半处理
而每处理完一次以后
都会相应的把它的长度递增一个单位
所以当这个循环执行完后 返回的这个length值
应该就是不折不扣的对应的序列长度
所以这个算法或者说我们如果还不能管它叫算法
我们说这个程序的正确性似乎是不言而喻的
我们马上就会看到 其实这里头是不那么简单的
我们来看更复杂的一些例子
也许能够让我们略微有些感觉
我们会注意到 Hailstone序列的长度
与这个输入的n未必是成正比
比如说42这个大概也就是10来个数
可是取一个小一点的数7
我们就会发现它的长度会远远的超过10
大家可以逐项的验证一下
我们在这不妨抽几个
奇数 乘3加1
偶数 除2 等等等等
那么27呢 介于7和42之间的这个数呢
如果大家有兴趣的话 你回去可以去试一下
用手或一个程序把它算出来
我可以告诉你的是
它的长度比刚才那两个要长很多很多
虽然还不是无穷
所以这里头我们其实已经引导大家
到了这个词了 无穷
我们刚才说的是 有穷
在这里头 为什么值得去讨论那个有穷呢
细致的同学肯定应该已经会脑子里闪现这个问题
上面这个程序如果要称作是一个算法
它就应该满足我们刚刚说过的有穷性
也就是说 它对任何的输入
都应该能够在有限步之后退出返回
那么while这个循环 能够做到这一点吗
对任何n都能做到这一点吗
这不取决于这个程序
而是取决于这个序列本身的定义
也就是说 对于任何的n
它对应的Hailstone sequence的长度
是否都是一个有限的一个长度呢
如果是 那它的有穷性
这个程序的有穷性 自然就满足
否则的话 我们就要打问号
它就不见得能称作是一个算法
那么 据我所知 我可以告诉大家的是
这个问题的结论是 还没有结论
也就是说 我们既不能证明对于任何的n
这个序列都必然是有穷的
反过来 我们也还没有找到一个反例
所以从这个意义上讲 我们这段貌似再简单不过
而且正确性都是一目了然的程序 未必是一个算法
程序未必是算法
这是我们要告诉大家的一个现象
其实这个现象大家并不陌生
大家可以各自回忆一下
在你刚刚学习编写程序的时候
应该会经常犯的一个错误就是写出死循环的程序
当时你得到的反馈就是
机器会告诉你说栈溢出 从而非法退出
老师呢 会给你一个大大的一个叉
然后告诉你说 下次要小心
但是尽管你再怎么小心
我们时不常的偶尔还是会犯这种错误
坦诚的讲 包括我也是这样
所以我们说 算法的有穷性
即使作为算法的一个侧面的要求
也不是那么简单的能够确定的
更不要说还有其他的一些东西
当然好消息是 我们这门课里
只是在绪论部分略微的介绍这些
不会详细的展开更不会去深入的探究
这是其他的课程
其他的学科分支讨论和研究的问题
而我们的问题不是这个
那么我们的问题是什么呢
我们的问题是 在正确性确定性可行性
包括有穷性都基本上确定了之后
如何能够设计并且优化出更好的一个计算过程
一个对应的数据结构和对应的算法
所以我们首先的一个问题就是
什么是好的算法什么是好的数据结构
或者说什么是一个好的计算过程
-选课之前
--写在选课之前
--宣传片
-考核方式
--考核方式
-OJ系统说明
--关于OJ
--1-注册与登录
--2-界面与选课
--3-提交测试
-关于课程教材与讲义
--课程教材与讲义
-关于讨论区
--关于讨论区
-微信平台
--html
-PA晋级申请
--PA晋级
-(a)计算
--演示
--(a)计算--作业
-(b)计算模型
-(b)计算模型--作业
-(c)大O记号
-(c)大O记号--作业
-(d)算法分析
-(d)算法分析--作业
-(e)迭代与递归
-(e)迭代与递归--作业
-(xc)动态规划
-- 演示
-(xc)动态规划--作业
-本章测验--作业
-(a)接口与实现
--02A-5 复制
-(a)接口与实现--作业
-(b)可扩充向量
-(b)可扩充向量--作业
-(c)无序向量
--02C-1 概述
--02C-3 插入
--02C-6 查找
--02C-8 遍历
-(c)无序向量--作业
-(d1)有序向量:唯一化
-(d1)有序向量:唯一化--作业
-(d2)有序向量:二分查找
-(d2)有序向量:二分查找--作业
-(d3)有序向量:Fibonacci查找
-(d3)有序向量:Fibonacci查找--作业
-(d4)有序向量:二分查找(改进)
-(d4)有序向量:二分查找(改进)--作业
-(d5)有序向量:插值查找
-第二章 向量(下)--(d5)有序向量:插值查找
-(e)起泡排序
--02E-2 改进
--02E-3 反例
-(e)起泡排序--作业
-(f)归并排序
-(f)归并排序--作业
-本章测验--作业
-(a)接口与实现
--03A-4 实现
-(a)接口与实现--作业
-(b)无序列表
--03B-2 查找
-(b)无序列表--作业
-(c)有序列表
--03C-3 查找
-(c)有序列表--作业
-(d)选择排序
--03D-1 构思
--03D-2 实例
--03D-3 实现
--03D-4 推敲
--03D-6 性能
-(d)选择排序--作业
-(e)插入排序
--03E-1 经验
--03E-2 构思
--03E-3 对比
--03E-4 实例
--03E-5 实现
-(e)插入排序--作业
-(xd)习题辅导:LightHouse
-本章测验--作业
- (a)栈接口与实现
--04A-1 栈
--04A-2 实例
--04A-3 实现
- (a)栈接口与实现--作业
-(c1)栈应用:进制转换
-第四章 栈与队列--(c1)栈应用:进制转换
-(c2)栈应用:括号匹配
-(c2)栈应用:括号匹配--作业
-(c3)栈应用:栈混洗
-第四章 栈与队列--(c3)栈应用:栈混洗
-(c4)栈应用:中缀表达式求值
-(c4)栈应用:中缀表达式求值--作业
-(c5)栈应用:逆波兰表达式
-第四章 栈与队列--(c5)栈应用:逆波兰表达式
-(d)队列接口与实现
--04D-1 接口
--04D-2 实例
--04D-3 实现
-第四章 栈与队列--本章测验
-(a)树
--05A-1 动机
--05A-2 应用
-(a)树--作业
-(b)树的表示
--05B-2 父亲
--05B-3 孩子
-第五章 二叉树--(b)树的表示
-(c)二叉树
-(c)二叉树--作业
-(d)二叉树实现
-(d)二叉树实现--作业
-(e1)先序遍历
-(e1)先序遍历--作业
-(e2)中序遍历
-第五章 二叉树--(e2)中序遍历
-(e4)层次遍历
-第五章 二叉树--(e4)层次遍历
-(e5)重构
-(e5)重构--作业
-本章测验--作业
-(a)概述
-(a)概述--作业
-(b1)邻接矩阵
-(b1)邻接矩阵--作业
-(c)广度优先搜索
--06C-2 策略
--06C-3 实现
--06C-5 实例
-(c)广度优先搜索--作业
-(d)深度优先搜索
--06D-1 算法
--06D-2 框架
--06D-3 细节
-(d)深度优先搜索--作业
-第六章 图--本章测验