• 关于

    repeat循环结构

    的搜索结果

问题

ng-repeat如何把两组数据循环放入一组结构中?

杨冬芳 2019-12-01 20:10:22 1339 浏览量 回答数 1

回答

for 循环 本系列前面 “探索 Python,第 5 部分:用 Python 编程” 一文讨论了 if 语句和 while 循环,讨论了复合语句以及适当缩进 Python 语句来指示相关 Python 代码块。该文的结尾介绍了 Python for 循环。但就其使用和功能来说,for 循环更值得关注,所以本文单独讲述该循环。 for 循环有一个简单的语法,使您可以从容器对象中提取单个项目并对其进行某些操作。简单地说,使用 for 循环,可以迭代中对象集合的项目。对象集合可以是任何 Python 容器类型,包括前面文章中讨论的 tuple、string 和 list 类型。但是容器 metaphor 的功能比这三种类型更强大。metaphor 包括其他序列类型,如 dictionary 和 set,将来的文章中将对它们进行讨论。 但是请稍等!还有更多信息:for 循环可以用于迭代支持迭代 metaphor 的任何对象,这使 for 循环非常有用。 清单 1 中显示了 for 循环的基本语法,还演示了如何在 for 循环中使用 continue 和 break 语句。 清单 1. for 循环的伪代码 ? 12345678910111213 for item in container: if conditionA: # Skip this item continue elif conditionB: # Done with loop break # action to repeat for each item in the container else: # action to take once we have finished the loop. 本系列中的第二篇文章 “探索 Python,第 2 部分:探索 Python 类型的层次结构” 介绍了 Python tuple。如文中所述,tuple 类型是不可变的异构容器。这主要是说 tuple 可以存放不同类型的对象,但是它一旦创建,就无法更改。清单 2 演示了如何使用 for 循环迭代 tuple 的元素。 清单 2. for 循环和 tuple ? 1234567891011121314151617 t = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) count = 0for num in t: ... count += num... else:... print count... 45 count = 0for num in t: ... if num % 2:... continue... count += num... else:... print count... 20 本例首先创建了名为 t 的 tuple,存放整数 0 至 9(包含 9)。第一个 for 循环迭代此 tuple,在 count 变量中累计 tuple 中数值的和。一旦代码已经迭代了 tuple 中的所有元素,它将进入 for 循环的 else 子句,打印 count 变量的值。 清单 2 中显示的第二个 for 循环也迭代 tuple 中的所有元素。但是,它仅累计容器中能够被 2 整除的那些项的值(请记住如果表达式为非零,if 语句将确定为真,num 不能被 2 整除时使用 % 运算符会返回非零值)。此限制通过使用适当的 if 语句和 continue 语句来完成。如前面的文章中所述,continue 语句使包含它的循环开始下一次迭代。实现相同结果的另一种方法是测试 tuple 中的当前项是否是偶数(使用 if not num % 2:),如果为真,那么将当前项添加到运行总和中。一旦代码完成 tuple 中的迭代,将调用 else 子句,打印总和。 本系列中的第三篇文章 “探索 Python:第 3 部分:探索 Python 类型的层次结构” 讨论了 Python string。string 是不可变的同构容器,这意味着它仅能存放字符且一旦建立将无法修改。清单 3 演示了如何使用 Python string 作为 for 循环的容器。 清单 3. for 循环和 string ? 123456789101112131415161718192021 st = "Python Is A Great Programming Language!"for c in st: ... print c,... P y t h o n I s A G r e a t P r o g r a m m i n g L a n g u a g e ! count = 0for c in st: ... if c in "aeiou":... count += 1... else:... print count...10 count = 0for c in st.lower(): ... if c in "aeiou":... count += 1... else:... print count... 12 本例提供了三个不同的 for 循环,它们都迭代同一 string。第一个 for 循环迭代 string “Python Is A Great Programming Language!” 并一次打印 string 中的一个字符。在此例中,print 语句变量 c 后加了一个逗号。这使 print 语句打印字符值时后面跟着空格字符,而不是换行字符。如果没有后面的逗号,字符将全部打印在单独的行中,会很难读。 下两个 for 循环迭代该字符串并计算其包含多少个元音字母(“a”、“e”、“i”、“o” 或 “u”)。第二个 for 循环在迭代原始 string 时仅查找小写元音字母。第三个 for 循环迭代通过调用 string 对象的 lower 方法返回的临时 string。lower 方法将 string 中的所有字符转换为小写。因此,第三个 for 循环可找到另外两个元音字母。 本系列中的第四篇文章 “探索 Python,第 4 部分:探索 Python 类型的层次结构” 介绍了 Python list。list 是异构可变容器,这意味着它可以存放不同类型的对象且创建后可以修改。清单 4 演示了如何使用 list 和 for 循环。 清单 4. for 循环和 list ? 12345678910 mylist = [1, 1.0, 1.0j, '1', (1,), [1]]for item in mylist: ... print item, "t", type(item))... 1 1.0 1j 1 (1,) [1] 既然 list 是很灵活的 Python 容器类型(您将在本系列其余的文章中多次看到它),本例看起来可能过于简单了。但是,这是一部分要点:使用 for 循环使处理容器中的每个项目非常简单,甚至处理包含各种不同对象的 list 也是如此。本例迭代 Python list 中的所有项目,并在单独的行中打印每一项及其相对应的 Python 类型。 迭代和可变容器 Python list 是一个可变序列,提供了一种令人好奇的可能性:for 循环主体可以修改其正在迭代的 list。正如您可能认为的,这样并不好,如果进行此操作,Python 解释器将无法很好地工作,如清单 5 所示。 清单 5. 在 for 循环中修改容器 ? 1234567891011121314151617 mylist = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]for item in mylist: ... if item % 2:... mylist.insert(0, 100)... ^CTraceback (most recent call last): File "", line 3, in ?KeyboardInterrupt print mylist [100, ...., 100, 100, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # Many lines deleted for clarity mylist = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]for item in mylist[:]: ... if item % 2:... mylist.insert(0, 100)... print mylist [100, 100, 100, 100, 100, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 本例中的第一个 for 循环只要在原始 list 中发现奇数,它就在 list 的开始插入数值 100。当然,这是一种演示此问题的不同寻常的方式,但却非常好。一旦在三个点的 Python 提示后按 Enter 键,Python 解释器就处于无限循环的混乱中。要停止这种混乱,必须通过按 Ctrl-C(其在 Python 输出中显示为 ^C)来中断进程,然后会出现 KeyboardInterrupt 异常。如果打印出修改的 list,将看到 mylist 现在包含大量的值为 100 的元素(新元素的准确数量取决于您中断循环的速度)。 本例中的第二个 for 循环演示了如何避免此问题。使用切片运算符创建原始 list 的副本。现在 for 循环将迭代该副本,而对原始 list 进行修改。最终的结果是修改后的原始 list,它现在以五个值为 100 的新元素开始。 for 循环和序列索引 如果您用过其他编程语言,Python for 循环可能看起来有点儿古怪。您可能认为它更像 foreach 循环。基于 C 的编程语言具有 for 循环,但它的设计目的是对一系列操作执行特定次数。Python for 循环可以通过使用内置的 range 和 xrange 方法来模拟该行为。清单 6 中演示了这两种方法。 清单 6. range 和 xrange 方法 ? 12345678910 r = range(10)print r [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] type(r) xr = xrange(10)print xr xrange(10) type(xr) 本例首先演示了 range 方法,它创建一个包含一系列整数的新 list。调用 range 方法的一般形式是提供单个值,用作整数 list 的上限。零为起始值。因此,调用 range(10) 将创建包含整数 0 至 9(包含 9)的 list。range 方法接受起始索引以及步长。所以,调用 range(11,20) 将创建从 11 至 19(包含 19)的整数 list,而调用 range(12, 89, 2) 将创建从 12 至 88 的偶数 list。 由于 xrange 方法也创建整数 list(其使用相同参数),所以它与 range 方法非常相似。但是,xrange 方法仅在需要时才在 list 中创建整数。例如,在清单 6 中,尝试打印出新创建的 xrange 时除了 xrange 的名称,不会显示任何数据。当需要迭代大量整数时,xrange 方法更适用,因为它不会创建极大的 list,那样会消耗大量计算机内存。 清单 7 演示了如何在 for 循环内使用 range 方法来创建整数 1 至 10(包含 10)的乘法表。 清单 7. 创建乘法表 ? 123456789101112131415 for row in range(1, 11): ... for col in range(1, 11):... print "%3d " % (row * col),... print... 1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 18 27 36 45 54 63 72 81 90 10 20 30 40 50 60 70 80 90 100 本例使用两个 for 循环,外面的 for 循环关注乘法表中的每一行,嵌套的 for 循环关注每行内的列。每个循环都迭代包含整数 1 至 10(包含 10)的 list。最里面的 print 语句使用了一个名为 字符串格式化 的新概念来创建格式设置精美的表。字符串格式化是一种非常有用的技术,用于以格式设置精美的布局创建由不同数据类型组成的 string。现在详细信息并不重要,将来的文章中将讲述这些内容(了解 C 编程语言的 printf 方法的任何人都会很熟悉这些内容)。在本例中,字符串格式化指定将从整数创建新 string 且需要保留三个字符来存放该整数(如果该整数小于三个字符,将在左边用空格填补,从而使数据排列整齐)。第二个 print 语句用于打印新行,从而使乘法表中的下一行被打印在新的行中。 range 方法还可用于迭代容器,通过使用适当的索引访问序列中的每一项。要进行此操作,需要包含容器的允许范围索引值的整数 list,这可以通过使用 range 方法和 len 方法来轻松实现,如清单 8 所示。 清单 8. 在 for 循环内索引容器 ? 1234567891011121314 st = "Python Is A Great Programming Language!"for index in range(len(st)): ... print st[index],... P y t h o n I s A G r e a t P r o g r a m m i n g L a n g u a g e ! for item in st.split(' '): ... print item, len(item)... Python 6Is 2A 1Great 5Programming 11Language! 9 这个最后的示例演示了如何使用 len 方法作为 range 方法的参数,创建可用于单独访问 string 中每个字符的整数 list。第二个 for 循环还显示了如何将 string 分割为子字符串的 list(使用空格字符来指示子字符串的边界)。for 循环迭代子字符串 list,打印每个子字符串及其长度。

