排序——插入排序、折半插入排序、希尔排序、冒泡排序、快速排序、简单选择排序、堆排序、2路归并排序(王道版)

参考王道《2023年数据结构考研复习指导》

注意:本程序中,带哨兵是指arr[0]该存储单元不用于存储数据。

#include <iostream>
#define	N 20		// 数组大小

void InsertSort(int arr[], int n);
void BinaryInsertSort(int arr[], int n);
void ShellSort(int arr[], int n);
void ShellSort2(int arr[], int n);
void BubbleSort(int arr[], int n);
void QuickSort(int arr[], int low, int high);
int Partition(int arr[], int low, int high);
void SelectSort(int arr[], int n);
void BuildMaxHeap(int arr[], int len);
void HeadAdjust(int arr[], int k, int len);
void HeapSort(int arr[], int len);
void Merge(int arr[], int low, int mid, int high, int n);
void MergeSort(int arr[], int low, int high, int n);

int main() {
	srand((unsigned)time(NULL));        // 初始化随机数种子
	int arr[N+1];	// arr[0]为哨兵
	for (int i = 1; i <= N; ++i) {		// 随机生成数组
		arr[i] = rand() % 100 + 1;		
	}
	std::cout << "数组初始状态为:" << std::endl;
	for (int i = 1; i <= N; ++i) {
		std::cout << arr[i] << " ";
	}
	std::cout << std::endl;

	// InsertSort(arr, N);
	// BinaryInsertSort(arr, N);
	// ShellSort(arr, N);
	// ShellSort2(arr, N);
	HeapSort(arr, N);
	std::cout << "数组排序后为:" << std::endl;
	for (int i = 1; i <= N; ++i) {
		std::cout << arr[i] << " ";
	}
	std::cout << std::endl;

	int arr2[N];	// arr2[0]为哨兵
	for (int i = 0; i < N; ++i) {		// 随机生成数组
		arr2[i] = rand() % 100 + 1;
	}
	std::cout << "数组初始状态为:" << std::endl;
	for (int i = 0; i < N; ++i) {
		std::cout << arr2[i] << " ";
	}
	std::cout << std::endl;

	// BubbleSort(arr2, N);
	// QuickSort(arr2, 0, N - 1);
	// SelectSort(arr2, N);
	MergeSort(arr2, 0, N - 1, N);
	std::cout << "数组排序后为:" << std::endl;
	for (int i = 0; i < N; ++i) {
		std::cout << arr2[i] << " ";
	}
	std::cout << std::endl;

	system("pause");
	return 0;
}

// 带哨兵的插入排序(数组)
void InsertSort(int arr[], int n) {
	int i, j;
	for (i = 2; i <= n; ++i) {
		if (arr[i] < arr[i - 1]) {
			arr[0] = arr[i];
			for (j = i - 1; arr[0] < arr[j]; --j) {
				arr[j + 1] = arr[j];
			}

			arr[j + 1] = arr[0];
		}
	}
}

// 优化——带哨兵的折半插入排序(数组)
void BinaryInsertSort(int arr[], int n) {
	int i, j, low, high, mid;
	for (i = 2; i <= n; ++i) {
		if (arr[i] < arr[i - 1]) {
			arr[0] = arr[i];
			// 折半查找
			low = 1;
			high = i - 1;
			while (low <= high) {
				mid = (low + high) / 2;
				if (arr[mid] > arr[0]) {		// 当中间值大于目标值
					high = mid - 1;
				} else {		// 当中间值小于或等于目标值(为了保证排序的稳定性,即使目标值与中间值相对,目标值也必须放在中间值右边)
					low = mid + 1;
				}
			}

			for (j = i - 1; j >= low; --j) {	// 后移
				arr[j + 1] = arr[j];
			}
			arr[j + 1] = arr[0];
		}
	}
}

// 带哨兵的希尔排序(数组)
// 和王道书上略有不同,王道书是在分组间交替排序
// 这里是对一个分组排序完后,再对其他分组排序,更符合希尔排序
void ShellSort(int arr[], int n) {
	int d, i, j, k;
	for (d = n / 2; d > 0; d = d / 2) {
		for (i = 1; i <= d; ++i) {
			for (j = i + d; j <= n; ++j) {
				if (arr[j] < arr[j - d]) {
					arr[0] = arr[j];
					for (k = j - d; k > 0 && arr[0] < arr[k]; k -= d) {
						arr[k + d] = arr[k];
					}
					arr[k + d] = arr[0];
				}
			}
		}
	}
}

// 王道版带哨兵的希尔排序(数组)
void ShellSort2(int arr[], int n) {
	int d, i, j;
	for (d = n / 2; d >= 1; d = d / 2) {
		for (i = d + 1; i <= n; ++i) {
			if (arr[i] < arr[i - d]) {
				arr[0] = arr[i];
				for (j = i - d; j > 0 && arr[0] < arr[j]; j -= d) {
					arr[j + d] = arr[j];
				}
				arr[j + d] = arr[0];
			}
		}
	}
}

