quick sort analyse

本文详细介绍了快速排序算法的工作原理,包括其核心的分区操作,并通过代码示例解释了具体实现方式。此外,还分析了该算法在不同情况下的性能表现。

快速排序及其分析

前言

快速排序的平均情况下是O(nlogn),但是一般都比其他运行时间为O(nlogn)的算法都要快,因为它隐藏的常数因子比较小,但是在最坏情况之下,快速排序的运行时间是O(n2)。

快速排序过程

快速排序采用的思想是分治思想,就像合并排序算法的思想一样,合并排序算法是从数组的中间开始分治,直到分为N个分组,最后分别合并N个分组的解。如下图,有原始数组A = {1, 3, 4, 5, 7, 2, 6, 8, 0}

image

快速排序是找出一个元素(理论上可以随便找一个)作为基准(pivot),然后对数组进行分区操作,使基准左边元素的值都不大于基准值,基准右边的元素值都不小于基准值,如此作为基准的元素调整到排序后的正确位置。递归快速排序,将其他n-1个元素也调整到排序后的正确位置。最后每个元素都是在排序后的正确位置,排序完成。所以快速排序算法的核心算法是分区操作,即如何调整基准的位置以及调整返回基准的最终位置以便分治递归。

基准

基准的挑选会影响到算法的性能,一般情况将序列的第一个元素作为基准。

分区算法

设两个指针left和right,一个从左往右扫描,一个从右往左扫描;对于左指针,如果左指针所指的元素的值小于或者等于基准值,那么指针往右移一位,如果大于基准值,则和基准值交换;同理,对于右指针,如果右指针所指的元素的值大于或者等于基准值,那么指针往左移一位,如果小于基准值,则和基准值交换。代码如下:

   1: int Partition(int A[], int p, int r)
   2: {
   3:     int privot = A[p];  //基准
   4:     // 设两个指针
   5:     int left = p;   //从左往右扫描
   6:     int right = r;  //从右往左扫描
   7:     
   8:     while (right > left)
   9:     {
  10:         while (right > left && A[right] >= privot)  
  11:         {
  12:             right--;
  13:         }
  14:  
  15:         A[left] = A[right];
  16:  
  17:         while (right > left && A[left] <= privot)
  18:         {
  19:             left++;
  20:         }
  21:  
  22:         A[right] = A[left];
  23:     }
  24:  
  25:     A[left] = privot;
  26:     return left;
  27: }
 

   1: void QuickSort(int A[], int p, int r)
   2: {
   3:     int pivot;
   4:  
   5:     if (r > p)
   6:     {
   7:         pivot = Partition(A, p, r);
   8:         QuickSort(A, p, pivot-1);
   9:         QuickSort(A, pivot+1, r);
  10:     }
  11: }

 

性能分析

最好情况

每次基准的最终位置都是在数组中间位置,从而使规模为N的问题分为2个规模为N/2的问题,即T(n) = 2T(n/2) + Θ(n),用递归树分析或者主定理得到时间T(n) = O(nlogn)。

最坏情况

每次基准的最终位置都是第一个位置,从而规模为N的问题分为一个规模为N-1的问题,即T(n) = T(n-1) + Θ(n),用递归树分析可得运行时间T(n) = O(n2)。

平均情况

假设规模为N的问题分为一个规模为9/10N的问题和规模为1/10N的问题,即T(n) = T(9n/10) + T(n/10) + Θ(n),用递归树分析可得T(n) = O(nlogn),而且比分区9:1要更平均(也就是情况更好)的概率为80%,所以在绝大部分情况下快速排序算法的运行时间为O(nlogn)。