xuning715 2019-12-02 01:10:25 0 浏览量 回答数 0

回答

当我可以在60秒内在类似硬件上执行相同操作时,您的查询要花2个小时才能执行,这是一件非常错误的事情。 以下某些内容可能会有所帮助... 为您的引擎调整MySQL 检查服务器配置并进行相应优化。以下某些资源应该是有用的。 http://www.mysqlperformanceblog.com/2006/09/29/what-to-tune-in-mysql-server-after-installation/ http://www.mysqlperformanceblog.com/ http://www.highperfmysql.com/ http://forge.mysql.com/wiki/ServerVariables http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html http://www.xaprb.com/blog/2006/07/04/how-to-exploit-mysql-index-optimizations/ http://jpipes.com/presentations/perf_tuning_best_practices.pdf http://jpipes.com/presentations/index_coding_optimization.pdf http://www.jasny.net/?p=36 现在不那么明显了... 考虑使用存储过程来处理数据服务器端 为什么不处理MySQL内部的所有数据,从而不必将大量数据发送到应用程序层?以下示例使用游标在2分钟内循环和处理服务器端5000万行。我不是游标的忠实拥护者,尤其是在MySQL游标非常有限的地方,但是我猜想您会循环结果集并进行某种形式的数值分析,因此在这种情况下使用游标是合理的。 简化的myisam结果表-基于您的密钥。 drop table if exists results_1mregr_c_ew_f; create table results_1mregr_c_ew_f ( id int unsigned not null auto_increment primary key, rc tinyint unsigned not null, df int unsigned not null default 0, val double(10,4) not null default 0, ts timestamp not null default now(), key (rc, df) ) engine=myisam; 我生成了1亿行数据,其中关键字段的基数与您的示例大致相同: show indexes from results_1mregr_c_ew_f; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Index_type ===== ========== ======== ============ =========== ========= =========== ========== results_1mregr_c_ew_f 0 PRIMARY 1 id A 100000000 BTREE results_1mregr_c_ew_f 1 rc 1 rc A 2 BTREE results_1mregr_c_ew_f 1 rc 2 df A 223 BTREE 存储过程 我创建了一个简单的存储过程,该过程将获取所需的数据并对其进行处理(使用与示例相同的where条件) drop procedure if exists process_results_1mregr_c_ew_f; delimiter # create procedure process_results_1mregr_c_ew_f ( in p_rc tinyint unsigned, in p_df int unsigned ) begin declare v_count int unsigned default 0; declare v_done tinyint default 0; declare v_id int unsigned; declare v_result_cur cursor for select id from results_1mregr_c_ew_f where rc = p_rc and df > p_df; declare continue handler for not found set v_done = 1; open v_result_cur; repeat fetch v_result_cur into v_id; set v_count = v_count + 1; -- do work... until v_done end repeat; close v_result_cur; select v_count as counter; end # delimiter ; 观察到以下运行时: call process_results_1mregr_c_ew_f(0,60); runtime 1 = 03:24.999 Query OK (3 mins 25 secs) runtime 2 = 03:32.196 Query OK (3 mins 32 secs) call process_results_1mregr_c_ew_f(1,60); runtime 1 = 04:59.861 Query OK (4 mins 59 secs) runtime 2 = 04:41.814 Query OK (4 mins 41 secs) counter 23000002 (23 million rows processed in each case) 嗯,性能有些令人失望,因此进入下一个想法。 考虑使用innodb引擎(令人震惊的恐怖) 为什么是innodb?因为它具有聚簇索引!您会发现使用innodb的插入速度较慢,但​​希望读取速度会更快,因此这是值得的折衷选择。 通过聚集索引访问行的速度很快,因为行数据位于索引搜索所位于的同一页上。如果表很大,则与使用不同于索引记录的页面存储行数据的存储组织相比,聚集索引体系结构通常可以节省磁盘I / O操作。例如,MyISAM将一个文件用于数据行,将另一个文件用于索引记录。 更多信息在这里: http://dev.mysql.com/doc/refman/5.0/en/innodb-index-types.html 简化的innodb结果表 drop table if exists results_innodb; create table results_innodb ( rc tinyint unsigned not null, df int unsigned not null default 0, id int unsigned not null, -- cant auto_inc this !! val double(10,4) not null default 0, ts timestamp not null default now(), primary key (rc, df, id) -- note clustered (innodb only !) composite PK ) engine=innodb; innodb的一个问题是它不支持构成复合键一部分的auto_increment字段,因此您必须自己使用序列生成器,触发器或其他方法(可能是在填充结果表本身的应用程序中)提供递增的键值?? 同样,我生成了1亿行数据,这些键字段的基数与您的示例大致相同。如果这些数字与myisam示例不匹配,请不要担心,因为innodb估计基数,因此它们不会完全相同。(但它们-使用相同的数据集) show indexes from results_innodb; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Index_type ===== ========== ======== ============ =========== ========= =========== ========== results_innodb 0 PRIMARY 1 rc A 18 BTREE results_innodb 0 PRIMARY 2 df A 18 BTREE results_innodb 0 PRIMARY 3 id A 100000294 BTREE 存储过程 存储过程与上面的myisam示例完全相同,但是从innodb表中选择数据。 declare v_result_cur cursor for select id from results_innodb where rc = p_rc and df > p_df; 结果如下: call process_results_innodb(0,60); runtime 1 = 01:53.407 Query OK (1 mins 53 secs) runtime 2 = 01:52.088 Query OK (1 mins 52 secs) call process_results_innodb(1,60); runtime 1 = 02:01.201 Query OK (2 mins 01 secs) runtime 2 = 01:49.737 Query OK (1 mins 50 secs) counter 23000002 (23 million rows processed in each case) 比myisam引擎实施快约2-3分钟!(innodb FTW) 分而治之 在使用游标的服务器端存储过程中处理结果可能不是最佳解决方案,尤其是因为MySQL不支持诸如数组和复杂数据结构之类的东西,而这些东西在3GL语言(如C#等)或什至在其他数据库(如作为Oracle PL / SQL。 因此,这里的想法是将成批的数据返回到应用程序层(C#等),然后可以将结果添加到基于集合的数据结构中,然后在内部处理数据。 存储过程 该存储过程需要3个参数rc,df_low和df_high,这使您可以选择以下数据范围: call list_results_innodb(0,1,1); -- df 1 call list_results_innodb(0,1,10); -- df between 1 and 10 call list_results_innodb(0,60,120); -- df between 60 and 120 etc... 显然,df范围越高,您将提取的数据越多。 drop procedure if exists list_results_innodb; delimiter # create procedure list_results_innodb ( in p_rc tinyint unsigned, in p_df_low int unsigned, in p_df_high int unsigned ) begin select rc, df, id from results_innodb where rc = p_rc and df between p_df_low and p_df_high; end # delimiter ; 我还敲出了一个myisam版本,除了所使用的表外,该版本完全相同。 call list_results_1mregr_c_ew_f(0,1,1); call list_results_1mregr_c_ew_f(0,1,10); call list_results_1mregr_c_ew_f(0,60,120); 基于上面的光标示例,我希望innodb版本的性能优于myisam版本。 我开发了一个快速且肮脏的多线程C#应用程序,该应用程序将调用存储过程并将结果添加到集合中以进行后查询处理。您不必使用线程,可以按顺序完成相同的批处理查询方法,而不会造成性能损失。 每个线程(QueryThread)选择一个df数据范围,循环结果集,并将每个结果(行)添加到结果集合中。 class Program { static void Main(string[] args) { const int MAX_THREADS = 12; const int MAX_RC = 120; List<AutoResetEvent> signals = new List<AutoResetEvent>(); ResultDictionary results = new ResultDictionary(); // thread safe collection DateTime startTime = DateTime.Now; int step = (int)Math.Ceiling((double)MAX_RC / MAX_THREADS) -1; int start = 1, end = 0; for (int i = 0; i < MAX_THREADS; i++){ end = (i == MAX_THREADS - 1) ? MAX_RC : end + step; signals.Add(new AutoResetEvent(false)); QueryThread st = new QueryThread(i,signals[i],results,0,start,end); start = end + 1; } WaitHandle.WaitAll(signals.ToArray()); TimeSpan runTime = DateTime.Now - startTime; Console.WriteLine("{0} results fetched and looped in {1} secs\nPress any key", results.Count, runTime.ToString()); Console.ReadKey(); } } 运行时观察如下: Thread 04 done - 31580517 Thread 06 done - 44313475 Thread 07 done - 45776055 Thread 03 done - 46292196 Thread 00 done - 47008566 Thread 10 done - 47910554 Thread 02 done - 48194632 Thread 09 done - 48201782 Thread 05 done - 48253744 Thread 08 done - 48332639 Thread 01 done - 48496235 Thread 11 done - 50000000 50000000 results fetched and looped in 00:00:55.5731786 secs Press any key 因此,在不到60秒的时间内获取了5000万行并将其添加到集合中。 我使用myisam存储过程尝试了同样的事情,该过程花了2分钟才能完成。 50000000 results fetched and looped in 00:01:59.2144880 secs 移至innodb 在我的简化系统中,myisam表的性能不会太差,因此可能不值得迁移到innodb。如果您确实决定将结果数据复制到innodb表中,请按照以下步骤进行操作: start transaction; insert into results_innodb select <fields...> from results_1mregr_c_ew_f order by ; commit; 在将整个事物插入并包装到事务中之前,通过innodb PK对结果进行排序将加快速度。 我希望其中一些证明是有帮助的。 祝好运

