常用各种sort排序实现(Go/C++版本)

Go版本: 

// 快排(分治)
func QuickSort(arr []int, left, right int) {
	var QuickSorting = func(arr []int, left, right int) int {
		tmp := arr[right] // 1、从右向左依次选基准值tmp
		for left < right {
			for arr[left] <= tmp && left < right { // 2、每轮循环中先从左向右,遇到比基准值小的数则left++
				left++
			}
			if left < right {
				arr[right] = arr[left] // 3、直至遇到比基准值大的数x=array[left]为止,然后再交换基准值与较大值x的位置(保证基准值左侧的值都比基准值tmp小)
			}

			for arr[right] >= tmp && left < right { // 4、每轮循环中再从右向左,遇到比基准值大的数则right--
				right--
			}
			if left < right { // 5、直至遇到比基准值小的数y=array[right]为止,然后再交换基准值与较小值y的位置(保证基准值右侧的值都比基准值tmp大)
				arr[left] = arr[right]
			}
		}

		arr[left] = tmp
		return left
	}

	if left < right {
		mid := QuickSorting(arr, left, right)
		QuickSort(arr, left, mid-1)
		QuickSort(arr, mid+1, right)
	}
}

// 快排(非递归)// todo:待补充
// https://www.bilibili.com/video/av758822583/?vd_source=2c268e25ffa1022b703ae0349e3659e4
func QuickSortNotByRecursion(arr []int) {
}

// 堆排(大顶堆:每个节点的值都大于或等于其左右孩子节点的值)
func HeapSort(arr []int) {
	var CreateHeap = func(arr []int, i, length int) {
		tmp := arr[i]

		// 注意for循环条件:是 j<length 而不是 j<len(arr)
		for j := 2*i + 1; j < length; j = j*2 + 1 { // j=2i+1:当前根节点的左孩子下标 j= 2*j + 1:以当前叶子节点为新根节点,该新根节点的下一层叶子节点左孩子下标
			if j+1 < length && arr[j] < arr[j+1] { // j+1<length:右孩子(j+1)不能超出len长度范围
				j++
			}

			if tmp > arr[j] { // 左右孩子节点中选较大的节点值,并与父节点比较大小
				break // 若父节点值满足"大于或等于其左右孩子节点的值"则break,否则与较大的孩子节点相互交换
			}

			arr[i] = arr[j]
			i = j
		}
		arr[i] = tmp // 将最终比较后较小值放到合适的位置
	}

	// 首次构建堆
	l := len(arr)
	for i := l / 2; i >= 0; i-- { // 从二叉树最后一个父节点从底向上遍历(最上面的父节点:i = 0;最后一个父节点下标:i = len(arr) / 2)
		CreateHeap(arr, i, l)
	}

	// 再次重建堆
	for i := l - 1; i > 0; i-- { // 从下往上不断在每轮循环中置换出当前最大值,arr长度i也逐渐减到0
		arr[0], arr[i] = arr[i], arr[0] // swap 把大顶堆根节点(下标为0)上的最大值交换到末尾,置换出来.
		CreateHeap(arr, 0, i)
	}
}

