00:00
好,紧接着我们再写我们最下一个比较核心的代码,哪一个方法呢?好,下面就是我们真实的解码方法。好,下面我们写一个方法就是。干什么呢?编写,编写一个方法完成什么呢?完成对这对这个。对这个压缩数据,压缩数据的解码。OK,那现在我开始来写最终这个方法了,Private private好,Static,那么你解码完了功能,你返回的就是那个真实的字符串的对应的对应的那个BA了啊,那就decode decode好,你给我传一个什么进来呢?肯定你要把这个哈曼的编码你要给我,呃,编码表你要给我传进来,说说我哈曼什么呢?Co。扣子好,你还要把什么呢?哈曼,经过哈曼编码过后的那个字节数组给我反过来,我叫halfman,什么呢?Bites。
01:09
好,BYS,我把这个方法做一个简单的说明。好,跟上我的思路,这个是哈夫曼编码,就是你原先用的那个哈夫曼编码。哈夫曼。哈夫曼编码。哎,编码那个表其实就是一个map,那么这个bit词是什么呢?说的再直接一点,这个bit就是。这个拜就是你呃接就是哈夫曼编码处理过的那一个,这个玩意儿,说白了就是这个东西啊,就是你们看到的这个东西,就是哈夫曼,就是哈赫赫夫曼啊,赫尔夫曼编码得到的这个字节数组。好,那么我们将来返回的是什么呢?返回的就是原来的,原来的这个字符串对应的什么数组?
02:07
好,明明白的意思吧,大致应该明白了,好,现在呢,我们就开始来写这这段代码。首先呢,同学们看。我们第一步是要得到,我们是要得到这一个,呃,哈弗曼bit数组对应的那个哈弗曼的编码的那个二进制字符串,第一步我说啊先。注意听这个稍微有点麻烦啊,先得到这个哈曼bits对应的注意听啊,稍微有点麻烦,应的这个二进制,二二进制的什么呀,字符串,那也就是说实际上就是这个。实际上就是刚才我们分析的。就这个东西啊,形式如这个。就稍微有点麻烦啊,如比如形式是这样子的,一个这样的,嗯,好,形式为这个,那是不是我们现在就可以来做这个工作,这个时候需要需要拼接,因为你要得到一个支付串码,需要拼接,我就用string builder,我先溜一个string。
03:15
Stream builder,这个应该很好,很好理解string builder。好,我得到一个string build拿到了,现在我还是用一啊,为什么他老是给我分配一个二。好,Builder我们拿到了下一步,下一步呢,我们要干什么事情呢?好将。将bit。BY数组A数组转成转成二进制的什么呀,字符串代码就开始写了,负循环。In ti等于零,I干什么呢?小于half,曼拜数组的认识,我就I加加,也就是说我一个一个自己进行处理。
04:02
是不是我一个个处理,嗯,那么怎么处理呢?同学们有没有发现我们前边。已经拥有了这个方法,就是bit bit to string。我我我在这个地方要去填一个真还是假。什么时候为真,什么时候养呢?我们刚才已经讲过,就是在这讲过,如果是最后,如果是最后一个字节,我们不需要补高补补高位,这点是不是刚才我已经讲过了,我在这再说一下啊,如果是最后一个字节,无需。无需补高位。补高位,可能有些东西还不知道老师在说什么啊。有些同学可能不知道说什么,我举个例子嘛。嗯。比比如说比如说你你在28了,你到最后这个28,各位同学28是多少位,就是他不一定是八位了,因为你前面负的88,负的65,负的56,负的65,这个它一定要是八位,八位的嘛,因为因为因为一个一个BAT是一个八位,你才能把它穿起来嘛,但是到了最后这一个是不是原先我们。
05:16
我们在这个形成这个28的时候,我们也没有说按照八个字节来处理的,是不是是这样子的吧,所以说你这个28到时间它成是多少就是多少,比如说打个比方啊,比如说28我转成了这个位数,注意听讲啊,这个其实一下就明白了,假设28是十进制。十进制我放过去,那么我转成二进制,它其实就是11100。1110,那你是11100,你就直接拼在这个后面就行了,你不能这样写啊,你不能说,诶我也补全后面,前面还要给他补三个零。那你这个就错了嘛。对不对,它本身在负的99后面这个字节,这个负,负的90肯定是有八位的,后面呢,你负28,假设是111,假设1110,你把它补上就可以了,你没有必要在这个上面你还加三个零了,你加三个零就错了。
06:13
是不是,所以说说说我这说的这一点大家看是不是就理解了,就是说如果是最后一个字节无需补高位。对不对,那所以说我们在进行转换的时候呢,我们要判断是不是最后一个字节,判断是不是最后一个字节,这个大家是不是就理解一点了,那我写一个boing flag等于什么呢?好,我写一个这个大家看能不能看懂I等不等于half man。Halfman bits,诶,我看看啊,Half bit.n减一。OK。就是如果这个I等于了它的最后一个好,那么就为真,那么为真的情况下呢,我们就不要再去补了,所以说我这取个反,取反过后把这个B返回去,好这个事就完成了,那么每拿到这个是不是要拼接到我们这个string build里面去啊,那就end upon什么呀,就是我们这得到这个字串,好同学们,我们第一步最关键的事情已经做完了。
07:17
那同学们我们输出一下,看看到底是不是跟我们想的一样呢,不知道对不对,System,好,各位朋友,现在我们打出就是赫夫曼。赫夫曼,对,呃,解码后解码赫夫曼字节数组干什么,就是转对应的。对应的这个二。二进制,二进制字符串等于多少呢?我们把它输出一把,实际上就是BU。点什么呢?To string,我们看看对不对。哦,我们看看对不对,后面这个,因为我还不用,我先返回一个空好吧。
08:00
我先返回一个空啊,这个地方好像有语法错误是不是,呃,他说什么问题。是最B啊,这个不是BB不对,我看到flag传进去,呃,是一个什么呢。Flag传我们是不是还没取出来呀?是不是我们还没有把它取出来,应该把它取一下才对,对,忘了取出来了,那就应该有个后慢。BAT把这个I写进去,然后用什么来接收呢?用一个bit来接收,是不是少了这句话?这样这样就对了,这样就对了,我们来打一打吧,我们来测一下,看看这个编码过后对不对,好,这个我先把它去掉,来我们。输出一下D扣。D扣的过呢,我先把和曼编码传过去,再把这个数组也传过去,这是我们编码过后的数组,对不对?好,我们执行一下,我们执行一下运行,那运行过后我们可以看到,诶,它返回的就是这个串。
09:03
这个串是不是以前那个串呢?我们把以前那个串打一下,我们以前这个串在哪里可以看到。是不是?在这个。嗯,在这个地方做了一个。Get code。哦,在哪个地方可以看到呢?这是创建赫夫曼数。创建赫夫曼数过后,对,我们得到一个赫夫曼的编码表,那应该在这里面才能看到是吧?我进去看一下。呃,再到这里面过后呢,我们诶。这个是他。是不是是这样子的,好,我在这呢,打出来是build对应的这个串串是不是这样子的,我们比较一下。比较一把,看看对对不对啊各位同学我运行一下。运行一下,好,我们看看上面这个和下面这个是不一样,1010100。1010100好是对的,我们看最后的位数对不对。
10:04
11100 11100,完全的正确,好,那说明我们这第一步已经OK了。也就是说我们刚才写的这个方法。这个方法已经可以得到了,好,下面呢,老师继续写代码,这这个方法稍微有点长哈,稍微有点长,那面我们接着写代码。嗯,拿到这个,呃,二进制字符串过后呢,下面我们完成一件事情,把什么呢,把字符串,把字符串按照。按照什么呢?按照指定的赫夫曼编码,赫夫曼编码干什么呢?进行解码。进行解码,那这个解码的时候,大家看到原先我们这个赫夫曼编码表,它是前面是一个是一个对应的字符,然后是赫夫曼编码,现在要反过来了,是不是现在要把什么把这个赫夫曼编码,赫夫曼编码表。
11:09
编码表进行一个调换,呃,为什么要,为什么要调换呢?因为因为要反向查询。反向查询。你看啊,你原先写的,比如说你97。是一个A,它对应的啊,对应的这个码,比如说100假设啊,现在你是不是要反过来查100对应的是哪一个阿斯码表,或者说对应的哪一个字符啊,比如原先是A对应。A对应的这个100现在是要反过来看1100是不是等于A啊,所以说我要转调转调转的话呢,我就不啰嗦了,我这直接写个菌,然后这边呢,我们写个bit,反过来写的,反过来写的好,这边呢我们写个MAP61个哈希map。反转准备,那反转它的K是字符串,呃,然后呢,它的值是一个BY。
12:07
好,现在我来反转一把,看看代码能否看懂map.entry。map.ent这个稍微麻烦点,稍微慢一点,这边是一个bit。好,这边是一个string。这边是一个使君恩翠。Entry大家看这个地方能否理解啊,然后我们是从哈曼。这一个扣子里面取出它的entry size。是不是也就是说现在我从这个哈弗曼Co里面取出了他原先最原始的那个,呃,就是他的赫夫曼编码表be和试卷的关系,那拿到过后呢,我们现在反向往里面放K就变成了N。点get它的value,大家看懂了没有,而它的value呢,恰恰是它的K就N。
13:04
点GA get他的key,好,这样就达到一个反向的,那么同学们有兴趣可以把这个输出来看一下,我们简单的看一看啊各位朋友,那现在这个map等于什么呢?我给大家打出来一下。好的,各位朋友,我运行一把。好,各位同学,我运行一把。啊,这边有个错误,是因为我们这没有返回值,我还返回一个空,主要是为了调试。同学们看现在是不是我反向拿到了,说113个零对应的是108 108肯定是对应一个字符嘛,我们看看你看零一三十二零一是不是空那个空串啊,100是不是九十九十七就是A嘛,反过来写的好,有了这个反向的。反向的赫夫曼编码过呢,下面的代码我们就继续完成,那下面应该怎么写了呢?有了返新的编码表,现在我们就要去创建一个集合,对,我们创建一个集合。
14:05
干什么呢?存放存放,我们的BAT要往里面放了。好,现在我先创建一个集合,里面放的是我们的BA,有的到时就往里面放了,我new一个r list,加上思路就稍微有点麻烦。啊,稍微有点麻烦,我拿到一个我干什么呢?我要开始便利了,我便利谁呀,我要便利我得到的这一个build。因为你的build里面是他。对应的这一个二进制的字符串是不是我们八位,我八位取一个半,我每八位进行哦,我不是每八位啊,我是。嗯,每一位一位的扫描,扫描过后扫到一个就比较看看在这里面有没有,在这个编码表里面有有没有,有的话我就放在这个list里面去,没有我就继续扫描,大家看懂了没有,好,稍微有点麻烦,我们来写写,那int I呢,大家看int I等于零。
15:07
I呢?只要它小于string build,注意听点。对A加加。是不是我只要满足这个条件,我就不停的扫描这个I呢?你可以理解成I,可以理解成就是一个。一个索引啊,一个索引,他在不停的什么呢?不停的扫描在扫描。扫描哪个呢?我们使build。哦,注意啊,这个string builder其实就是这个二进制对应的字符串。大家。是不是刚才已经给大家看过了。好,现在我们就来开始扫,可是你扫的时候呢,有一个问题,我们先理解一下怎么去扫它,各位同学,我要稍微的给大家画一个示意图,不然待会我讲起来,大家听不懂我在说什么。好,同学们看,假如现在我们这有个字符串啊。
16:01
这个是我们的二进制的周算。好看好的,嗯,因为你这个字符串呢,我们有一个I。在不停的扫。啊,扫到一个我们就加进去啊,扫一个我们要比较,比较完了,如果是我们再加进去,但是但是你在扫的时候,比如你扫到一个,你扫到一个,下一次这个I是不是又得重新来一遍啊,因为你你的I呢,是要重新开始计数的。所以说我为了解决这个问题呢,同学们看啊,我要这么去处理一下,我定义一个count。代孕。一。哦,等于一,然后呢,我再定一个booing flag。Flag等于一个处,我待会有用,我再定义一个bit。B等于一个空,好同学们现在呢,不太知道我的意思,这个count啊,它是用来做什么呢?它是用来去扫描,每就是扫描,就是相当于一次小在扫描,在得到一个对应的编码的时候呢,它的是一个小的计数器,你可以认为它是个小的小的计数计数器。
17:15
理解吧。好,那我现在把这个代码写完,大家可能心里面就比较清晰了,Well well,循环flag,只要这个flag为帧,大家看我就不停的去做,我怎么做呢?我先取出哦,注意听我先取出一个字符。啊,一个字符。诶,一个一应该不是取出一个字符啊,应该是取出一个,呃,一或者是。或者是零。好,那么我就拼接,大家看,我这里先取一个K,怎么写呢?String builder,跟上我的思路,点sub string。
18:00
好,我怎么取我ii加count。大家知道我我在干什么事吗?好,也就是说零进来的时候呢,我这边是0I是一,就相当于先取一位。就是以这个I不动让抗走。相当于是I不动,让什么呢?让count移动,让count移动。直到什么呢?直到匹配到。一个。匹配到一个什么呢?匹配到一个字符。理解这意思吧。好,那我拿到这个过后呢,我要做件什么事情呢?我B,我看看他有没有点盖子,谁要这一个。K。K,大家有没有发现这个K是在逐渐的增长的,这个是取哦,这个不一定是取出一个了,这个是第,嗯,你看啊,第一次这个I呢是等于零,这个count呢等于一,那下次取,如果取不到我,我就让这个countt加加一,这样子的话呢,这个K在不停的变化,就是说这个不好讲,大家听啊,就是这个I呢,在I不动,但是count在不停移动,直到他匹配到一个字母,也就是说它这个编码呀,这个K。
19:18
啊。啊取就是不递递增的吧,应该这样写,递增的取出取出这个。呃,String builder,取出这个K吧,这样写大家应该理解了,比如你第一次假,假如你第一次取的是一。我们看看map里面有没有,那么如果没有的话呢,我那个count再加一下,是不是我现在取的就是010了。大家看懂了没有啊,如果我把这个拿下来,大家待会呢,就看的比较清晰了啊。如果我把这拿出来,就好像这个I呢,在这不动。就是挨在这是不动的,但是这个count呢,帮助我们中count,第一次A走到这儿,不是再取,再取,直到你取到一个。
20:03
好,知道你取到一个,那我就开始判断了,如果这个B它等于空,说明还没有匹配到。是不是说明还没有匹配到?说明没有匹配到,没有匹配到,我让这个count呢加加。好A,说明什么?我匹配到了。匹配到。那匹配到匹配到你是个什么东西呢?好,那我就可以退出了,Flag等于一个。什么呢,等于一个false,大家看你一旦等于false的话。整个这个外循环就退出。整个外循环就说群退出过后呢,我怎么玩呢,大家看这时我让这个list加入,我们找到这个B就完事。大家看是这个意思,做完这个事情,让这个I呢,直接增长到count这个位置,是不是下次下次继续来玩了,那这个count为什么错了。
21:03
C啊,这空格不能打。好,这个让I直接直接移动到count这个位置,而且注意是。递增的啊,也也就是说你可以这样理解,我们这个I第一次是在这个位置,当它匹配到一个字符过后呢,匹配到一个字符过后,他就直接到下一个位置,这个I就到这来了上再让那个count count你不上来,每次都先制了一个一吗?它又开始走一圈这个坑坑如果又载到一个呢,好把它加进去,把加进去过后让这个I呢,继续移动到下一个位置。相当于说这个抗体在帮我不停的跑来跑去的,I呢,一次性的走一圈就可以了。大家看能看懂吧,好,当我们把整个这个外循环。做完了以后,大家想,是不是此时此刻我们这个list里面就存放了什么,存这个list里面就存放了我们所有的。
22:02
这一个字符,这个能能理解吗?好,我写到这。当for循环,For循环结束后,结束后我们这个历史特征,历史特征就存放了。存放了所有的字符,什么谁的字符呢?说的再直接一点,其实说白了就是把你的这句话就是I like。把你这个I like,就是这个字符串里面所有的单个的字符就已经存进去了。好,但是你这样子返回一个历史是不对的,因为它最终呢是要返回一个BY的数组。因此我们要把。把什么呢?List中的数据放入到一个bit数组并返回。并返回。是不是这样的同学们?
23:00
好,老师开始写了啊,Bit呢,我就写个最简单,B等于六一个bit,它的大小是多少呢?显示list的点size。是不是好,拿到这个过后我们往里面扔东西了。int I等于。0I小于什么玩意儿呢?小于B点认识,诶B点认识诶,啊这么写错了吗。Bit数,诶,这忘了给一个数组了对不对?没关系,我们加上就行了,I小于B点认I恰恰对不对?I加加,大家还跟上我的思路吧,I等于多少呢?OK list.get一个I。是不是往里面再扔了,最后我们是不是直接返回这个B就完事了。好,同学们这个呢,就是通过这个解码过后,同学们我们就拿到这个BAT了,那有有些同学老师这个be到底是不是你的那个I like什么什么的,一句话呢,好,我们来玩一把。
24:03
你这是不是返回一个数组啊,同学们,好的,那这个就是我们的B,这个相当于是。呃,原来的那个呃,叫source吧,Orc,原来的那个bit数组。是这样子的吧,好,那么我们可以把它输出来看一看。我们把它梳出来看一看。来原来的字符串,原来的字符串我们输出一把,是不是等于S。A硕点点to string。这个时候如果没有出问题的话呢,他就应该输出了这句话。但如果我们这代码有问题,那就要调试了,这些调试那就是大事啊,那就是大事,因为你你看咱们这段代码呢,写的还是比较多的,哪一个地方出了问题,不好说,不好说,那现在呢,老师给大家运行一下,我希望咱们一次过把它过了对不对,一次把它过了,好各位同学我们运行一把。
25:07
运行一把。诶,大家看这有问题,我们这儿。键盘是不是不需要啊,看看怎么输出这个玩意儿呢,这样子输出看对不对。啊,这样还不行,哈托斯最我们看能不能溜一个溜一个字符串。把这个放进去呢。看行不行啊。这样子运行一下看看。好,同学们看我们拿到了,但是拿到这个东西跟我们想的其实是有区别的,长得很怪,对不对?那问题出在哪里了?同学们大家想一想,我们这个地方的问题出在哪里了?大家想错在哪里了?好,这个地方我们要进行一个简单的调试,对我们要进行一个简单调试,把它看看问题是在哪,是在哪个地方出现的,调一把。调试也是增长我们一个写代码的能力,对不对,没有关系啊,调一调就可以了。
26:05
看一下吧,嗯,这个调试起来有点难度,我们再看一下输出这个东西给我们看一下,这么怪啊,好,我们看一下啊,呃,我把这个长度打出来,看看他到底有多大,按理说呢,应该是40。但是你看30,他现在长度只有30,那我们看哪个地方出问题,因为前面我们测试都没有毛病,都没有毛毛病,包括我们在这把这个实存build打出来生也是正确的,对不对?这个地方是不是把赫夫曼编码进行调换也没问题,那下边呢,如果要出问题,一定只只能是这个for循环出了问题了。只能是这个破循环出问题,那我们来看看破循环的问题在哪里呢?大家看这个I啊,我们这个I是在诶II等于零,I小于I加加不对呀。
27:00
I,哦,对,这个地方有问题,大家看,因为我们这个I呢,不再是按这个加加的形式来走的,我们I是不是是刚才分析的是这样子的,就是听我听我讲啊,听我讲,假如我们这有个字符串,我们ID一次是指向这个零的,然后count这个玩意呢,在不停的帮我们找匹配好,Count结束以后,这个I是直接移动到count加一的这个位置,所以你在这写个I加加,那就出大问题。那肯定会造成少扫描。好,那这样子我们把这个I加加就去掉了就可以了。把这个爱加加去掉应该就可以了,来,再来玩一把。再来玩一把啊,如果这个不行,我们再调玩一把走。好,40好正确长度是正确的了,但是这个结果正不正确我们不知道,来,再来玩一把运行车。诶,非常的幸运,我们拿到I like like like Java do you like加very good very good,好,同学们,那关于我们这一个就是。
28:05
就是把这个数据进行压缩,然后呢再用我们赫夫曼编码进行解码,这块的内容呢,就给大家先讲到这里,大家看看能不能理解哦,这段代码说实话还是有一点难度的。主要是这里面涉及到。呃,一些Java的基础,另外呢,还涉及到一个二进制的这么一个内容。好,同学们把这段代码好好的看一看,理解一下。
我来说两句