保持可爱mmm 2020-05-18 11:14:35 0 浏览量 回答数 0

阿里云高校特惠,助力学生创业梦!0元体验,快速入门云计算!

学生动手场景应用,快速了解并掌握云服务器的各种新奇玩法!

问题

Swift2.0到底「新」在哪?

忆远0711 2019-12-01 21:30:17 8367 浏览量 回答数 0

回答

一、插入排序(Insertion Sort) 1. 基本思想: 每次将一个待排序的数据元素,插入到前面已经排好序的数列中的适当位置,使数列依然有序;直到待排序数据元素全部插入完为止。 2. 排序过程:  【示例】: [初始关键字] [49] 38 65 97 76 13 27 49     J=2(38) [38 49] 65 97 76 13 27 49     J=3(65) [38 49 65] 97 76 13 27 49     J=4(97) [38 49 65 97] 76 13 27 49     J=5(76) [38 49 65 76 97] 13 27 49     J=6(13) [13 38 49 65 76 97] 27 49     J=7(27) [13 27 38 49 65 76 97] 49     J=8(49) [13 27 38 49 49 65 76 97]  Procedure InsertSort(Var R : FileType); //对R[1..N]按递增序进行插入排序, R[0]是监视哨//   Begin     for I := 2 To N Do //依次插入R[2],...,R[n]//     begin       R[0] := R; J := I - 1;       While R[0] < R[J] Do //查找R的插入位置//        begin         R[J+1] := R[J]; //将大于R的元素后移//         J := J - 1        end       R[J + 1] := R[0] ; //插入R //     end   End; //InsertSort // 复制代码二、选择排序 1. 基本思想:   每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。 2. 排序过程: 【示例】: 初始关键字 [49 38 65 97 76 13 27 49] 第一趟排序后 13 [38 65 97 76 49 27 49] 第二趟排序后 13 27 [65 97 76 49 38 49] 第三趟排序后 13 27 38 [97 76 49 65 49] 第四趟排序后 13 27 38 49 [49 97 65 76] 第五趟排序后 13 27 38 49 49 [97 97 76] 第六趟排序后 13 27 38 49 49 76 [76 97] 第七趟排序后 13 27 38 49 49 76 76 [ 97] 最后排序结果 13 27 38 49 49 76 76 97  Procedure SelectSort(Var R : FileType); //对R[1..N]进行直接选择排序 //   Begin     for I := 1 To N - 1 Do //做N - 1趟选择排序//      begin       K := I;       For J := I + 1 To N Do //在当前无序区R[I..N]中选最小的元素R[K]//        begin         If R[J] < R[K] Then K := J        end;       If K <> I Then //交换R和R[K] //         begin Temp := R; R := R[K]; R[K] := Temp; end;      end   End; //SelectSort // 复制代码三、冒泡排序(BubbleSort) 1. 基本思想:   两两比较待排序数据元素的大小,发现两个数据元素的次序相反时即进行交换,直到没有反序的数据元素为止。 2. 排序过程:   设想被排序的数组R[1..N]垂直竖立,将每个数据元素看作有重量的气泡,根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R,凡扫描到违反本原则的轻气泡,就使其向上"漂浮",如此反复进行,直至最后任何两个气泡都是轻者在上,重者在下为止。 【示例】: 49 13 13 13 13 13 13 13 38 49 27 27 27 27 27 27 65 38 49 38 38 38 38 38 97 65 38 49 49 49 49 49 76 97 65 49 49 49 49 49 13 76 97 65 65 65 65 65 27 27 76 97 76 76 76 76 49 49 49 76 97 97 97 97  Procedure BubbleSort(Var R : FileType) //从下往上扫描的起泡排序// Begin   For I := 1 To N-1 Do //做N-1趟排序//    begin      NoSwap := True; //置未排序的标志//      For J := N - 1 DownTo 1 Do //从底部往上扫描//       begin        If R[J+1]< R[J] Then //交换元素//         begin          Temp := R[J+1]; R[J+1 := R[J]; R[J] := Temp;          NoSwap := False         end;       end;      If NoSwap Then Return//本趟排序中未发生交换,则终止算法//     end End; //BubbleSort// 复制代码四、快速排序(Quick Sort) 1. 基本思想:   在当前无序区R[1..H]中任取一个数据元素作为比较的"基准"(不妨记为X),用此基准将当前无序区划分为左右两个较小的无序区:R[1..I-1]和R[I+1..H],且左边的无序子区中数据元素均小于等于基准元素,右边的无序子区中数据元素均大于等于基准元素,而基准X则位于最终排序的位置上,即R[1..I-1]≤X.Key≤R[I+1..H](1≤I≤H),当R[1..I-1]和R[I+1..H]均非空时,分别对它们进行上述的划分过程,直至所有无序子区中的数据元素均已排序为止。 2. 排序过程: 【示例】: 初始关键字 [49 38 65 97 76 13 27 49] 第一次交换后 [27 38 65 97 76 13 49 49] 第二次交换后 [27 38 49 97 76 13 65 49] J向左扫描,位置不变,第三次交换后 [27 38 13 97 76 49 65 49] I向右扫描,位置不变,第四次交换后 [27 38 13 49 76 97 65 49] J向左扫描 [27 38 13 49 76 97 65 49] (一次划分过程) 初始关键字 [49 38 65 97 76 13 27 49] 一趟排序之后 [27 38 13] 49 [76 97 65 49] 二趟排序之后 [13] 27 [38] 49 [49 65]76 [97] 三趟排序之后 13 27 38 49 49 [65]76 97 最后的排序结果 13 27 38 49 49 65 76 97 各趟排序之后的状态  Procedure Parttion(Var R : FileType; L, H : Integer; Var I : Integer); //对无序区R[1,H]做划分,I给以出本次划分后已被定位的基准元素的位置 // Begin   I := 1; J := H; X := R ;//初始化,X为基准//   Repeat     While (R[J] >= X) And (I < J) Do       begin        J := J - 1 //从右向左扫描,查找第1个小于 X的元素//        If I < J Then //已找到R[J] 〈X//          begin           R := R[J]; //相当于交换R和R[J]//           I := I + 1          end;        While (R <= X) And (I < J) Do           I := I + 1 //从左向右扫描,查找第1个大于 X的元素///       end;      If I < J Then //已找到R > X //        begin         R[J] := R; //相当于交换R和R[J]//         J := J - 1        end   Until I = J;   R := X //基准X已被最终定位// End; //Parttion // 复制代码 Procedure QuickSort(Var R :FileType; S,T: Integer); //对R[S..T]快速排序// Begin   If S < T Then //当R[S..T]为空或只有一个元素是无需排序//     begin       Partion(R, S, T, I); //对R[S..T]做划分//       QuickSort(R, S, I-1);//递归处理左区间R[S,I-1]//       QuickSort(R, I+1,T);//递归处理右区间R[I+1..T] //     end; End; //QuickSort// 复制代码五、堆排序(Heap Sort) 1. 基本思想: 堆排序是一树形选择排序,在排序过程中,将R[1..N]看成是一颗完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系来选择最小的元素。 2. 堆的定义: N个元素的序列K1,K2,K3,...,Kn.称为堆,当且仅当该序列满足特性:        Ki≤K2i Ki ≤K2i+1(1≤ I≤ [N/2]) 堆实质上是满足如下性质的完全二叉树:树中任一非叶子结点的关键字均大于等于其孩子结点的关键字。例如序列10,15,56,25,30,70就是一个堆,它对应的完全二叉树如上图所示。这种堆中根结点(称为堆顶)的关键字最小,我们把它称为小根堆。反之,若完全二叉树中任一非叶子结点的关键字均大于等于其孩子的关键字,则称之为大根堆。 3. 排序过程: 堆排序正是利用小根堆(或大根堆)来选取当前无序区中关键字小(或最大)的记录实现排序的。我们不妨利用大根堆来排序。每一趟排序的基本操作是:将当前无序区调整为一个大根堆,选取关键字最大的堆顶记录,将它和无序区中的最后一个记录交换。这样,正好和直接选择排序相反,有序区是在原记录区的尾部形成并逐步向前扩大到整个记录区。 【示例】:对关键字序列42,13,91,23,24,16,05,88建堆  Procedure Sift(Var R :FileType; I, M : Integer); //在数组R[I..M]中调用R,使得以它为完全二叉树构成堆。事先已知其左、右子树(2I+1 <=M时)均是堆// Begin   X := R; J := 2*I; //若J <=M, R[J]是R的左孩子//   While J <= M Do //若当前被调整结点R有左孩子R[J]//    begin     If (J < M) And R[J].Key < R[J+1].Key Then       J := J + 1 //令J指向关键字较大的右孩子//         //J指向R的左、右孩子中关键字较大者//     If X.Key < R[J].Key Then //孩子结点关键字较大//       begin         R := R[J]; //将R[J]换到双亲位置上//         I := J ; J := 2*I //继续以R[J]为当前被调整结点往下层调整//       end;      Else       Exit//调整完毕,退出循环//    end   R := X;//将最初被调整的结点放入正确位置// End;//Sift// 复制代码 Procedure HeapSort(Var R : FileType); //对R[1..N]进行堆排序//  Begin   For I := N Div Downto 1 Do //建立初始堆//    Sift(R, I , N)   For I := N Downto 2 do //进行N-1趟排序//    begin     T := R[1]; R[1] := R; R := T;//将当前堆顶记录和堆中最后一个记录交换//     Sift(R, 1, I-1) //将R[1..I-1]重成堆//    end End; //HeapSort// 复制代码六、几种排序算法的比较和选择 1. 选取排序方法需要考虑的因素: (1) 待排序的元素数目n; (2) 元素本身信息量的大小; (3) 关键字的结构及其分布情况; (4) 语言工具的条件,辅助空间的大小等。 2. 小结: (1) 若n较小(n <= 50),则可以采用直接插入排序或直接选择排序。由于直接插入排序所需的记录移动操作较直接选择排序多,因而当记录本身信息量较大时,用直接选择排序较好。 (2) 若文件的初始状态已按关键字基本有序,则选用直接插入或冒泡排序为宜。 (3) 若n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序、堆排序或归并排序。 快速排序是目前基于比较的内部排序法中被认为是最好的方法。 (4) 在基于比较排序方法中,每次比较两个关键字的大小之后,仅仅出现两种可能的转移,因此可以用一棵二叉树来描述比较判定过程,由此可以证明:当文件的n个关键字随机分布时,任何借助于"比较"的排序算法,至少需要O(nlog2n)的时间。 这句话很重要 它告诉我们自己写的算法 是有改进到最优 当然没有必要一直追求最优 (5) 当记录本身信息量较大时,为避免耗费大量时间移动记录,可以用链表作为存储结构。 

小哇 2019-12-02 01:17:25 0 浏览量 回答数 0

问题

【精品问答】110+数据挖掘面试题集合

珍宝珠 2019-12-01 21:56:45 2713 浏览量 回答数 3

问题

【精品问答】python技术1000问(2)

问问小秘 2019-12-01 22:03:02 3129 浏览量 回答数 1
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 企业信息查询 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 2020阿里巴巴研发效能峰会 企业建站模板 云效成长地图 高端建站 阿里云双十一主会场 阿里云双十一新人会场 1024程序员加油包 阿里云双十一拼团会场 场景化解决方案 阿里云双十一直播大厅