首页 > temp > 简明python教程 >
-
排序
1.冒泡排序
思路:
一个列表有n个数字就循环n-1次,循环一次就会将最大数字放到了最后(相邻数字进行比较,大的就放在右边,每次对比后数字大的都放右边,这样一行数字每两个相邻的数字都进行一次比较下来后,最大的数字就放到了最右边,
也就是本列表的-1索引位置,这样做n-1次,就把整个列表排序做好了,n是整个列表长度,因为最后一次就剩最左边一个元素了就不用再比较了.)
#冒泡排序完整代码 #上述代码操作需要作用n-1才可以将整个序列变成有序的 def sort(alist): length = len(alist) for j in range(0,length-1): #有几个数字就循环几次,确保每一个数字都移动到对应的位置 #让两两元素进行比较(n-1) for i in range(0,length-1-j):#每相邻两个数字都做比较,大的就放到最后,依次下去, 直到对应的位置,这里减j是要省去每次循环都对比7个元素 (循环一次就有一个数字已经找到对应的位置,接下来再循环时相邻数字作比较就少一个就好了), 第一次对比7个数字,第二次减去一个上依次循环已经定位好的第7个数字,就只对6个数字最相邻数字比较 if alist[i] > alist[i+1]:#第一个元素大于第二个元素 #两个元素交换位置 alist[i],alist[i+1] = alist[i+1],alist[i] return alist alist = [3,8,5,2,0,7,6] print(sort(alist))
2.选择排序
思路:
先循环换找到最大的数字(并且获取到对应的索引),再将最后一个数字和最大数字交换位置,这样省去了每相邻两个数字做比较大小.
选择排序改进了冒泡排序,每次遍历列表只做一次交换。为了做到这一点,一个选择排序在他遍历时寻找最大的值,并在完成遍历后,将其放置在正确的位置。
如图:
#选择排序完整代码 def sort(alist): for j in range(0,len(alist)-1): max_index = 0 #表示的是最大值的下标,一开始我们假设列表中的第0个元素为最大值 for i in range(len(alist)-1-j):#控制比较的次数 if alist[max_index] < alist[i+1]: max_index = i+1 #将最大值和最后一个元素交换位置,就可以将最大值放置到序列的最后位置 alist[max_index],alist[len(alist)-1-j] = alist[len(alist)-1-j],alist[max_index] return alist alist = [3,8,5,2,0,7,6] print(sort(alist))
3.插入排序
分析:
-
-
有序部分:默认为序列中的第一个元素
-
无序部分:默认为序列中除了第一个元素剩下的元素
-
关键:将无序部分的元素逐一插入到有序部分中即可
-
-
定义一个变量叫做i
-
i表示的是有序部分元素的个数
-
i还可以表示无序部分中第一个元素的下标
-
-
原始序列:[3,8,5,2,6,10,1]
-
[3, 8,5,2,6,10,1] ==》i=1
-
思路:
插入排序的主要思想是每次取一个列表元素与列表中已经排序好的列表段进行比较,然后插入从而得到新的排序好的列表段,最终获得排序好的列表。比如,待排序列表为[49,38,65,97,76,13,27,49],则比较的步骤和得到的新列表如下:(带有背景颜色的列表段是已经排序好的,红色背景标记的是执行插入并且进行过交换的元素)
#插入排序完整代码 def sort(alist): #i的取值范围是1-(n-1) for i in range(1,len(alist)):#假设左起第一个数字已经是排序好了的,然后就要拿左起第二个数字和这个数字作比较, 比第一个大,位置就不动,如果比第一个数字小就要放到第一个数字的左边,然后继续循环 (注意这里的range是顾头不顾尾,会比len(alist)少1) #i = 2 #有序部分有两个元素 while i > 0: if alist[i] < alist[i-1]: alist[i],alist[i-1] = alist[i-1],alist[i]#[6,5,8, 2,6,10,1] i -= 1 #i是不可以为负数,减一之后就是刚才的数字向左移了一位,这里你继续和他左边的数字作对比, 对比大了就不动了,小了就继续移动有可能会直到移动到最左边. else: break return alist alist = [3,8,5,2,0,7,6] print(sort(alist))
4.快速排序
分析:
-
-
基数:
-
默认情况下序列中第一个元素作为基数
-
原始序列中比基数大的值放置到基数右侧,比基数小的值放置到基数左侧
-
-
将列表中第一个元素设定为基准数字,赋值给mid变量,然后将整个列表中比基准小的数值放在基准的左侧,比基准大的数字放在基准右侧。然后将基准数字左右两侧的序列在根据此方法进行排放。
-
定义两个指针,low指向最左侧,high指向最右侧
-
然后对最右侧指针进行向左移动,移动法则是,如果指针指向的数值比基准小,则将指针指向的数字移动到基准数字原始的位置,否则继续移动指针。
-
如果最右侧指针指向的数值移动到基准位置时,开始移动最左侧指针,将其向右移动,如果该指针指向的数值大于基准则将该数值移动到最右侧指针指向的位置,然后停止移动。
-
如果左右侧指针重复则,将基准放入左右指针重复的位置,则基准左侧为比其小的数值,右侧为比其大的数值。
思路:
-
一排数字(这些数字最好不要随便拿因为有时候会出bug),快排是所有排序算法里面速度最快的.
-
一排数字,先取第一个数字作为基数,这样第一个位置就空了,然后定义两个变量low和high,low暂时定义为0,high暂时为列表的长度(其实low和high就是索引)
-
先从右边起,将high对应的数字与基数比大小,如果high比基数大,那么high对应的数字的位置就不动,将high重新赋值(向左挪一个数字),如果high比基数小,那么就将这个数字赋值给low,而这里的high对应的数字就算是空了,再往下,就从low这边开始算,刚赋值给了low一个数字(从右边第二个数字移动到了最左端第一个数字),现在再将low向右移动一个数字,将最左端第二个数字赋值给low,再把low和基数对比,如果low小于基数,就继续将low向左移动,如果low大于基数,就将low对应的数字移动到刚才high对应的数字的位置上去,移动之后,再从high向左推算,后面依次继续.
-
直到low等于了high,这俩索引最终就指向了基数,基数左边都比基数小,右边都比基数大,但是左边一半(可能左右数字个数不一样多)和右边一半还没排序,左边一半继续用刚才的方法,左端low定为0,右端high定为基数左边的第一个数字的索引(就是刚才low和high),右边一半也像刚才的方法,左边的low数字定位为基数右边第一个数字的索引,high就用列表总长度,和最初的一样,再继续下去迭代.直到出现low>high,迭代才停止.
#加入递归后完整的快速排序代码 def sort(alist,left,right): #low&hight表示的序列的起始位置的下标 low = left high = right #结束递归的条件 #这里有点难理解,只要记住到了极点出现low小于high就是递归结束的时候,不加他就会无限循环 if low > high: return mid = alist[low] #基数 while low < high: #将原始序列中比基数小的值放置在基数的左侧,比基数大的值放置在基数的右侧 #注意:一开始的时候先将high向左偏移 #向左偏移 while low < high: if alist[high] < mid: #high小于基数 alist[low] = alist[high] break else:#基数如果小于了high,将high向左偏移 high -= 1 #high想左偏移了以为 #low向右偏移 while low <high: if alist[low] < mid:#如果low小于mid则让low想右偏移 low += 1#让low向右偏移一位 else: alist[high] = alist[low] break if low == high:#low和high重复,将基数赋值到low或者high的位置, alist[low] = mid #alist[high] = mid,每循环一次(将mid值左半部分和右半部分已经区分开了,low索引左边的比mid小,low索引右边的比mid大,注意此时low和high相等,这时候就要把low索引对应的值写成mid最早的值,即是中间值) #指定操作作用到基数左侧的子序列中 sort(alist,left,low-1) #指定操作作用到基数右侧的子序列中 sort(alist,high+1,right) return alist alist = [66,13,51,76,81,26,57,69,23] print(sort(alist,0,len(alist)-1))
5.希尔排序
思路:
希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本,该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量(gap)”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率比直接插入排序有较大提高。下面借用一下网上找的图:
#希尔排序:插入排序是一种特殊的希尔排序 def sort(alist): gap = len(alist) // 2 while gap >= 1: #将增量设置成gap for i in range(gap,len(alist)): while i > 0 : if alist[i] < alist[i-gap]: alist[i],alist[i-gap] = alist[i-gap],alist[i] i -= gap else: break gap //= 2 return alist alist = [4,3,6,1,9,2] print(sort(alist))
6.归并排序
-
归并排序采用分而治之的原理:
- 将一个序列从中间位置分成两个序列;
- 在将这两个子序列按照第一步继续二分下去;
- 直到所有子序列的长度都为1,也就是不可以再二分截止。这时候再两两合并成一个有序序列即可。
如何合并?
下图中的倒数第三行表示为第一次合并后的数据。其中一组数据为 4 8 , 5 7。该两组数据合并方式为:每一小组数据中指定一个指针,指针指向每小组数据的第一个元素,通过指针的偏移指定数据进行有序排列。排列情况如下:
1. p1指向4,p2指向5,p1和p2指向的元素4和5进行比较,较小的数据归并到一个新的列表中。经过比较p1指向的4会被添加到新的列表中,则p1向后偏移一位,指向了8,p2不变。
2.p1和p2指向的元素8,5继续比较,则p2指向的5较小,添加到新列表中,p2向后偏移一位,指向了7。
3.p1和p2指向的元素8,7继续比较,7添加到新列表中,p2偏移指向NULL,比较结束。
4.最后剩下的指针指向的数据(包含该指针指向数据后面所有的数据)直接添加到新列表中即可。
借用一下网上找的图:
def merge_sort(alist): n = len(alist) #结束递归的条件 if n <= 1: return alist #中间索引 mid = n//2 left_li = merge_sort(alist[:mid]) right_li = merge_sort(alist[mid:]) #指向左右表中第一个元素的指针 left_pointer,right_pointer = 0,0 #合并数据对应的列表:该表中存储的为排序后的数据 result = [] while left_pointer < len(left_li) and right_pointer < len(right_li): #比较最小集合中的元素,将最小元素添加到result列表中 if left_li[left_pointer] < right_li[right_pointer]: result.append(left_li[left_pointer]) left_pointer += 1 else: result.append(right_li[right_pointer]) right_pointer += 1 #当左右表的某一个表的指针偏移到末尾的时候,比较大小结束,将另一张表中的数据(有序)添加到result中 result += left_li[left_pointer:] result += right_li[right_pointer:] return result alist = [3,8,5,7,6] print(merge_sort(alist))