记不得什么时候,我们群里发问题,如下:
有两个表,各存放了数亿条网址记录,而这两个表中有一部分是相同的,现在求出两个表中不同的数据项。
咋一看这题目,我就没辙了,如果简单用sql语句,恐怕不知道要何时才能得出结果,所以需要将他们取出来放到数组中。而如果把他们从数据库中取出来,又有什么办法能够求出呢?假设那两个数组分别为A []、B[],如果我首先遍历数组A,然后每条数据都遍历数组B,那效率也是相当的慢。
前思后想,忽然有个思路,倒是可以跟大家交流一下。
步骤1)首先对两个数组排序。对于排序我们都知道有多种方法,我们就用最快的排序,快速排序对它们排序吧。
假如数组A的数据如下:
[0] www.blog.com
[1] www.amazon.com
[2] www.sina.com
[3] www.baidu.com
[4] www.sohu.com
数组B的数据如下:
[0] www.blog.com
[1] www.sina.com
[2] www.iteye.com
[3] www.csdn.com
[4] www.sohu.com
排序的时候,前边的字符串www.可以直接抛弃不管,只对www.字符串之后的数据排序,排序的时候要注意了,不能仅仅对第一个字符进行排序,还要对字符以后的数据依次排序。如对数组A的排序,排序后结果如下:
[0] www.amazon.com
[1] www.blog.com
[2] www.baidu.com
[3] www.sina.com
[4] www.sohu.com
此时我们已经对首字母进行排序了,然而我们还需要对首字母后的数据依次排序,结果如下:
[0] www.amazon.com
[1] www.baidu.com
[2] www.blog,com
[3] www.sina.com
[4] www.sohu.com
注意粗斜体部分,他们的位置已经发生了变化。当然首字母以后的字母排序和首字母排序可以写到一起,我是为了说明问题,并不说要排序两次。
数组B的排序如数组A,排序后结果如下:
[0] www.blog.com
[1] www.csdn.com
[2] www.iteye.com
[3] www.sina.com
[4] www.sohu.com
排序完成了,进行步骤2.
步骤2)
同时对两个数组循环比较。
1)两个数组的长度不一定是相等的,所以要求出两个数组的长度,取最大长度。
代码大致如此: long count = length(A) > length(B) ? length(A) : length(B);
2)然后来个循环,根据下标依次比较两个数组,如果数组A[i]的首字目比B[i]的小,那么A[i]为异同项,那么数组A的下标则向下移一位,然后继续与B[i]比较,直到B[i]的项比它小为止;如果数组A[i]的首字目比B[i]的大,则B[i]为异同项,则数组B的下标下移一位,继续与A[i]项比较,直到B[i]比它大为止;如果相等,那么他们的下标都下移一位。比较时必要时还要比较首字母后续部分。循环次数为count;
以以上的数据举例:
先用A[0]与B[0]比较,则发现A[0] www.amazon.com比B[0]
www.blog.com的首字母小,那么A[0] www.amazon.com则是异同项,那么A[0]的数组下标下移一位即:www.baidu.com,继续与B[0]www.blog.com比较;
此时将发现它们首字母相同,那么继续对第二个字符比较,很快发现 A[1] www.baidu.com比B[0]www.blog.com小,那么A[1]也是异同项;
继续对A的数组下移一位 A[2]对 B[0]进行比较,那么发现他们是相同的,此时将他们所有的下标都下移一位,用A[3]对B[1]进行比较,按照上边的发法,那么发现,A[3]比B[1]、B[2]都大,所以B[1]、B[2]都是异同项;
而对A[3]与B[3]比较时,发现他们是相同项,所以他们的数组下标都下移一位;
用A[4]与B[4]进行比较时,发现他们是相同项,所以他们的下标也下移一位;
此时循环条件已经不满足了,所以他们退出循环;
由此可以知道,他们的异同项为:A[0] www.amazon.com、 A[1]
www.baidu.com、B[1]www.csdn.com、B[2] www.iteye.com;
此时求解完毕。如果快速排序的情况最坏为 n*n,那么我们的运行次数为:
数组A的排序:length(A)*length(A)
加上数组B的排序length(B)*length(B)
再加上比较的次数count,那么总数为:length(A)*length(A) +length(B)*length(B) + length(A) > length(B) ? length(A) : length(B);这好像比我刚开始说的循环遍历数组A,每一项再遍历数组B依次比较公用的时间length(A)*length(B)的时间要多出很多。然而大家都知道,快速排序的这种情况基本上很少出现,平均情况下只需要:n(log n),也就是说比如数组A、B各有1亿条数据,每个只需要循环8亿次,一共加起来共计算18亿次,这明显比每项依次比较1亿*1亿要好很多。