// 归并
func MergeSort(arr []int, length int) {

	var MergeSorting = func(arr1, arr2 []int, length1, length2 int) {
		i, j := 0, 0
		tempArr := make([]int, 0 /*, length1+length2*/)

		// 1.分别将两个子数组中较小一方的值按大小顺序移动到临时数组tempArr中
		for i < length1 && j < length2 {
			if arr1[i] < arr2[j] {
				tempArr = append(tempArr, arr1[i]) // 将较小值加入临时数组tempArr
				i++
				// fmt.Println("i ", i)
			} else {
				tempArr = append(tempArr, arr2[j])
				j++
				// fmt.Println("j ", j)
			}
		}

		// 2.肯定存在一个子数组先移动完,所以需要将另一个未移动完的有序子数组剩下的元素继续移动到tempArr中
		if i < length1 {
			tmpArr = append(tmpArr, arr1[i:]...)
		}

		if j < length2 {
			tmpArr = append(tmpArr, arr2[j:]...)
		}

		// 3.将合并数组值赋给原始数组
		copy(arr, tmpArr) // arr = tempArr // 此赋值方式不会影响main()中原数组arr中的值,仅仅在该函数作用域内的结果是排好序的
		// for i := 0; i < length1+length2; i++ {
		// 	arr[i] = tmpArr[i]
		// }
	}

	// 注意:下面的l1和l2不能写成 "len(arr)/2" 和 "len(arr)-l1"
	if length > 1 { // 最后拆至每个子数组只有一个元素
		l1 := length / 2
		l2 := length - l1
		arr1, arr2 := arr, arr[l1:] // arr1原数组前半部分、arr2原数组后半部分
		MergeSort(arr1, l1)         // 不断拆分数组长度直至长度为1
		MergeSort(arr2, l2)         // 不断拆分数组长度直至长度为1
		MergeSorting(arr1, arr2, l1, l2)

        // mid := length / 2
		// arr1, arr2 := arr[:mid], arr[mid:] // arr1原数组前半部分、arr2原数组后半部分
		// MergeSort(arr1, len(arr1))         // 不断拆分数组长度直至长度为1
		// MergeSort(arr2, len(arr2))         // 不断拆分数组长度直至长度为1
		// MergeSorting(arr1, arr2, len(arr1), len(arr2))
	}
}

// 冒泡
func MaoPaoSort(arr []int) {
	for i := 0; i < len(arr); i++ {
		for j := i + 1; j < len(arr); j++ {
			if arr[i] > arr[j] {
				arr[i], arr[j] = arr[j], arr[i] // swap
			}
		}
	}
}

func main() {
	array := []int{5, 28, 73, 19, 6, 0, 5}
	// MaoPaoSort(array)
	// QuickSort(array, 0, len(array)-1)
	// QuickSortNotByRecursion(array)
	// HeapSort(array)
	MergeSort(array, len(array))
	fmt.Println(array)
	return
}

C++版本:

/*******************************归并*******************************/
 void merge_sort(int* array1, int len1, int* array2, int len2)
 {
	 int i = 0;
	 int j = 0;
	 int k = 0;
	 //int tmp[10];						// 临时数组 后续要优化,不能固定为10
	 int* tmp = new int[10];
	 // 1.分别将两个子数组中较小一方的值按大小顺序移动到临时数组tmp中
	 while (i < len1 && j < len2)
	 {
		 if (array1[i] < array2[j])
		 {
			 tmp[k++] = array1[i++];
		 }
		 else
		 {
			 tmp[k++] = array2[j++];
		 }
	 }
	 // 2.肯定存在一个子数组先移动完,所以需要将另一个未移动完的有序子数组剩下的元素继续移动到tmp中
	 while (i < len1)
	 {
		 tmp[k++] = array1[i++];
	 }
	 while (j < len2)
	 {
		 tmp[k++] = array2[j++];
	 }

	 // 3.将合并数组值赋给原始数组
	 for (int q = 0; q < len1 + len2; q++)
	 {
		 array1[q] =  tmp[q];			// int* subArray1 = array; subArray1中包含原数组的所有元素
	 }

	 free(tmp);
 }

 // 拆分函数
 void merge(int* array, int len)
 {
	 if (len > 1)						// 最后拆至每个子数组只有一个元素
	 {
		 int len1 = len / 2;
		 int len2 = len - len1;
		 int* subArray1 = array;
		 int* subArray2 = array + len1;
		 merge(subArray1, len1);
		 merge(subArray2, len2);
		 merge_sort(subArray1, len1, subArray2, len2);
	 }
 }

 int main()
 {
	int test_array[7] = { 5, 28, 73, 19, 6, 0, 5 };
	int len = sizeof(test_array) / sizeof(int);
	int right = len - 1; // 下标从0开始

	//maopao_sort(test_array, len);
	//quick_sort(test_array, 0, right); // ok
	//quick_sroting_not_by_recursion(test_array, 0, right); // ok
	//heap_sort(test_array, len);
	merge(test_array, len);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值