一、实验目的
1、掌握寻找第k小的数算法;
2、上机实现该算法。
二、理解算法
三、函数接口设计
四、遇到的问题
在写程序时,被这个问题困扰了很久
经过演算发现,在有些函数里,没有考虑到特殊的情况,像在递归最后,总数不满5个,没办法分成5个一组,而剩下的都是比较不匀称的怎么处理。
像这里,按照书上的算法,分组小于mm的那部分,下标为[3,5)的都是小于M*(mid)的,但是有一些细节需要处理,如果最后只剩下[2,3,4,5]等一些特殊情况但又是在程序进行中一定会出现的情况,应该怎么处理。
问题2:当个数小于5时怎么划分
问题3:递归嵌套后如何返回
五、运行时间分析
当k=10000时,超出了python中递归次数的限制,采用下面的代码去修改递归次数,
sys.setrecursionlimit(10000000)
当k=1000000,StackOverflow,堆溢出了,由于这是一个递归程序,每一次递归都需要开辟新的内存空间,所以消耗很大。采用如下解决办法:
threading.stack_size(200000000)
thread=threading.Thread(target=select_kth_smallest,args=(arr,10))
thread.start()
我将函数时间画成图表,可以明显看到增长趋势:
六、实验结果截图
随机产生1000个数,输入要寻找的第k小
import math
import random
import datetime
import sys
import threading
def partition(arr, low, high):
i = (low - 1) # 最小元素索引
pivot = arr[high]
for j in range(low, high):
# 当前元素小于或等于 pivot
if arr[j] >= pivot:
i = i + 1
arr[i], arr[j] = arr[j], arr[i]
arr[i + 1], arr[high] = arr[high], arr[i + 1]
return (i + 1)
# 快速排序函数
def quickSort_FindMid(arr, low, high):
if low < high:
pi = partition(arr, low, high)
quickSort_FindMid(arr, low, pi - 1)
quickSort_FindMid(arr, pi + 1, high)
def quickSort(arr, low, high):
if low < high:
i = (low - 1) # 最小元素索引
pivot = arr[high][0]
for j in range(low, high):
# 当前元素小于或等于 pivot
if arr[j][0] <= pivot:
i = i + 1
arr[i], arr[j] = arr[j], arr[i]
arr[i + 1], arr[high] = arr[high], arr[i + 1]
pi = (i + 1)
quickSort_FindMid(arr, low, pi - 1)
quickSort_FindMid(arr, pi + 1, high)
def generate_arr(Num):
Arr = []
for i in range(0,Num):
x = random.randint(0, 20000)
Arr.append(x)
return Arr
def part5Sort(midArr,arr):
arrAfterSort = []
if len(midArr)>1:
for i in range(0,len(midArr)):
if len(arr) - (midArr[i][1]+2)>0:
left = midArr[i][1] - 2
right = midArr[i][1] + 2
arrAfterSort.append(arr[left:right+1])
#把不能整除5的部分再添加到最后
t = len(arr)%5
if t!=0:
right = len(arr)
left = right - t
arrAfterSort.append(arr[left:right])
print("part5Sort:")
print(arrAfterSort)
return arrAfterSort
def devide_to_S(arrAfterSort,mm):
#mm是第几个分组
#mid是所指的数
# S1是比mm小的
# S2是比mm大的
S1 = []
S2 = []
#如果最后只剩一组
if len(arrAfterSort) == 1:
mid = arrAfterSort[0][len(arrAfterSort[0]) // 2]
mid_index = len(arrAfterSort[0]) // 2
for j in range(0, len(arrAfterSort[0])):
if j!=mid_index:
if (arrAfterSort[0][j] >= mid):
S2.append(arrAfterSort[0][j])
else:
S1.append(arrAfterSort[0][j])
print(S1, S2, mid)
return (S1, S2,mid)
else:
mid = arrAfterSort[mm][2]
#如果mm前面有一组
if mm != 0:
for i in range(0,mm):
for j in range(0,2):
if(arrAfterSort[i][j]>mid):
S2.append(arrAfterSort[i][j])
else:
S1.append(arrAfterSort[i][j])
for j in range(2,5):
S1.append(arrAfterSort[i][j])
S1.append(arrAfterSort[mm][3])
S1.append(arrAfterSort[mm][4])
# 如果mm后面有组是5个一分的
if mm+1 < len(arrAfterSort)-1:
#最后一组可能不规则,不满5个,最后特殊处理
for i in range(mm+1,len(arrAfterSort)-1):
for j in range(3, 5):
if arrAfterSort[i][j] > mid:
S2.append(arrAfterSort[i][j])
else:
S1.append(arrAfterSort[i][j])
for j in range(0, 3):
S2.append(arrAfterSort[i][j])
S2.append(arrAfterSort[mm][0])
S2.append(arrAfterSort[mm][1])
#最后处理不规则组
k = len(arrAfterSort)-1
t = len(arrAfterSort[k])
for j in range(0,t):
if (arrAfterSort[k][j] > mid):
S2.append(arrAfterSort[k][j])
else:
S1.append(arrAfterSort[k][j])
print(S1,S2,mid)
return (S1,S2,mid)
def select_kth_smallest(arr, k):
midArr = []
arrAfterSort = []
S1 = []
S2 = []
left = 0
while left + 4 < len(arr):
quickSort_FindMid(arr, left, left + 4)
mid = left+2
midArr.append([arr[mid],mid])
left += 5
if len(arr)%5 != 0:
quickSort_FindMid(arr,left,len(arr)-1)
index = (int)((left+len(arr)-1)//2)
midArr.append([arr[index], index])
quickSort(midArr,0,len(midArr)-1)
#quickSort(midArr,0,len(midArr)-1)
midArr.sort()
print("midArr")
print(midArr)
print(arr)
arrAfterSort = part5Sort(midArr,arr)
mm = (len(midArr)-1)//2
S = devide_to_S(arrAfterSort,mm)
print(S)
S1 = S[0]
S2 = S[1]
midd = S[2]
print("k=%d"%k)
if k==(len(S1)+1):
return midd
elif k>len(S1):
return select_kth_smallest(S2, k-len(S1)-1)
else:
return select_kth_smallest(S1, k)
if __name__ == '__main__':
starttime = datetime.datetime.now()
n = input("Enter your input number: ")
n = int(n)
arr = []
arr = generate_arr(1000)
print(arr)
x = select_kth_smallest(arr,n)
arr.sort()
print(arr)
endtime = datetime.datetime.now()
print("Time used:", endtime - starttime)
print("the %d answer:%d"%(n,x))