最近学习数据结构算法,学习了简书上一篇博客python的八大排序算法,想着试着通过不同语言去实现一下各种排序算法,由于语法不一样,实现起来也有很大差异(感觉js和python语法风格上非常近似),相比之下,python真是简洁便利和通俗易懂啊
冒泡排序(Bubble Sort)是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端
步骤
def bubble_sort(list):
length = len(list)
# 第一级遍历
for index in range(length):
# 第二级遍历
for j in range(1, length - index):
if list[j - 1] > list[j]:
# 交换两者数据,这里没用temp是因为python 特性元组。
list[j - 1], list[j] = list[j], list[j - 1]
return list # 这里语句其实可以省略,传入的list已经发生改变
a = [2,5,3,47,46,19,15,26,36,4,50,48,44,27,38]
print(bubble_sort(a))
function bubble(list){
var len = list.length;
for (let i = 0; i<len; i++){
for(let j = 1; j<len - i; j++){
if (list[j-1] > list[j]){
var temp = list[j-1];
list[j-1] = list[j];
list[j] = temp;
}
}
}
return list; // 这里甚至可以省略返回值,因为数组对象在函数中是引用传递
}
$arr = [2,5,3,47,46,19,15,26,36,4,50,48,44,27,38];
function bubble($lst){
for ($i = 0;$i<count($lst);$i++){
for ($j = 1;$j<count($lst)-$i;$j++){
if ($lst[$j-1]>$lst[$j]){
$temp = $lst[$j-1];
$lst[$j-1] = $lst[$j];
$lst[$j] = $temp;
}
}
}
return $lst;
}
print_r(bubble($arr));
function [lst_out] = bubble(lst_in)
for ii = 1:length(lst_in) % matlab数组的索引从1开始
for jj = 2:length(lst_in)-ii
if lst(jj-1)>lst(jj)
temp = lst(jj-1);
lst(jj-1) = lst(jj);
lst(jj) = temp;
end
end
end
lst_out = lst_in;
return
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理大致是将后面的元素最小元素一个个取出然后按顺序放置
步骤
def selection_sort(list):
n=len(list)
for i in range (0,n):
min = i
for j in range(i+1,n):
if list[j]<list[min]:
min=j
list[min],list[i]=list[i],list[min]
return list
function select(lst){
let len = lst.length;
for (let i = 0; i< len; i++){
let min = i;
for (let j = i+1;j< len; j++){
if (lst[min]>lst[j]){
min = j;
}
}
let temp = lst[i];
lst[i] = lst[min];
lst[min] = temp;
}
return lst;
}
$arr = [1,2,5,7,9,6,8,4,3];
for($i = 0,$len = count($arr);$i<$len-1;$i++){
for ($j = $i+1,$len = count($arr);$j<$len;$j++){
// $min = $arr[$i];
$min = $i;
if ($arr[$min]>$arr[$j]){
/* $temp = $arr[$i];
$arr[$i] = $arr[$j];
$arr[$j] = $temp; */ // 这种在元素比较时,交换了多次
$min = $j;
}
}
if ($min != $i){
$temp = $arr[$min];
$arr[$min] = $arr[$i];
$arr[$i] = $temp; // 这种可以直接提取索引,只进行一次交换
}
}
print_r($arr);
function [lst_out] = selection(lst_in)
len = length(lst_in);
for ii = 1:len
min = ii;
for jj = (ii+1):len
if(lst_in(min)>lst(jj))
min = jj;
end
end
temp = lst_in(ii);
lst_in(ii) = lst_in(min);
lst_in(min) = temp;
end
return
插入排序(Insertion Sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入
步骤
def insert_sort(list):
n = len(list)
for i in range(1, n):
# 后一个元素和前一个元素比较
# 如果比前一个小
if list[i] < list[i - 1]:
# 将这个数取出
temp = list[i]
# 保存下标
index = i
# 从后往前依次比较每个元素
for j in range(i - 1, -1, -1):
# 和比取出元素大的元素交换
if list[j] > temp:
list[j + 1] = list[j]
index = j
else:
break
# 插入元素
list[index] = temp
return list
a = [2,5,3,47,46,19,15,26,36,4,50,48,44,27,38]
print(insert_sort(a))
function insert_sort(arr){
let len = arr.length;
for (let i = 1; i<len; i++){
let flag = i;
let compare = arr[i];
for (let j = i - 1; j>0; j--){
if (arr[j]>compare){
flag = j;
arr[j+1] = arr[j];
}
}
arr[flag] = compare;
}
return arr;
}
// 测试
var arr = [2,5,3,47,46,19,15,26,36,4,50,48,44,27,38]
console.log(insert_sort(arr))
function insert_sort($arr){
$len = count($arr);
for($i = 1; $i < $len; $i++){
$flag = $i;
$compare = $arr[$i];
for ($j = $i-1;$j>0;$j--){
if ($compare<$arr[$j]){
$flag = $j;
$arr[$j+1] = $arr[$j];
}
}
$arr[$flag] = $compare;
}
return $arr;
}
// 测试
$arr = [2,5,3,47,46,19,15,26,36,4,50,48,44,27,38];
print_r(insert_sort($arr));
function [lst_out] = insert_sort(lst_in)
len = length(lst_in);
for ii = 2:len
flag = ii;
compare = lst_in(ii);
for jj = ii-1:-1:1
if compare
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本(带步长)。希尔排序是非稳定排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率
但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。
步骤
每次以一定步长(就是跳过等距的数)进行排序,直至步长为1.
def shell_sort(list):
n = len(list)
# 初始步长
gap = n // 2
while gap > 0:
for i in range(gap, n):
# 每个步长进行插入排序
temp = list[i]
j = i
# 插入排序
while j >= gap and list[j - gap] > temp:
list[j] = list[j - gap]
j -= gap
list[j] = temp
# 得到新的步长
gap = gap // 2
return list
function shell_sort(list){
let n = list.length;
// 初始步长
let gap = Math.floor(n / 2);
while(gap>0){
for (let i = gap; i < n; i++){
let temp = list[i];
let j = i;
while (j>=gap && list[j-gap]>temp){
list[j] = list[j-gap];
j-=gap;
}
list[j] = temp;
}
gap = Math.floor(gap / 2);
}
return list;
}
function shell_sort($arr){
$n = count($arr);
$gap = floor($n / 2);
while ($gap > 0){
for ($i = $gap;$i < $n; $i++){
$temp = $arr[$i];
$j = $i;
while (($j>=$gap) && ($temp < $arr[$j - $gap])){
$arr[$j] = $arr[$j - $gap];
$j -= $gap;
}
$arr[$j] = $temp;
}
$gap = floor($gap / 2);
}
return $arr;
}
// 测试
$arr = [2,5,3,47,46,19,15,26,36,4,50,48,44,27,38];
print_r(shell_sort($arr));
function [lst_out] = shell_sort(lst_in)
n = length(lst_in);
gap = floor(n/2);
while gap > 0
for ii = gap:n
temp = lst_in(ii);
jj = ii;
while (jj>gap) && (temp < lst_in(jj-gap))
lst_in(jj) = lst_in(jj-gap);
jj = jj - gap;
end
lst_in(jj) = temp;
end
gap = floor(gap/2);
end
lst_out = lst_in;
return
归并操作(归并算法),指的是将两个已经排序的序列合并成一个序列的操作。归并排序算法依赖归并操作。
步骤
# 方式一:迭代法实现两个有序序列合并
def merge_sort(list1, list2):
length_list1 = len(list1)
length_list2 = len(list2)
list3 = []
j = 0
for i in range(length_list1):
while j<length_list2 and list2[j] < list1[i]:
list3.append(list2[j])
j = j+1
list3.append(list1[i])
if j<(length_list2-1): # 最后剩下的元素直接追加进入列表尾
for k in range(j, length_list2):
list3.append(list2[k])
return list3
list1 = [1 3 5 6 9 10]
list2 = [ 2 4 6 7 8 12 15]
print(merge_sort(list1, list2))
# 方式二:分治法实现单个无序序列转为有序序列
def merge_sort2(list):
# 认为长度不大于1的数列是有序的
if len(list) <= 1:
return list
# 二分列表
middle = len(list) // 2
left = merge_sort2(list[:middle])
right = merge_sort2(list[middle:])
# 最后一次合并
return merge(left, right)
# 合并
def merge(left, right):
l,r=0,0
result=[]
while l<len(left) and r<len(right):
if left[l] <right[r]:
result.append(left[l])
l+=1
else:
result.append(right[r])
r +=1
result += left[l:]
result += right[r:]
return result
if __name__ == "__main__":
a = [2,5,3,47,46,19,15,26,36,4,50,48,44,27,38]
print(merge_sort2(a))
function merge_sort(arr1, arr2){
let len1 = arr1.length;
let len2 = arr2.length;
let arr3 = [];
let j = 0;
for (let i = 0; i<len1; i++ ){
while (j<len2 && arr2[j]<arr1[i]){
arr3.push(arr2[j]);
j+=1
}
arr3.push(arr1[i])
}
if (j<len2-1){
for (let k = j;k<len2;k++){
arr3.push(arr2[k]);
}
}
return arr3;
}
// 测试
arr1 = [1, 3, 5, 10]
arr2 = [2, 4, 6, 8, 9, 11, 12, 13, 14]
console.log(merge_sort(arr1, arr2))
function merge_sort($arr1, $arr2){
$len1 = count($arr1);
$len2 = count($arr2);
$arr3 = [];
$j = 0;
for ($i = 0; $i<$len1;$i++){
while ($j<$len2 && $arr2[$j] < $arr1[$i]){
array_push($arr3,$arr2[$j]);
$j+=1;
}
array_push($arr3,$arr1[$i]);
}
if ($j < ($len2-1)){
for ($k = $j; $k < $len2; $k++){
array_push($arr3, $arr2[$k]);
}
}
return $arr3;
}
$arr1 = [1,3,5,10];
$arr2 = [2,4,6,8,9,11,13,14];
echo(''
);
print_r(merge_sort($arr1, $arr2));
function [lst_out] = merge_sort(lst1, lst2)
len1 = length(lst1);
len2 = length(lst2);
lst3 = [];
jj = 1;
for ii=1:len1
while jjlst2(jj)
lst3(length(lst3)+1) = lst2(jj);
jj = jj+1;
end
lst3(length(lst3)+1) = lst1(ii);
end
if jj
快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists
步骤
# 普通版本
def quick_sort(list):
less = []
pivotList = []
more = []
# 递归出口
if len(list) <= 1:
return list
else:
# 将第一个值作为基准
pivot = list[0]
for i in list:
# 将比基准小的值放到less数列
if i<pivot:
less.append(i)
elif i>pivot:
more.append(i)
else:
pivotList.append(i)
# 递归再排序
less = quick_sort(less)
more = quick_sort(more)
return less+pivotList+more
if __name__ == "__main__":
a = [2,5,3,47,46,19,15,26,36,4,50,48,44,27,38]
print(quick_sort(a))
# 优化版本
def qsort(arr):
if len(arr)<=1:
return arr
else:
pivot = arr[0]
less = [x for x in arr[1:] if x < pivot]
greater = [y for y in arr[1:] if x >= pivot]
return qsort(less) + [pivot] + qsort(greater)
# 语法糖
qs = lambda xs:((len(xs) <=1 and [xs]) or [qs([x for x in xs[1:] if x < xs[0]])+ [xs[0]] + qs([x for x in xs[1:] if x > xs[0]])])[0]
/*
function qsort(arr){
if (arr.length<=1)
return arr;
else{
var pivot = arr[0]; // 这里不能用let定义变量,会将变量限制在结构中,下一次函数调用访问不到
var less = arr.filter((ele)=>{return ele{return ele>=arr[0]});
}
return qsort(less).concat([pivot]).concat(qsort(greater)) // 报错,递归深度问题
return [...qsort(less),pivot,...qsort(greater)] // 报错,递归深度问题
}
*/
var quickSort = function(arr) {
if (arr.length <= 1) { return arr; }
var pivotIndex = Math.floor(arr.length / 2);
var pivot = arr.splice(pivotIndex, 1)[0];
var left = [];
var right = [];
for (var i = 0; i < arr.length; i++){
if (arr[i] < pivot) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
return quickSort(left).concat([pivot], quickSort(right));
};
function quick_sort($arr){
$len = count($arr);
if ($len <= 1){
return $arr;
}
$left = $right = [];
for ($i=1;$i<$len;$i++){
// 第一个元素为比较元素
// 小的元素放在left中,大的元素放在right中
if ($arr[$i]<$arr[0]){
$left[] = $arr[$i];
}
else{
$right[] = $arr[$i];
}
}
return array_merge(quick_sort($left),(array)$arr[0],quick_sort($right)); // 强制转换$arr[0]为数组元素进行连接
}
function [lst_out] = quick_sort(lst_in)
len = length(lst_in);
if len<= 1
lst_out = lst_out
else
left = [];
right = [];
for ii = 2:len
if lst_in(ii) < lst_in(1)
left(length(left)+1) = lst_in(ii);
else
right(length(right)+1) = lst_in(ii);
end
end
lst_out = cat(2, quick_sort(left), lst_in(1), quick_sort(right));
end
return
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点
步骤
def heap_sort(list):
# 创建最大堆
for start in range((len(list)-2) // 2, -1, -1):
sift_down(list,start,len(list)-1)
# 堆排序
for end in range(len(list) - 1, 0, -1):
list[0], list[end] = list[end], list[0] # 一次取出最大放入列表末尾,然后重新调整最大堆(end依次-1)
sift_down(list, 0, end-1)
return list
# 最大堆调整
def sift_down(lst, start, end):
root = start # 设置初始节点
while True:
child = 2*root + 1 # 左儿子索引,右儿子索引为child+1
if child>end:
break
if child+1 <= end and lst[child] < lst[child+1]:
child += 1 # 选取节点中的最大者
if lst[root] < lst[child]:
lst[root], lst[child] = lst[child], lst[root]
root = child # 继续判断下一节点
else:
break
function heap_sort(list){
// 创建最大堆
for (let i = Math.floor((list.length-2)/2); i>=0;i--){
sift_down(list, i, list.length - 1);
}
// 最大堆调整
for (let j = list.length - 1; j>0; j--){
[list[0], list[j]] = [list[j], list[0]]; // ES6 结构赋值
sift_down(list, 0, j-1);
}
return list;
}
// 调整最大堆
function sift_down(list, start, end){
var root = start;
var child;
while(true){
child = 2*root + 1;
if (child>end)
break;
if (child + 1 <= end && list[child] < list[child+1])
child += 1;
if (list[root]<list[child]){
[list[root],list[child]] = [list[child],list[root]]; // ES6 结构赋值
root = child;
}
else
break;
}
}
function heap_sort($arr){
// 创建最大堆
for ($i = floor((count($arr) - 2)/2); $i>=0; $i--){
sift_down($arr, $i, count($arr) -1);
}
// 堆排序
for ($j = count($arr)-1; $j >0; $j--){
// print_r($arr);
[$arr[0],$arr[$j]] = [$arr[$j], $arr[0]]; // 结构赋值
// $temp = $arr[0];
// $arr[0] = $arr[$j];
// $arr[$j] = $temp;
sift_down($arr, 0, $j-1);
}
return $arr;
}
// 调整堆函数
// 使用引用传递将数组传入
function sift_down(&$arr, $start, $end){
$root = $start;
while (true) {
$child = 2 * $root + 1;
if ($child > $end)
break;
if ($child + 1 <= $end && $arr[$child] < $arr[$child + 1]){
$child += 1;
}
if ($arr[$root] < $arr[$child]){
[$arr[$root], $arr[$child]] = [$arr[$child], $arr[$root]];
// $temp = $arr[$root];
// $arr[$root] = $arr[$child];
// $arr[$child] = $temp;
$root = $child;
}
else
break;
}
}
$a = [2,5,3,47,46,19,15,26,36,4,50,48,44,27,38];
echo ''
;
print_r(heap_sort($a));
// 上述代码实际运行后为错误输出(还是原数组),查找逻辑错误为sift_down应该传入&$arr;
// 还没有理解为啥需要使用引用传递,数组应该默认是引用传递啊(深拷贝和浅拷贝?)
function lst_in = heap_sort(lst_in)
len = length(lst_in);
for ii = floor(len/2):-1:1
lst_in = sift_down(lst_in, ii, len);
end
for jj = len:-1:1
temp = lst_in(1);
lst_in(1) = lst_in(jj);
lst_in(jj) = temp;
lst_in = sift_down(lst_in, 1, jj-1);
end
return
%% 调整堆函数
function lst_in = sift_down(lst_in, starts, ends)
root = starts;
while 1
child = 2*root;
if child >ends
break
end
if child + 1 <= ends && lst_in(child)
当输入的元素是n个0到k之间的整数时,它的运行时间是Θ(n + k)。计数排序不是比较排序,排序的速度快于任何比较排序算法。
由于用来计数的数组C的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存。例如:计数排序是用来排序0到100之间的数字的最好的算法,但是它不适合按字母顺序排序人名。但是,计数排序可以用在基数排序算法中,能够更有效的排序数据范围很大的数组。
步骤
def count_sort(list):
min = 2147483647
max = 0
# 获取最大值和最小值
for x in list:
if x < min:
min = x
if x > max:
max = x
count = [0] * (max - min + 1)
for index in list:
count[index-min] += 1
index = 0
# 填值
for a in range(max-min + 1):
for c in range(count[a]):
list[index] = a + min
index += 1
return list
function count_sort(list){
var min = 2147483647;
var max = 0;
// 获取最大值和最小值
for (let val of list){
if (val < min)
min = val;
if (val > max)
max = val;
}
var count = [];
for (let i = 0;i<max-min+1; i++){
count.push(0);
}
for (let index of list){
count[index-min]+=1;
}
var index = 0;
for (let a = 0; a<max-min+1; a++){
for (let b = 0; b<count[a]; b++){
list[index] = a + min;
index += 1;
}
}
return list;
}
function count_sort($arr){
$min = 2147483647;
$max = 0;
// 取得最大值和最小值
foreach ($arr as $key => $val){
if ($val < $min){
$min = $val;
}
if ($val > $max){
$max = $val;
}
}
// 创建数组
$arr_count = [];
for ($i = 0; $i<$max-$min+1; $i++){
$arr_count[] = 0;
}
foreach($arr as $key=>$val){
$arr_count[$val-$min] += 1;
}
$index = 0;
for ($a = 0;$a<$max - $min + 1; $a++){
for ($b = 0; $b< $arr_count[$a]; $b++){
$arr[$index] = $a + $min;
$index += 1;
}
}
return $arr;
}
$a = [2,5,3,47,46,19,15,26,36,4,50,48,44,27,38];
echo ''
;
print_r(count_sort($a));
function lst = count_sort(lst)
min = 2797373661;
max = 0;
for a = lst
if a < min
min = a;
end
if a > max
max = a
end
end
count = zeros(1, max-min+1);
for val = lst
kk = val - min + 1;
count(kk) = count(kk) + 1;
end
index = 1;
for ii = 1:max-min+1
for jj = 1:count(ii)
lst(index) = ii+min-1;
index = index + 1;
end
end
return