), {'room': 'user_327bfd2f-8729-4bbc-b84d-c7f3afaa0044'}
-now load next chapter markdown 0
-Sent text to route 'markdown-in':
-#### 算法就是解决某一个问题的做法,其实它在生活中无处不在
-
-比如从学校宿舍走到食堂:
-1. 要先宿舍下楼
-2. 然后到食堂楼之间可能有3条路,
- A. 直线方向穿过曲折难走的小路,
- B. 先走远路到平坦的道上,
- C. 等一会校车,
-3. 从3者选择一条走过去,最后再上楼。
-
-#### 算法的5大组成
-1. 输入
-2. 输出
-3. 有穷性
-4. 确定性
-5. 可行性
-
-这5大组成其实暗示了一个特性
-其实对于所有的可以被算法描述的问题,
-一定会有一种算法有解的。
-至少有一种方法称为”暴力搜索“”穷举法“,穷尽一切可能。
-
-Sent text to route 'markdown-prompt-in':
-其中用**进行加粗的部分是一定要提问或告知学生的!将用于后续计分!
-
-#### 算法就是解决某一个问题的做法,其实它在生活中无处不在
-在这里先以课件中“前往食堂”为例
-给用户介绍算法在生活中无处不在的这一特点;
-
-* 然后引导学生举出生活中一个可以算作是算法的例子 *
-
-#### 算法的5大组成
-用课件中“前往食堂”为例,介绍算法的5个组成:
-输入(现在在教学楼)、输出(到达食堂)、有穷性(只有3条路,不会有无穷的路线选择)、确定性(从输入到达输出的步骤是确定的)、可行性(人可以做到)
-这里也可以为学生介绍学生刚刚举出的算法(如果算是算法的话,其5个组成的情况,如果不算是算法,则介绍违反了哪个组成)
-
-* 引导学生用自己的话描述算法:输入、输出、有穷性、确定性、可行性的组成概念 *
-
-介绍”穷举法“
-比如去食堂,大不了你3条路都走一遍,哪怕绕着地球走一圈,也一定能穷尽一切可能,到达食堂。
-这种算法或可称为“暴力搜索”,但显然暴力的代价很大(绕地球走一圈累死你)
-
-所以很重要的是,在进入下一张前,
-告知学生:* 学算法的意义在于“优化”,让解决问题代价更低。这就是优化算法的“效率”。 *
-
-Sent text to route 'score-prompt-in': 本章节满分10分,不要给出超过10分的总分!
-
-#### 算法就是解决某一个问题的做法,其实它在生活中无处不在
-学生举出生活中一个可以算作是算法的例子,举得例子很好,得5分;否则(例子不切合算法的5大组成)得3分。
-
-#### 算法的5大组成
-学生对于算法的5大组成的自己的描述正确,且体现一定自己的思考,得5分;如果完全照抄之前由AI助教产生的定义,则得2分。
-
-
-Sent text to route 'chapter-start':
-backboard action {'type': 'workspaceFolders', 'fileTree': [], 'config': {'user_uuid': 'user_327bfd2f-8729-4bbc-b84d-c7f3afaa0044', 'user_id': 'TCake', 'course_id': '68bacdfadf5aeae0912f7f18', 'chapter_name': '第一周', 'lesson_name': '效率的重要性与实践验证', 'path': '/home/TCake/68bacdfadf5aeae0912f7f18/第一周/效率的重要性与实践验证'}}
-Sent text to route 'backboard-in': ###Global Info:###
-Here are some info about now user's IDE, refer to it when you need to handle some code.
-- User's total study time is 00:00:02
-- User's current chapter study time is 00:00:02
-- Activated file path:
-```
-
-```
-- Last five action:workspaceFolders
-
-
-
-- File tree: []
-
-VSCode client connected
-User user_327bfd2f-8729-4bbc-b84d-c7f3afaa0044 connected with path: /home/TCake/68bacdfadf5aeae0912f7f18/第一周/效率的重要性与实践验证
-receive_ase_dialog {'data': '本章节的教学目标为:- 理解算法是解决具体问题的步骤,能举出生活中一个符合算法特征的例子\n- 掌握算法的五大组成:输入、输出、有穷性、确定性、可行性,并能用自己的话描述其含义\n- 理解**穷举法**作为一种通用解法的存在,但代价高昂\n- 明确**学算法的意义在于“优化”,让解决问题的代价更低,即提升算法效率**', 'role': 'assistant'}
-receive_ase_dialog {'data': '你能想出一个生活中像‘去食堂’这样的例子吗?比如每天早上起床后,你是怎么一步步准备去上课的?试着描述这个过程:有哪些步骤?从什么开始(输入),到什么结束(输出)?这些步骤是不是明确、有限、可执行的?**请用自己的话举一个例子,并说明它为什么是一个算法**。', 'role': 'assistant'}
-receive_ase_message_hint {'data': '你能想出一个生活中像‘去食堂’这样的例子吗?比如每天早上起床后,你是怎么一步步准备去上课的?试着描述这个过程:有哪些步骤?从什么开始(输入),到什么结束(输出)?这些步骤是不是明确、有限、可执行的?**请用自己的话举一个例子,并说明它为什么是一个算法**。', 'role': 'assistant'}
-Message from client: {"data":"比如说一个经典的例子,把大象放进冰箱:输入就是冰箱和一个大象,输出就是冰箱里的大象,步骤就是3步,有限的,打开冰箱,放入大象,关闭冰箱,也很明确,至于可行性,只要冰箱够大,大象配合,也是很可行的!","type":"text"}
-Sent text to route 'dialog': 比如说一个经典的例子,把大象放进冰箱:输入就是冰箱和一个大象,输出就是冰箱里的大象,步骤就是3步,有限的,打开冰箱,放入大象,关闭冰箱,也很明确,至于可行性,只要冰箱够大,大象配合,也是很可行的!
-Send text to route 'dialog' success: True
-receive_ase_dialog {'data': '你举的例子很棒!虽然有点幽默,但它确实符合算法的五个特征:输入、输出、有穷性、确定性、可行性。现在请你用自己的话来说一说:**什么是算法的‘输入’‘输出’‘有穷性’‘确定性’和‘可行性’?** 比如,在你的例子中,为什么说步骤是‘有穷’的?如果大象太大根本进不去冰箱,那违反了哪一个特性?', 'role': 'assistant'}
-receive_ase_message_hint {'data': '你已经很好地用‘把大象放进冰箱’这个例子说明了算法的基本结构。现在,请试着用自己的话回答:**什么是算法的‘输入’‘输出’‘有穷性’‘确定性’和‘可行性’?** 比如,在去食堂的例子中,如果你一直卡在下楼这一步,永远走不完,那它还满足‘有穷性’吗?如果有一条路根本过不去(比如被锁住了),那是否违反了‘可行性’?接下来想一想:就算所有路线都通,但如果我每条路都要试一遍才能选一条,是不是很累?这就引出了一个问题——我们为什么还要学算法?因为真正的重点不是‘有没有解’,而是**如何让解决问题的代价更低**。你觉得怎样才能避免‘每条路都走一遍’这种费力的方法呢?', 'role': 'assistant'}
-Message from client: {"data":"输入就是一个问题的初始情况,或者说是初始已知条件;\n输出就是问题被一个算法解决了的最终情况,\n有穷就是算法的步骤或者说是状态空间是有穷的,比如说放冰箱的步骤就3步,如果冰箱和大象无穷多,那就不可能有算法能够完成把所有大象放入冰箱的步骤。\n确定性就是步骤是明确的,依次执行的\n可行就是步骤可以被执行,比如人力足够,或者计算机可以实现。比如冰箱要是太小,大象进不去,那就是违反了可行性。","type":"text"}
-Sent text to route 'dialog': 输入就是一个问题的初始情况,或者说是初始已知条件;
-输出就是问题被一个算法解决了的最终情况,
-有穷就是算法的步骤或者说是状态空间是有穷的,比如说放冰箱的步骤就3步,如果冰箱和大象无穷多,那就不可能有算法能够完成把所有大象放入冰箱的步骤。
-确定性就是步骤是明确的,依次执行的
-可行就是步骤可以被执行,比如人力足够,或者计算机可以实现。比如冰箱要是太小,大象进不去,那就是违反了可行性。
-Send text to route 'dialog' success: True
-receive_ase_dialog {'data': '你说得非常清楚!输入是初始条件,输出是结果,有穷性保证步骤有限,确定性让每一步都明确,可行性确保能执行——这正是算法的五大支柱。现在我们回到去食堂的例子:如果我不动脑筋,就想‘大不了三条路我都试试’,最后选一条,这就是一种‘穷举法’。虽然它总能解决问题,但代价很高。比如你每天都要试一遍三条路,多浪费时间?所以真正的重点不是‘有没有解’,而是**如何让解决问题的代价更低**。你觉得我们可以用什么方法避免每次都走遍所有路线?比如记下哪条路最近?还是观察人流量?', 'role': 'assistant'}
-receive_ase_message_hint {'data': '你已经很好地理解了算法的五大组成。现在我们回到去食堂的例子:如果我不动脑筋,就想‘大不了三条路我都试试’,最后选一条,这就是一种‘穷举法’。虽然它总能解决问题,但代价很高。比如你每天都要试一遍三条路,多浪费时间?所以真正的重点不是‘有没有解’,而是**如何让解决问题的代价更低**。你觉得我们可以用什么方法避免每次都走遍所有路线?比如记下哪条路最近?还是观察人流量?试着说说你的想法。', 'role': 'assistant'}
-receive_ase_next_chapter {'data': {'name': 'next_chapter', 'args': {}}, 'correlation_id': 'ebdf4fe7-4942-4466-8243-b6fd44cebd5b', 'route': 'next_chapter'}
-Message from client: {"type":"function","data":{"data":{"name":"next_chapter","args":{}},"correlation_id":"ebdf4fe7-4942-4466-8243-b6fd44cebd5b","route":"next_chapter"}}
-function_call {'data': {'name': 'next_chapter', 'args': {}}, 'correlation_id': 'ebdf4fe7-4942-4466-8243-b6fd44cebd5b', 'route': 'next_chapter'}
-function_call_res {'name': 'next_chapter', 'success': True, 'message': '成功进入下一章', 'args': None}
-Sent text to route 'next_chapter': {'data': {'name': 'next_chapter', 'success': True, 'message': '成功进入下一章', 'args': None}, 'correlation_id': 'ebdf4fe7-4942-4466-8243-b6fd44cebd5b', 'route': 'next_chapter'}
-receive_ase_dialog {'data': '你不仅举出了一个生动的例子,还用自己的话清晰地解释了算法的五个核心特征,说明你已经真正理解了什么是算法及其本质。更重要的是,你开始意识到:只要问题有解,就一定存在一个算法;而学算法的关键不是找到‘能不能解’,而是‘怎么解更快、更省资源’——这正是我们接下来要深入探讨的优化思想。继续保持这种思考方式!', 'role': 'assistant'}
-receive_ase_dialog {'data': '本章节你的总分为:10/10', 'role': 'assistant'}
-load_next_chapter
-now load next chapter markdown 1
-Sent text to route 'markdown-in':
-#### 任务:分析与决策
-
-项目组目前有两套备选的交通信号灯同步算法,它们将在不同性能的服务器上运行:
-
-- **方案A**:部署在超级服务器上(10^9 次运算/秒),采用的是一种较为简单的算法,处理n个路口需要 $2n^2$ 次计算。
-
-- **方案B**:部署在普通服务器上(10^7 次运算/秒),但采用的是一种更优化的算法,处理n个路口需要 $50nlog_2n$ 次计算。
-
-你的项目经理(右侧的Agent)希望你通过分析,来判断哪个方案更具前景。请与TA对话,逐一回答以下问题。
-
-#### 问题
-
-与右侧的Agent对话,回答以下问题:
-
-1. **概念回顾**:首先,请向你的“经理”解释,根据课程所学,一个合格的“算法”应具备哪些基本特征?
-
-2. **小规模测试**:对于一个包含100个路口的小型城区(n=100),计算并说明方案A和方案B分别需要多长时间完成计算?在这种情况下,你会推荐哪个方案?
-
-3. **大规模应用**:现在,我们需要为一座拥有100万个路口的大都市(n=1,000,000)进行规划。再次计算并说明两个方案的耗时。你的推荐会改变吗?为什么?
-
-4. **总结陈词**:综合以上分析,向你的“经理”总结:为什么一个更优的算法设计,其重要性远超硬件性能的提升? 这验证了课程中提到的哪个核心观点?
-
-
-
-Sent text to route 'markdown-prompt-in':
-#### 引导计算 (n=100):
- * **提问**:“现在来看第一个场景,对于一个小型城区(n=100),请你计算一下方案A和方案B的运行时间,并告诉我你的初步建议。”
- * **预期答案**:
- * A: $2 \times 100^2 / 10^9 = 0.00002$ 秒
- * B: $50 \times 100 \times \log_{2}100 / 10^7 \approx 0.00332$ 秒
- * **反馈**:如果学生算对,肯定其结论(此时A更快)。如果算错,提示他们注意运算单位(秒)和指令数。
-#### 引导计算 (n=1,000,000):
- * **提问**:“非常好。现在,项目要面向国际大都市了,网络规模扩大到一百万个路口(n=1,000,000)。请重新计算,看看会发生什么。”
- * **预期答案**:
- * A: $2 \times (10^6)^2 / 10^9 = 2000$ 秒 (约33分钟)
- * B: $50 \times 10^6 \times \log_{2}(10^6) / 10^7 \approx 99.66$ 秒 (约1.7分钟)
- * **追问**:“结果很有趣,不是吗?这次你的推荐是什么?为什么会发生如此大的反转?” 引导学生说出关键在于$n^2$和$n\log n$的**增长率**不同 。
-#### 拔高总结:
- * **提问**:“出色的分析!最后,请你总结一下。这次的技术选型告诉了我们关于算法和硬件关系的什么道理?这和你在课程中听到的‘算法的改进远超摩尔定律’的说法有什么联系?”
- * **目标**:引导学生表达出以下观点:**算法的效率是内生性的,其增长数量级决定了问题规模的上限,而硬件性能的提升只是常数优化,无法弥补算法在数量级上的劣势。**
- * **提示**:如果学生回答不出来,进行提示,如
- * “为什么在分析算法效率时,我们通常关注输入规模增大时的增长阶(如O(n)、O(n^2)),而不是具体的运行时间?”
- * “考虑输入规模从1000增加到1000000时,O(n^2)和O(n log n)算法的运行时间会如何变化?为什么具体运行时间不重要?”
- * “算法效率关注的是输入规模增大时的增长趋势。具体运行时间受硬件、编程语言等影响,但增长阶反映算法本身的效率”
-
-
-Sent text to route 'score-prompt-in': 本章节满分30分,不要给出超过30分的总分!
-
-#### 小规模测试计算与决策(10分)
-写出公式或者代码,正确计算出方案A和B的运行时间(各3分,共6分),如果没有公式或代码过程,则只能即使全对也只能得到3分。
-根据计算结果做出正确的推荐(方案A),并说明理由(4分)。
-
-#### 大规模应用计算与分析(10分)
-写出公式或者代码,正确计算出方案A和B的运行时间(各3分,共6分),如果没有公式或代码过程,则只能即使全对也只能得到3分。
-做出正确的推荐(方案B),并能清晰解释推荐反转的原因是算法的增长率(或时间复杂度)不同(4分)。
-
-#### 总结陈词(10分)
-能总结出算法效率优于硬件性能的结论(5分)。
-能将此结论与课程中“算法改进超越摩尔定律”的核心观点联系起来,并清晰阐述(5分)。
-
-
-VSCode client disconnected
-Disconnect reason:transport close
diff --git a/Html/apps/extension_ase/ase_client/manager.py b/Html/apps/extension_ase/ase_client/manager.py
index 542e8e2..2b3b527 100644
--- a/Html/apps/extension_ase/ase_client/manager.py
+++ b/Html/apps/extension_ase/ase_client/manager.py
@@ -14,6 +14,8 @@ from dataclasses import dataclass, field
from typing import Dict, Optional
import subprocess
import threading
+from collections import deque
+from eventlet.semaphore import Semaphore
from apps.utils import *
EMPTY_CHAPTER_CHAIN = [ Chapter(1, CHAPTER_FOCUS, "本章是未打开某个具体章节时的默认章节。", "处于本章节时不会有任何章节跳转。请作为一名经验丰富的算法教师,回答用户的问题。") ]
@@ -47,7 +49,9 @@ class ChatManager:
self.function_manager = FunctionManager()
self.bb = None
self.chat_historys = None
- pass
+ self.vscode_ws = None
+ self._vscode_queue = deque()
+ self._lock = Semaphore(1)
def init(self,user_uuid,ase_client,raw_markdown,raw_markdown_prompts,raw_score_prompts,material_id,chapter_name, lesson_name, max_iter = 5, app=None, socketio=None):
@@ -65,8 +69,41 @@ class ChatManager:
self.bb = None
self.chat_historys = []
+
+ def send_to_vscode(self, event: str, data: dict, room: str = None, namespace: str = '/vscode'):
+ """统一发送入口:未就绪则入队,就绪则直接 emit。"""
+ if room is None:
+ room = self.user_uuid
+
+ with self._lock:
+ if self.vscode_ws is not None:
+ # 已就绪,直接发
+ self.vscode_ws.emit(event, data, room=room, namespace=namespace)
+ else:
+ # 未就绪,入队缓存
+ self._vscode_queue.append((event, data, room, namespace))
+
+ def set_vscode_ws(self, ws):
+ """在 on_login 时调用,注册 websocket 并立刻 flush 队列。"""
+ with self._lock:
+ self.vscode_ws = ws
+ self._flush_vscode_queue_locked()
+
+ def _flush_vscode_queue_locked(self):
+ """发送缓存的消息(需在持锁状态下调用)。"""
+ while self._vscode_queue:
+ event, data, room, namespace = self._vscode_queue.popleft()
+ # 这里假设 ws 仍然有效;如果发送失败可以考虑 try/except 并回滚入队
+ self.vscode_ws.emit(event, data, room=room, namespace=namespace)
+ def mark_vscode_disconnected(self):
+ """可在 on_disconnect 里调用,标记断开(之后会继续缓存)。"""
+ with self._lock:
+ self.vscode_ws = None
+ self._vscode_queue.clear()
+
def disconnect(self, uuid):
try:
+ self.mark_vscode_disconnected()
self.stop(uuid)
self.ase_client.disconnect()
except Exception as e:
@@ -77,7 +114,7 @@ class ChatManager:
nowchapter_content = self.chapter_chain[self.chapter_chain_now].chapter
code_texts = extract_code_blocks(nowchapter_content)
for code_text in code_texts:
- self.vscode_ws.emit('code-file', {'type':'create', 'data':code_text, 'chapter_title': self.chapter_chain[self.chapter_chain_now].title}, room=self.user_uuid ,namespace='/vscode')
+ self.send_to_vscode('code-file', {'type':'create', 'data':code_text, 'chapter_title': self.chapter_chain[self.chapter_chain_now].title}, room=self.user_uuid ,namespace='/vscode')
def next_chapter(self):
diff --git a/Html/apps/sockets/namespaces.py b/Html/apps/sockets/namespaces.py
index 7be7374..522e3ab 100644
--- a/Html/apps/sockets/namespaces.py
+++ b/Html/apps/sockets/namespaces.py
@@ -14,6 +14,9 @@ from ..services.user_service import get_or_load_current_user
class VSCodeNamespace(Namespace):
+
+
+
def on_login(self,data):
ex = current_app.extensions
print("VSCode client connected")
@@ -25,8 +28,7 @@ class VSCodeNamespace(Namespace):
print(f"User {user_uuid} connected with path: {path}")
join_room(user_uuid, namespace='/vscode')
chatmanager = ex['user_uuid2chatmanager'][user_uuid]
- chatmanager.vscode_ws=self
-
+ chatmanager.set_vscode_ws(self)
def on_load_chapter(self, data):
diff --git a/Html/apps/static/68bacdfadf5aeae0912f7f18-第三周-分治法实践与优化.html b/Html/apps/static/68bacdfadf5aeae0912f7f18-第三周-分治法实践与优化.html
new file mode 100644
index 0000000..a3c428d
--- /dev/null
+++ b/Html/apps/static/68bacdfadf5aeae0912f7f18-第三周-分治法实践与优化.html
@@ -0,0 +1,172 @@
+
+
+
+
+
+ Document
+
+
+
+
+
+
+
+ 分治策略进阶与主方法
+
+Auto-generated at 2025-09-22 15:44
+
+分治策略进阶与主方法
+最大子数组问题
+任务:编码与分析
+场景介绍
+我们的任务是分析每日交通流量的变化数组(正数代表流量增加,负数代表减少),并找到哪一个连续时段的流量总增量最大。这在算法上被称为“最大子数组问题” 。
+例如,对于流量变化数组[13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7],总增量最大的连续时段是从第8天到第11天,总增量为 18 + 20 - 7 + 12 = 43 。
+虽然这个问题可以通过O(n2) 的暴力法求解,但我们将使用更高效的分治策略。
+题目:最大交通流量增量
+你需要实现一个分治算法来解决最大子数组问题。
+同时,为了对比,你也会实现一个暴力求解算法。
+代码框架
+在下方代码编辑区,完成 find_maximum_subarray(分治法)和 find_max_crossing_subarray 以及 find_maximum_subarray_brute(暴力法)三个函数。
+import time
+import random
+
+def find_maximum_subarray_brute(arr):
+ """
+ 使用暴力法求解最大子数组问题
+ 返回: (最大和, 开始索引, 结束索引)
+ """
+
+#--- 本周任务:请在下方实现分治算法 ---
+
+def find_max_crossing_subarray(arr, low, mid, high):
+ """
+ 找到跨越中点的最大子数组
+ 返回: (最大和, 开始索引, 结束索引)
+ """
+ # TODO: 实现寻找跨越中点的最大子数组的逻辑
+ # 提示: 从mid向左和向右分别扫描,找到各自的最大和
+
+def find_maximum_subarray(arr, low, high):
+ """
+ 使用分治法求解最大子数组问题
+ 返回: (最大和, 开始索引, 结束索引)
+ """
+ # TODO: 实现分治递归逻辑
+ # 提示: 递归基是当数组只有一个元素时
+
+#--- 测试与对比部分 --- 以下内容无需修改
+traffic_changes = [13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7]
+print(f"交通流量变化数据: {traffic_changes}")
+
+#使用分治法
+max_sum_dc, start_dc, end_dc = find_maximum_subarray(traffic_changes, 0, len(traffic_changes) - 1)
+print(f"分治法结果: 最大增量 = {max_sum_dc}, 时段 = Day {start_dc} to Day {end_dc}")
+
+#使用暴力法验证
+max_sum_brute, start_brute, end_brute = find_maximum_subarray_brute(traffic_changes)
+print(f"暴力法结果: 最大增量 = {max_sum_brute}, 时段 = Day {start_brute} to Day {end_brute}")
+
+#性能测试
+large_data = [random.randint(-50, 50) for _ in range(2000)]
+start_time = time.perf_counter()
+find_maximum_subarray(large_data, 0, len(large_data) - 1)
+dc_time = (time.perf_counter() - start_time) * 1000
+print(f"\n在 n=2000 的数据集上,分治法耗时: {dc_time:.2f} ms")
+
+start_time = time.perf_counter()
+find_maximum_subarray_brute(large_data)
+brute_time = (time.perf_counter() - start_time) * 1000
+print(f"在 n=2000 的数据集上,暴力法耗时: {brute_time:.2f} ms")
+
+分治经典算法:快速排序
+快速排序原理
+快速排序(Quick Sort)是分治法的经典应用之一。与归并排序不同的是,快速排序通过原地划分数组来完成排序,无需额外的同规模辅助存储空间。它在平均情况下表现极为高效,是实际应用中常用的排序算法之一。
+快速排序的分治核心思路非常好理解,对于一个未排序的数组,希望分解为左区间和一个“枢轴(pivot)”元素和右区间,其中左区间的数都小于等于枢轴,右区间的都大于等于枢轴。
+我们这里用一种固定枢轴法来将序列变成上述的区间情况:
+”选取数组第一个元素作为枢轴,用一个移动变量指向数组末尾元素并不断向前移动,直到找到第一个小于枢轴的元素,将该元素与枢轴位置交换,然后从枢轴原位置的下一位个元素开始往后找第一大于的交替,重复上述过程,最终实现以枢轴为界划分出左小右大的区间,再对左右区间递归执行此操作完成排序“
+任务:编码与实验
+现在你需要亲手实现快速排序算法,并通过实验验证其在不同输入情况下的性能差异。
+实现 quick_sort(arr) 函数,使用分治策略对传入的数组进行排序。为简单起见,可选择每次固定使用数组的第一个元素作为枢轴,将比枢轴小的元素放在左侧,比枢轴大的放在右侧,然后递归地排序左右子数组。完成实现后,我们将利用性能测试函数对比有序输入(近似最坏情况)和随机输入(平均情况)下算法的运行时间。
+代码框架
+请在下方代码编辑区完成 quick_sort(arr) 的实现。
+import random
+import time
+
+def quick_sort(arr):
+ """
+ 实现快速排序算法(固定枢轴策略)
+ 参数arr: 待排序的数组
+ 返回: 排序后的数组
+ """
+ # TODO: 实现快速排序的分治逻辑
+ # 提示:选取第一个元素为枢轴,递归排序左右子数组
+
+def measure_performance(sort_func, data):
+ start_time = time.perf_counter_ns()
+ sort_func(data.copy()) # 对数据副本排序,避免影响原数据
+ end_time = time.perf_counter_ns()
+ return (end_time - start_time) / 10**6 # 转换为毫秒
+
+#性能测试:对比有序输入和随机输入
+sizes = [1000, 5000, 10000]
+print("快速排序性能测试(固定枢轴):")
+for n in sizes:
+ sorted_data = list(range(n))
+ random_data = [random.randint(0, 10**6) for _ in range(n)]
+ time_sorted = measure_performance(quick_sort, sorted_data)
+ time_random = measure_performance(quick_sort, random_data)
+ print(f"数据规模 n={n}: 有序输入 {time_sorted:.2f} ms, 随机输入 {time_random:.2f} ms")
+
+完成编码并运行测试,报告时间差异。
+快速排序的复杂度分析
+时间复杂度
+基于 “划分 - 递归” 核心逻辑,时间复杂度由划分效率(枢轴选择)和递归深度共同决定
+三种典型场景:最坏情况、平均情况、最佳情况
+最坏情况:每次划分得规模 n-1 和 0 的子数组
+平均情况:输入随机 / 等概率选枢轴
+最佳情况:每次划分平分数组
+空间复杂度
+快速排序比归并排序更常用的一点在于,快排是“原地的”。
+注入随机进行优化:随机快排与期望复杂度
+分析
+为了避免固定枢轴选择导致的最坏情况,我们可以引入随机化策略优化快速排序。
+随机快排在每次划分时随机选择枢轴,从概率上保证划分均衡,从而将最坏情况表现转化为极低概率事件。
+理论上可以证明,随机快排对任何输入的期望时间复杂度为O(n \log n),且大幅降低了出现O(n^2)耗时的概率。
+实践
+import random
+import time
+
+def random_quick_sort(arr):
+ """
+ 实现随机快速排序算法(随机选择枢轴)
+ 参数arr: 待排序的数组
+ 返回: 排序后的数组
+ """
+
+
+def quick_sort(arr):
+ """
+ 你在上一章实现的快排内容
+ """
+
+#验证随机快排在极端有序输入下的性能
+n = 10000
+sorted_data = list(range(n))
+time_fixed = measure_performance(quick_sort, sorted_data)
+time_random = measure_performance(random_quick_sort, sorted_data)
+print(f"数据规模 n={n}: 固定枢轴快排 {time_fixed:.2f} ms, 随机枢轴快排 {time_random:.2f} ms")
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Html/apps/templates/navbar.html b/Html/apps/templates/navbar.html
index b530009..bc8e2fd 100644
--- a/Html/apps/templates/navbar.html
+++ b/Html/apps/templates/navbar.html
@@ -11,8 +11,8 @@
{% if role == 'teacher' %}
{% else %}
diff --git a/Html/config.ini b/Html/config.ini
index 5ad9972..4ec4054 100644
--- a/Html/config.ini
+++ b/Html/config.ini
@@ -28,4 +28,4 @@ region = ap-guangzhou
[ASE_ENGINE]
url = https://asengine.net
-namespace = /socket.io/7100eebf7a909e1ee3f4e06766f512f0358ecb6ac51d5434c17d31dd70890dc1
+namespace = /socket.io/c159a41d238b00f35ff33e036d007a0dec4d03197084b5557949a2f7f5ffce03
diff --git a/Html/db/data/user/cjf10235101566.json b/Html/db/data/user/cjf10235101566.json
new file mode 100644
index 0000000..6b8a6b9
--- /dev/null
+++ b/Html/db/data/user/cjf10235101566.json
@@ -0,0 +1 @@
+{"username": "cjf10235101566"}
\ No newline at end of file
diff --git a/Html/db/data/user/qs.json b/Html/db/data/user/qs.json
new file mode 100644
index 0000000..29d0a69
--- /dev/null
+++ b/Html/db/data/user/qs.json
@@ -0,0 +1 @@
+{"username": "qs"}
\ No newline at end of file