// 冒泡排序(无哨兵)
void BubbleSort(int arr[], int n) {
	for (int i = 0; i < n - 1; ++i) {
		bool flag = false;
		for (int j = n - 1; j > i; --j) {
			if (arr[j - 1] > arr[j]) {
				int temp = arr[j - 1];
				arr[j - 1] = arr[j];
				arr[j] = temp;
				flag = true;
			}
		}
		if (!flag) {		// 如果没有发生交换,说明表已经有序
			return ;
		}
	}
}

// 快速排序(无哨兵)
void QuickSort(int arr[], int low, int high) {
	if (low < high) {
		int pivotops = Partition(arr, low, high);	// 划分
		QuickSort(arr, low, pivotops - 1);		// 对左子表进行快速排序
		QuickSort(arr, pivotops + 1, high);		// 对右子表进行快速排序
	}
}

// 用第一个元素将待排序序列划分成左右两个部分
int Partition(int arr[], int low, int high) {
	int pivot = arr[low];		// 用第一个元素作为枢轴
	while (low < high) {
		while (low < high && arr[high] >= pivot) {
			--high;
		}
		arr[low] = arr[high];	// 比枢轴小的移动到左边
		while (low < high && arr[low] <= pivot) {
			++low;
		}
		arr[high] = arr[low];	// 比枢轴大的移动到右边
	}
	arr[low] = pivot;

	return low;		// 返回存放枢轴的最终位置
}

// 简单选择排序(无哨兵)
void SelectSort(int arr[], int n) {
	for (int i = 0; i < n - 1; ++i) {
		int min = i;
		for (int j = i + 1; j < n; ++j) {
			if (arr[j] < arr[min]) {
				min = j;
			}
		}
		if (min != i) {
			int temp = arr[i];
			arr[i] = arr[min];
			arr[min] = temp;
		}
	}
}

// 建立大根堆
void BuildMaxHeap(int arr[], int len) {		// len为数组长度
	for (int i = len / 2; i > 0; --i) {		// 从后往前调整所有非终端结点
		HeadAdjust(arr, i, len);
	}
}

// 将以k为根的子树调整为大根堆
void HeadAdjust(int arr[], int k, int len) {	// len为数组长度
	arr[0] = arr[k];	// arr[0]暂存子树的根节点
	for (int i = 2 * k; i <= len; i *= 2) {		// 沿key较大的子结点向下筛选
		if (i < len && arr[i] < arr[i + 1]) {	// 如果存在右结点且右结点大于左结点
			++i;			
		}
		if (arr[0] >= arr[i]) {		// 如果根结点大于等于子结点,则说明符合大根堆
			break;
		} else {					// 否则,根结点与子结点互换
			arr[k] = arr[i];		
			k = i;					// 修改k值,以便继续向下筛选
		}
	}
	arr[k] = arr[0];				// 被筛选结点的值放入最终位置
}

// 堆排序(带哨兵)
void HeapSort(int arr[], int len) {
	BuildMaxHeap(arr, len);			// 初始建堆
	for (int i = len; i > 1; --i) {	
		int temp = arr[1];			// 堆顶元素和堆底元素交换
		arr[1] = arr[i];
		arr[i] = temp;

		HeadAdjust(arr, 1, i - 1);	// 将剩余元素调整成大根堆
	}
}

// arr[low ... mid] 和 arr[mid+1 ... high]各自有序,将两个部分归并
void Merge(int arr[], int low, int mid, int high, int n) {
	int* temp = (int*)malloc(n*sizeof(int));	// 辅助数组
	int i, j, k;
	for (i = low; i <= high; ++i) {		// 将arr[low ... high]中的元素复制到temp中
		temp[i] = arr[i];
	}

	for (i = low, j = mid + 1, k = i; i <= mid && j <= high; k++) {
		if (temp[i] <= temp[j]) {	// 保证稳定性
			arr[k] = temp[i++];
		} else {
			arr[k] = temp[j++];
		}
	}

	while (i <= mid) {		// 将剩余排序好的元素放入arr
		arr[k++] = temp[i++];
	}

	while (j <= high) {		// 将剩余排序好的元素放入arr
		arr[k++] = temp[j++];
	}

	free(temp);
}

// 2路归并排序(无哨兵)
void MergeSort(int arr[], int low, int high, int n) {
	if (low < high) {
		int mid = (low + high) / 2;			// 从中间划分
		MergeSort(arr, low, mid, n);		// 对左半部分归并排序
		MergeSort(arr, mid + 1, high, n);	// 对右半部分归并排序
		Merge(arr, low, mid, high, n);		// 归并
	}
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈阿土i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值