chapter1.找出你最不常用的几件衣物

在chapter0 中,我们设计了一个产品,叫私人衣橱。这个手机app帮助我们管理衣物,方便我们查找衣物的位置,也可以展示我们的衣服。
现在这个app要添加新功能:

  • 找出过去一年中,自己最不常用的10件物品,看是否需要转卖或者扔掉。

怎么实现这个功能呢?方法有很多,我们先来介绍第一种方法:

“堆”

这个堆不是土堆、人堆,而是数据的堆。

特征

计算机语言里的描述:堆是指一个特定的基于树结构的数据结构。
我们先不管这个抽象的描述,我们只需要记住堆的特征:
一.任何一个节点不大于父亲节点(大根堆)
比如下面这幅图,2的父节点是17,17的父节点是19,是不是子节点小于父节点。不过19不是2的父节点,因为中间跨了一层。其他以此类推。100叫根节点,因为它已经到顶了,没有父节点。


chapter1.找出你最不常用的几件衣物_第1张图片
堆-数据结构

二.它必须是一棵完全二叉树:就是除了最后一层节点外,其他层节点数必须是两个,最后一层的所有节点集中在最左侧。
如下图:


chapter1.找出你最不常用的几件衣物_第2张图片
p1

它是一个正确的例子:55必须有两个子节点:22;25。22和25 不一定是有两个子节点,因为他们已经最后一层。

又如下图:


chapter1.找出你最不常用的几件衣物_第3张图片
p2

它是一个错误的例子,为什么?最后一层的所有节点没有集中在最左侧。因为子节点必须从上往下,从左往右添加。

了解完堆的概念,那么堆有哪些分类呢?
首先是:大根堆,即根节点的值最大,逐层递减,最下面一层的数据最小。
再次是小根堆:正好和大根堆相反。

介绍完堆,我们回到上面的问题,假设我们有一系列的衣物,他们的使用频率分别是:35 33 42 10 14 19 27 44 26 31,我们将组数据构建成一个大根堆,从下往上层级的节点必然是小的值。

最终的结果是这样的:


chapter1.找出你最不常用的几件衣物_第4张图片
大根堆

具体构建大根堆的步骤:
Step 1 − 在堆的底部创建一个新节点
Step 2 − 将值放在该节点
Step 3 − 比较新关键的节点值与它的父节点值大小
Step 4 − 如何父节点值小于新节点值,那么交换他们
Step 5 − 重复第三步和第四部

chapter1.找出你最不常用的几件衣物_第5张图片
堆的创建

好了,现在堆创建好,我们需要将频率最低的几个数据取出,堆是一种特殊的树(一种数据结构,后面再介绍),遍历数据有两种方式:广度遍历和深度遍历,方式如名字:
广度遍历方向:


chapter1.找出你最不常用的几件衣物_第6张图片
广度遍历

遍历出来的数据是:
44 42 35 33 31 19 27 10 26 14

深度遍历方向:


chapter1.找出你最不常用的几件衣物_第7张图片
深度遍历

遍历出来的数据是:
44 42 33 10 26 31 14 35 19 27

利用广度遍历,已经基本是从大到小了,后面的几个就已经基本满足我们的要求了。而且我们还可以知道,根节点就是我们使用频率最高的衣物。
但是我们也发现,广度遍历出来的数据,并不绝对是最后一个数据就是频率最低,这个怎么解决呢?
解决办法是:

排序

将使用频率:35 33 42 10 14 19 27 44 26 31,这组数据进行从高到底排序。也就实现我们的功能。

那排序的算法怎么设计呢?

选择排序(常规思维想到的第一个方法)

思想:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

算法描述
n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果。具体算法描述如下:

  • 初始状态:无序区为R[1..n],有序区为空;
  • 第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1..i-1]和R(i..n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1..i]和R[i+1..n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区;
  • n-1趟结束,数组有序化了。
chapter1.找出你最不常用的几件衣物_第8张图片
选择排序.gif
冒泡排序

冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

算法描述

  • 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
  • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
  • 针对所有的元素重复以上的步骤,除了最后一个;
  • 重复步骤1~3,直到排序完成。
chapter1.找出你最不常用的几件衣物_第9张图片
冒泡排序.gif
归并排序(Merge Sort)

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。

算法描述

  • 把长度为n的输入序列分成两个长度为n/2的子序列;
  • 对这两个子序列分别采用归并排序;
  • 将两个排序好的子序列合并成一个最终的排序序列。


    chapter1.找出你最不常用的几件衣物_第10张图片
    归并排序.gif
基数排序(Radix Sort)

基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。

算法描述

  • 取得数组中的最大数,并取得位数;
  • arr为原始数组,从最低位开始取每个位组成radix数组;
  • 对radix进行计数排序(利用计数排序适用于小范围数的特点);


    chapter1.找出你最不常用的几件衣物_第11张图片
    基数排序.gif

排序的算法还有很多,就不一一介绍了。

总结

选择排序:不停找最小值(效率也是最低的)
冒泡排序:相邻比较,不停交换,冒泡
归并排序:分组,不同组之间比较
基数排序:非比较类算法,先低优先级再高优先级排序
上面的堆也是也可以达到排序的目的。

通过排序,我们就可以得到降序的一个数组:
10 14 19 26 27 31 33 35 42 44

还怕找不到你最不常用的衣物吗?好了,最不常用的衣物已经找到了,快去处理掉把。

其他知识

堆的删除

从叶子开始添加,删除的时候从根节点开始删除。

具体的步骤是:
Step 1 − 删除根节点.
Step 2 − 移动最近一层的最近一个元素到根节点位置
Step 3 − 比较它与子节点值的大小
Step 4 − 加入父节点值小于子节点值,则相互交换
Step 5 − 重复第三步和第四步


chapter1.找出你最不常用的几件衣物_第12张图片
堆的删除

排序图来自https://www.cnblogs.com/onepixel/articles/7674659.html

你可能感兴趣的:(chapter1.找出你最不常用的几件衣物)