import pandas as pd import jieba import jieba.analyse import re class KeywordExtractor: def __init__(self, custom_dict_path=None, stopwords_path=None): """ 关键词提取器 参数: - custom_dict_path: 自定义词典路径 - stopwords_path: 停用词路径 """ # 加载自定义词典以提高分词准确性 自定义字典采用懒猫-苏程祥的结果 if custom_dict_path: jieba.load_userdict(custom_dict_path) # 加载停用词 self.stopwords = set() self._load_default_stopwords() # 加载用户自定义停用词 停用词为哈工大停用词 if stopwords_path: self._load_custom_stopwords(stopwords_path) # 正则表达式过滤数字 过滤商品信息中的规格 self.number_pattern = re.compile(r'\d+') def _load_default_stopwords(self): """加载默认停用词""" default_stopwords = [ '的', '了', '在', '是', '我', '有', '和', '就', '不', '人', '都', '一', '一个', '上', '也', '很', '到', '说', '要', '去', '你', '会', '着', '没有', '看', '好', '自己', '这', '那', '这个', '那个', '啊', '吧', '把', '被', '【', '】', '/', '个', '份', 'ml', 'kg', 'g', 'l', '组合', '系列', '加大', '款' ] self.stopwords.update(default_stopwords) def _load_custom_stopwords(self, stopwords_path): """从文件加载自定义停用词""" try: with open(stopwords_path, 'r', encoding='utf-8') as f: custom_stopwords = [line.strip() for line in f if line.strip()] self.stopwords.update(custom_stopwords) print(f"成功从 {stopwords_path} 加载 {len(custom_stopwords)} 个停用词") except Exception as e: print(f"加载自定义停用词出错: {e}") print("使用默认停用词集") def is_valid_keyword(self, word): """判断关键词是否有效""" # 过滤纯数字 if self.number_pattern.fullmatch(word): return False # 过滤单个字符 if len(word) <= 1: return False # 过滤停用词 if word in self.stopwords: return False return True def hybrid_keywords(self, text, topK=5, tfidf_weight=0.5): """ 融合TF-IDF和TextRank算法提取关键词 参数: - text: 输入文本 - topK: 返回关键词数量 - tfidf_weight: TF-IDF算法权重(0.0~1.0),TextRank权重为1-tfidf_weight """ # 使用TF-IDF提取关键词及权重 *2 扩大算法提取的关键词数量 避免因关键词过少结果为空 tfidf_words = jieba.analyse.extract_tags( text, topK=topK*2, withWeight=True, allowPOS=('n', 'nr', 'ns', 'nt', 'nz', 'v', 'a') ) # 使用TextRank提取关键词及权重 同上 textrank_words = jieba.analyse.textrank( text, topK=topK*2, withWeight=True, allowPOS=('n', 'nr', 'ns', 'nt', 'nz', 'v', 'a') ) # 转换为字典便于处理 便于对两个算法的结果进行加权计算 tfidf_dict = {word: weight for word, weight in tfidf_words if self.is_valid_keyword(word)} textrank_dict = {word: weight for word, weight in textrank_words if self.is_valid_keyword(word)} # 融合得分(线性加权) hybrid_scores = {} for word in set(tfidf_dict.keys()).union(set(textrank_dict.keys())): tfidf_score = tfidf_dict.get(word, 0) textrank_score = textrank_dict.get(word, 0) hybrid_scores[word] = tfidf_score * tfidf_weight + textrank_score * (1 - tfidf_weight) # 按得分排序并返回前topK个关键词 return sorted(hybrid_scores.items(), key=lambda x: x[1], reverse=True)[:topK] def process_excel(self, input_path, output_path, sheet_name='Sheet1', text_column='菜单名', topK=5, tfidf_weight=0.5): """ 处理Excel文件并提取关键词 参数: - input_path: 输入Excel路径 - output_path: 输出Excel路径 - sheet_name: 工作表名称 - text_column: 文本列名称 - topK: 每个文本提取的关键词数量 - tfidf_weight: TF-IDF权重 """ # 读取Excel文件 try: excel_file = pd.ExcelFile(input_path) df = excel_file.parse(sheet_name) except Exception as e: print(f"读取Excel文件出错: {e}") return False # 对文本列提取融合关键词 df['hybrid_keywords'] = df[text_column].apply(lambda x: [word for word, score in self.hybrid_keywords(x, topK=topK, tfidf_weight=tfidf_weight)]) # 保存结果 try: df.to_excel(output_path, index=False) print(f"关键词提取完成,结果已保存至: {output_path}") return True except Exception as e: print(f"保存Excel文件出错: {e}") return False def main(): """主函数""" # 创建关键词提取器实例,指定自定义停用词路径 extractor = KeywordExtractor( custom_dict_path='E:/Data/VScode/custom_dict.txt', # 自定义词典路径 stopwords_path='E:/Data/VScode/hit_stopwords.txt' # 自定义停用词路径 ) # 处理Excel文件 result = extractor.process_excel( input_path='E:/Data/VScode/test_1.xlsx', # 输入文件路径 output_path='E:/Data/VScode/keywords6.xlsx', # 输出文件路径 sheet_name='Sheet1', # 工作表名 text_column='菜单名', # 文本列名 topK=3, # 提取关键词数量 tfidf_weight=0.8 # > 0.5 偏向TF-IDF算法的权重 < 0.5 偏向于TextRank算法的权重 ) if result: print("关键词提取成功!") else: print("关键词提取失败,请检查文件路径和格式。") if __name__ == "__main__": main() 对上面提供的代码进行分析 并给出如何优化代码的建议
05-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值