diff --git a/codes/python/chapter_sorting/bubble_sort.py b/codes/python/chapter_sorting/bubble_sort.py index 521dd8a..61f11f5 100644 --- a/codes/python/chapter_sorting/bubble_sort.py +++ b/codes/python/chapter_sorting/bubble_sort.py @@ -1,37 +1,47 @@ ''' File: bubble_sort.py Created Time: 2022-11-25 -Author: Krahets (krahets@163.com) +Author: timi (xisunyy@163.com) ''' -import sys, os.path as osp -sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * +import sys +import os.path as osp +sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) -"冒泡排序" +"""冒泡排序""" def bubble_sort(nums): - n=len(nums) + n = len(nums) # 外循环:待排序元素数量为 n-1, n-2, ..., 1 - for i in range(n-1,-1,-1): + for i in range(n-1, -1, -1): # 内循环:冒泡操作 for j in range(i): - if nums[j]>nums[j+1]: - nums[j],nums[j+1]=nums[j+1],nums[j] -"冒泡排序(标志优化)" -def bubbleSortWithFlag(nums): - n=len(nums) + # 交换 nums[j] 与 nums[j + 1] + if nums[j] > nums[j+1]: + nums[j], nums[j+1] = nums[j+1], nums[j] + + +"""冒泡排序(标志优化)""" +def bubble_sort_with_flag(nums): + n = len(nums) # 外循环:待排序元素数量为 n-1, n-2, ..., 1 - for i in range(n-1,-1,-1): - flag=False #初始化标志位 + for i in range(n-1, -1, -1): + flag = False # 初始化标志位 # 内循环:冒泡操作 for j in range(i): - if nums[j]>nums[j+1]: - nums[j],nums[j+1]=nums[j+1],nums[j] - flag=True #记录交换元素 - if not flag:break -if __name__=='__main__': - nums=[4,1,3,1,5,2] + # 交换 nums[j] 与 nums[j + 1] + if nums[j] > nums[j+1]: + nums[j], nums[j+1] = nums[j+1], nums[j] + flag = True # 记录交换元素 + if not flag: + break # 此轮冒泡未交换任何元素,直接跳出 + + +if __name__ == '__main__': + nums = [4, 1, 3, 1, 5, 2] bubble_sort(nums) - print("冒泡排序后数组 nums = " ,nums) - bubbleSortWithFlag(nums) - print("冒泡排序后数组 nums = " ,nums) \ No newline at end of file + print("排序后数组 nums = ", nums) + + nums1 = [4, 1, 3, 1, 5, 2] + bubble_sort_with_flag(nums1) + print("排序后数组 nums = ", nums1) diff --git a/codes/python/chapter_sorting/insertion_sort.py b/codes/python/chapter_sorting/insertion_sort.py index 8640abc..a3b2b23 100644 --- a/codes/python/chapter_sorting/insertion_sort.py +++ b/codes/python/chapter_sorting/insertion_sort.py @@ -1,26 +1,28 @@ ''' File: insertion_sort.py Created Time: 2022-11-25 -Author: Krahets (krahets@163.com) +Author: timi (xisunyy@163.com) ''' -import sys, os.path as osp -sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * +import sys +import os.path as osp +sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) -"直接插入排序" -def insertionSort(nums): - #外循环:base = nums[1], nums[2], ..., nums[n-1] - for i in range(1,len(nums)): - base=nums[i] - j=i-1 - #内循环:将 base 插入到左边的正确位置 - while j>=0 and nums[j]>base: - nums[j+1]=nums[j] #1. 将 nums[j] 向右移动一位 - j-=1 - nums[j+1]=base #2. 将 base 赋值到正确位置 +"""插入排序""" +def insertion_sort(nums): + # 外循环:base = nums[1], nums[2], ..., nums[n-1] + for i in range(1, len(nums)): + base = nums[i] + j = i-1 + # 内循环:将 base 插入到左边的正确位置 + while j >= 0 and nums[j] > base: + nums[j+1] = nums[j] # 1. 将 nums[j] 向右移动一位 + j -= 1 + nums[j+1] = base # 2. 将 base 赋值到正确位置 -if __name__=='__main__': - nums=[4,1,3,1,5,2] - insertionSort(nums) - print("排序后数组 nums = " ,nums) \ No newline at end of file + +if __name__ == '__main__': + nums = [4, 1, 3, 1, 5, 2] + insertion_sort(nums) + print("排序后数组 nums = ", nums) diff --git a/codes/python/chapter_sorting/merge_sort.py b/codes/python/chapter_sorting/merge_sort.py index 04c7130..f3212ef 100644 --- a/codes/python/chapter_sorting/merge_sort.py +++ b/codes/python/chapter_sorting/merge_sort.py @@ -1,48 +1,60 @@ ''' File: merge_sort.py Created Time: 2022-11-25 -Author: Krahets (krahets@163.com) +Author: timi (xisunyy@163.com) ''' -import sys, os.path as osp -sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) +import copy from include import * +import sys +import os.path as osp +sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) """ -另一种 思路实现归并排序 +合并左子数组和右子数组 +左子数组区间 [left, mid] +右子数组区间 [mid + 1, right] """ -def merge_sort(nums,l,r): - if l>=r:return - mid=l+r>>1 #划分中点 - #进行归并 - merge_sort(nums,l,mid) - merge_sort(nums,mid+1,r) - - k,i,j=0,l,mid+1 #借助辅助数组 完成排序 - while i<=mid and j<=r: - if nums[i]<=nums[j]: #这一步保证了 稳定排序 - help_ls[k]=nums[i] - i+=1 +def merge(nums, left, mid, right): + # 初始化辅助数组 借助 copy模块 + tmp = copy.deepcopy(nums[left:right+1]) + # 左子数组的起始索引和结束索引 + leftStart, leftEnd = left-left, mid - left + # 右子数组的起始索引和结束索引 + rightStart, rightEnd = mid + 1 - left, right - left + # i, j 分别指向左子数组、右子数组的首元素 + i, j = leftStart, rightStart + # 通过覆盖原数组 nums 来合并左子数组和右子数组 + for k in range(left, right+1): + # 若 “左子数组已全部合并完”,则选取右子数组元素,并且 j++ + if i > leftEnd: + nums[k] = tmp[j] + j += 1 + # 否则,若 “右子数组已全部合并完” 或 “左子数组元素 < 右子数组元素”,则选取左子数组元素,并且 i++ + elif j > rightEnd or tmp[i] <= tmp[j]: + nums[k] = tmp[i] + i += 1 + # 否则,若 “左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++ else: - help_ls[k]=nums[j] - j+=1 - k+=1 - - while i<=mid: #对于左边区域 - help_ls[k]=nums[i] - k,i=k+1,i+1 - while j<=r: #对于右边区域 - help_ls[k]=nums[j] - k,j=k+1,j+1 + nums[k] = tmp[j] + j += 1 - i,j=l,0 - while i<=r: - nums[i]=help_ls[j] - i,j=i+1,j+1 -if __name__=='__main__': - nums=[4,1,3,1,5,2] - n=len(nums) - help_ls=[0 for _ in range(n)] - merge_sort(nums,0,n-1) - print("归并排序完成后 nums = ",nums) \ No newline at end of file + +"""归并排序""" +def merge_sort(nums, left, right): + # 终止条件 + if left >= right: + return # 当子数组长度为 1 时终止递归 + # 划分阶段 + mid = left + right >> 1 # 计算中点 + merge_sort(nums, left, mid) # 递归左子数组 + merge_sort(nums, mid + 1, right) # 递归右子数组 + # 合并阶段 + merge(nums, left, mid, right) + + +if __name__ == '__main__': + nums = [4, 1, 3, 1, 5, 2] + merge_sort(nums, 0, len(nums)-1) + print("归并排序完成后 nums = ", nums) diff --git a/codes/python/chapter_sorting/quick_sort.py b/codes/python/chapter_sorting/quick_sort.py index f66ff5f..50236e4 100644 --- a/codes/python/chapter_sorting/quick_sort.py +++ b/codes/python/chapter_sorting/quick_sort.py @@ -1,31 +1,132 @@ ''' File: quick_sort.py Created Time: 2022-11-25 -Author: Krahets (krahets@163.com) +Author: timi (xisunyy@163.com) ''' -import sys, os.path as osp -sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * +import sys +import os.path as osp +sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) -"另一种思维 实现快速排序" -def quick_sort(nums,l,r): - if l>=r: - return - i,j,x=l-1,r+1,nums[l+r>>1] - while i=x:break - while True: - j-=1 - if nums[j]<=x:break - if i= nums[left]: + j -= 1 # 从右向左找首个小于基准数的元素 + while i < j and nums[i] <= nums[left]: + i += 1 # 从左向右找首个大于基准数的元素 + # 元素交换 + nums[i], nums[j] = nums[j], nums[i] + # 将基准数交换至两子数组的分界线 + nums[i], nums[left] = nums[left], nums[i] + return i # 返回基准数的索引 + + """快速排序""" + def quick_sort(self, nums, left, right): + # 子数组长度为 1 时终止递归 + if left >= right: + return + # 哨兵划分 + pivot = self.partition(nums, left, right) + # 递归左子数组、右子数组 + self.quick_sort(nums, left, pivot-1) + self.quick_sort(nums, pivot+1, right) + + +"""快速排序类(中位基准数优化)""" +class quick_sort_median(): + + # 选取三个元素的中位数 + def median_three(self, nums, left, mid, right): + # 使用了异或操作来简化代码 + # 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 + if (nums[left] > nums[mid]) ^ (nums[left] > nums[right]): + return left + elif (nums[mid] < nums[left]) ^ (nums[mid] > nums[right]): + return mid + return right + + """哨兵划分(三数取中值)""" + def partition(self, nums, left, right): + # 以 nums[left] 作为基准数 + med = self.median_three(nums, left, (left+right)//2, right) + # 将中位数交换至数组最左端 + nums[left], nums[med] = nums[med], nums[left] + # 以 nums[left] 作为基准数 + i, j = left, right + while i < j: + while i < j and nums[j] >= nums[left]: + j -= 1 # 从右向左找首个小于基准数的元素 + while i < j and nums[i] <= nums[left]: + i += 1 # 从左向右找首个大于基准数的元素 + # 元素交换 + nums[i], nums[j] = nums[j], nums[i] + # 将基准数交换至两子数组的分界线 + nums[i], nums[left] = nums[left], nums[i] + return i # 返回基准数的索引 + + """快速排序""" + def quick_sort(self, nums, left, right): + # 子数组长度为 1 时终止递归 + if left >= right:return + # 哨兵划分 + pivot = self.partition(nums, left, right) + # 递归左子数组、右子数组 + self.quick_sort(nums, left, pivot-1) + self.quick_sort(nums, pivot+1, right) + + +"""快速排序类(尾递归优化)""" +class quick_sort_tail_call(): + + """哨兵划分""" + def partition(self, nums, left, right): + # 以 nums[left] 作为基准数 + i, j = left, right + while i < j: + while i < j and nums[j] >= nums[left]: + j -= 1 # 从右向左找首个小于基准数的元素 + while i < j and nums[i] <= nums[left]: + i += 1 # 从左向右找首个大于基准数的元素 + # 元素交换 + nums[i], nums[j] = nums[j], nums[i] + # 将基准数交换至两子数组的分界线 + nums[i], nums[left] = nums[left], nums[i] + return i # 返回基准数的索引 + + """快速排序(尾递归优化)""" + def quick_sort(self, nums, left, right): + # 子数组长度为 1 时终止 + while left < right: + # 哨兵划分操作 + pivot = self.partition(nums, left, right) + # 对两个子数组中较短的那个执行快排 + if pivot-left < right-pivot: + self.quick_sort(nums, left, pivot-1) # 递归排序左子数组 + left = pivot+1 # 剩余待排序区间为 [pivot + 1, right] + else: + self.quick_sort(nums, pivot+1, right) # 递归排序右子数组 + right = pivot-1 # 剩余待排序区间为 [left, pivot - 1] + +if __name__ == '__main__': + # 快速排序 + nums = [4, 1, 3, 1, 5, 2] + quick_sort().quick_sort(nums, 0, len(nums)-1) + print("快速排序完成后 nums = ", nums) + + # 快速排序(中位基准数优化) + nums1 = [4, 1, 3, 1, 5, 2] + quick_sort_median().quick_sort(nums1, 0, len(nums1)-1) + print("快速排序(中位基准数优化)完成后 nums = ", nums) + + # 快速排序(尾递归优化) + nums2 = [4, 1, 3, 1, 5, 2] + quick_sort_tail_call().quick_sort(nums, 0, len(nums2)-1) + print("快速排序(尾递归优化)完成后 nums = ", nums)