数据结构之内部排序

原理和代码来自耿国华数据结构–用C语言描述(第二版)

1 排序的基本概念

  • 排序:有 n n n个记录的序列 { R 1 , R 2 , … , R n } \{R_1,R_2,{\dots},R_n\} {R1,R2,,Rn},其相应关键字的序列是 { K 1 , K 2 , … , K n } \{K_1,K_2,{\dots},K_n\} {K1,K2,,Kn},相应的下标序列为 { 1 , 2 , … , n } \{1,2,{\dots},n\} {1,2,,n}。通过排序,要求找出当前下标序列 { 1 , 2 , … , n } \{1,2,{\dots},n\} {1,2,,n}的一种排序 { p 1 , p 2 , … , p n } \{p_1,p_2,{\dots},p_n\} {p1,p2,,pn},使得相应关键字满足非递减或非递增关系。
  • 内部排序:整个排序过程完全在内存中进行的。
  • 外部排序:由于待排序记录数据量太大,内存无法容纳全部数据,排序需要借助外部存储设备才能完成。
  • 排序的稳定性:假设在待排序的序列中存在多个具有相同关键字的记录。设 K i = K j K_i=K_j Ki=Kj。若在排序前的序列中 R i R_i Ri领先于 R j R_j Rj,经过排序后得到的序列中 R i R_i Ri仍然领先于 R j R_j Rj,则称所用的排序方法是稳定的,反之是不稳定的。

2 插入类排序

基本思想:在一个已排好序的记录子集上,每一步将下一个待排序的记录有序插入到已排好序的记录子集中,直到将所有待排序记录全部插入为止。

2.1 直接插入排序

算法思想:将第个记录插入到前面个已排好序的记录中。

#include "stdio.h"
#include "stdlib.h"
const int MaxLength = 100;
int arr[MaxLength];


// 直接插入排序的时间复杂度为O(n^2),空间复杂度为O(1)
void InsSort(int arr[], int length) {
	for (int i = 2; i <= length; i++) {
		arr[0] = arr[i];  // 设置监视哨
		int j = i - 1;
		while (arr[0] < arr[j]) {
			arr[j + 1] = arr[j];
			j = j - 1;
		}
		arr[j + 1] = arr[0];  // 此处需要注意是j + 1
	}
}

void Print(int arr[], int length) {
	for (int i = 1; i <= length; i++) {
		printf("%d ", arr[i]);
	}
	printf("\n");
}

int main() {
	int n;
	printf("请输入待排序的元素个数n,其中n必须大于0,并且小于100:");
	scanf_s("%d\n", &n);

	for (int i = 1; i <= n; i++) {
		printf("请输入第%d个元素:", i);
		scanf_s("%d", &arr[i]);
	}

	Print(arr, n);
	InsSort(arr, n);
	Print(arr, n);

	system("pause");
	return 0;
}

注:
直接插入排序的时间复杂度为O(n^2),空间复杂度为O(1)。

2.2 折半插入排序

算法改进:折半插入排序改进于直接插入排序,直接插入排序在寻找带插入元素的位置时,采用的是顺序查找。
算法思想:在寻找待排序记录在子表中的位置时,采用折半查找。

#include "stdio.h"
#include "stdlib.h"
const int MaxLength = 100;
int arr[MaxLength];


// 折半插入排序改善了直接插入排序中比较次数的数量级,但是时间复杂度仍为O(n^2),空间复杂度为O(1)
void BinSort(int arr[], int length) {
	for (int i = 2; i <= length; i++) {
		arr[0] = arr[i];
		int low = 1, high = i - 1;
		while (low <= high) {
			int mid = (low + high) / 2;
			if (arr[0] < arr[mid])
				high = mid - 1;
			else
				low = mid + 1;
		}
		for (int j = i - 1; j >= low; j--)
			arr[j + 1] = arr[j];
		arr[low] = arr[0];
	}
}

void Print(int arr[], int length) {
	for (int i = 1; i <= length; i++) {
		printf("%d ", arr[i]);
	}
	printf("\n");
}

int main() {
	int n;
	printf("请输入待排序的元素个数n,其中n必须大于0,并且小于100:");
	scanf_s("%d\n", &n);

	for (int i = 1; i <= n; i++) {
		printf("请输入第%d个元素:", i);
		scanf_s("%d", &arr[i]);
	}

	Print(arr, n);
	BinSort(arr, n);
	Print(arr, n);

	system("pause");
	return 0;
}

注:
1、平均关键字比较次数为 n l o g 2 n nlog_2n nlog2n,其比直接插入排序的最差情况要好,但是比其最好情况要差。
2、时间复杂度为 O ( n 2 ) O(n^2) O(n2)

2.3 希尔排序

算法改进:希尔排序改进于直接插入排序,直接插入排序在待排序的关键字较少且基本有序的情况下,性能最佳,希尔排序利用了这一点。
算法思想:将待排序的关键字序列分成若干较小的子序列,对子序列进行直接插入排序,使整个待排序序列排好序。

#include "stdio.h"
#include "stdlib.h"
const int MaxLength = 100;
int arr[MaxLength];

void ShellInsert(int arr[], int length, int delta) {
	for (int i = delta + 1; i <= length; i++) {
		if (arr[i] < arr[i - delta]) {
			arr[0] = arr[i];
			int j;
			for (j = i - delta; j > 0 && arr[0] < arr[j]; j -= delta)
				arr[j + delta] = arr[j];
			arr[j + delta] = arr[0];
		}
	}
}

void SheSort(int arr[], int length, int delta[], int n) {
	for (int i = 0; i <= n - 1; i++) {
		ShellInsert(arr, length, delta[i]);
	}
}

void Print(int arr[], int length) {
	for (int i = 1; i <= length; i++) {
		printf("%d ", arr[i]);
	}
	printf("\n");
}

int main() {

	int n, delta[] = {5, 2, 1};
	printf("请输入待排序的元素个数n,其中n必须大于0,并且小于100:");
	scanf_s("%d\n", &n);

	for (int i = 1; i <= n; i++) {
		printf("请输入第%d个元素:", i);
		scanf_s("%d", &arr[i]);
	}

	Print(arr, n);
	SheSort(arr, n, delta, 3);
	Print(arr, n);

	system("pause");
	return 0;
}

注:
1、算法在具体实现的时候,并不是先对一个子序列完成插入排序,再对另一个子序列进行插入排序,而是从第一个子序列的第二个记录开始,顺序扫描整个待排序记录序列,当前记录属于哪个子序列,就在哪一个子序列中进行插入排序。
2、希尔排序的增量序列并没有唯一的选择,此处选取 d = n / 2 d=n/2 d=n/2,再取 d = d / 2 d=d/2 d=d/2
3、时间复杂度为 O ( n 1.5 ) O(n^{1.5}) O(n1.5)

2.4 插入类排序的总结

排序算法改进思路时间复杂度最好情况最坏情况空间复杂度稳定性
直接插入排序 O ( n 2 ) O(n^2) O(n2) O ( n ) O(n) O(n) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)稳定
折半插入排序改进了确定插入位置方法:利用折半思想确定在有序表中的插入位置 O ( n 2 ) O(n^2) O(n2)比较时间复杂度为 n l o g n nlogn nlogn O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)稳定
希尔排序利用直接插入排序的最好情况: n n n比较小时,基本有序 O ( n 1.5 ) O(n^{1.5}) O(n1.5) O ( 1 ) O(1) O(1)不稳定

3 交换类排序

基本思想:通过一系列交换逆序元素进行排序的方法。

3.1 冒泡排序

算法思想:反复扫描待排序记录序列,在扫描的过程中顺次比较相邻的两个元素的大小,若逆序就交换位置。

#include "stdio.h"
#include "stdlib.h"

const int MaxLength = 100;
int arr[MaxLength];

/*
	冒泡排序的时间复杂度:O(n^2),并且是一种稳定的排序方法。
*/
void BubSort(int arr[], int length) {
	bool flag = true;  // 快速得知是否已经排好序
	for (int i = 1; i < length && flag; i++) {
		flag = false;
		for (int j = 0; j < (length - i); j++) {
			if (arr[j] > arr[j + 1]) {
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
				flag = true;
			}
		}
	}
}

void Print(int arr[], int length) {
	for (int i = 0; i < length; i++) {
		printf("%d ", arr[i]);
	}
	printf("\n");
}


int main() {

	int n;
	printf("请输入待排序的元素个数n,其中n必须大于0,并且小于等于100:");
	scanf_s("%d\n", &n);

	for (int i = 0; i < n; i++) {
		printf("请输入第%d个元素:", (i + 1));
		scanf_s("%d", &arr[i]);
	}

	Print(arr, n);
	BubSort(arr, n);
	Print(arr, n);

	system("pause");
	return 0;
}

注:
1、对于 n n n个记录的序列,冒泡排序最多进行 n − 1 n-1 n1趟。且若数组下标从 0 0 0开始记录,那么每趟冒泡排序选择的记录为 n − i − 1 n-i-1 ni1个。
2、冒泡排序的时间复杂度为 O ( n 2 ) O(n^2) O(n2)。最好的情况是待排序序列已经有序,那么此时的时间复杂度为 O ( n ) O(n) O(n)
3、空间复杂度为 O ( 1 ) O(1) O(1)

3.2 快速排序

算法改进:快速排序改进于冒泡排序,冒泡排序一次只能消除一个逆序。而快速排序的一次交换可能消除多个逆序。
算法思想:从待排序记录序列中选取一个记录为枢轴,将小于枢轴的记录移到其前面,大于或等于枢轴的记录移到其后面,最后将枢轴插入到两个子表分界线的位置。这一过程称为一趟快速排序。对分割后的子表再次按以上原则分割,知道所有子表的表长不超过1为止。

#include "stdio.h"
#include "stdlib.h"

const int MaxLength = 100;
int arr[MaxLength];

/*
	一趟快速排序:基准选取arr[low],对arr[low]至arr[high]进行一趟排序划分,使得基准记录之前所有的
				  记录均小于基准,基准之后的记录均大于基准。
*/
int QKPass(int arr[], int low, int high) {
	int temp = arr[low];
	while (low < high) {
		while (low < high && arr[high] > temp)
			high--;
		if (low < high) {
			arr[low] = arr[high];
			low++;
		}
		while (low < high && arr[low] < temp)
			low++;
		if (low < high) {
			arr[high] = arr[low];
			high--;
		}
	}
	arr[low] = temp;
	return low;
}

/*
	完整的快速排序:注意递归控制条件low < high
*/
void QKSort(int arr[], int low, int high) {
	if (low < high) {
		int pos = QKPass(arr, low, high);
		QKSort(arr, low, pos - 1);
		QKSort(arr, pos + 1, high);
	}
}

void Print(int arr[], int length) {
	for (int i = 0; i < length; i++) {
		printf("%d ", arr[i]);
	}
	printf("\n");
}

int main() {

	int n;
	printf("请输入待排序的元素个数n,其中n必须大于0,并且小于等于100:");
	scanf_s("%d\n", &n);

	for (int i = 0; i < n; i++) {
		printf("请输入第%d个元素:", (i + 1));
		scanf_s("%d", &arr[i]);
	}

	Print(arr, n);
	QKSort(arr, 0, n - 1);
	Print(arr, n);


	system("pause");
	return 0;
}

注:
1、快速排序的平均时间复杂度为 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n),并且这是目前内部排序方法中所能达到的最好的平均复杂度。其最好的情况为 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n),最坏的情况为 O ( n 2 ) O(n^2) O(n2)
2、空间复杂度为 O ( l o g 2 n ) O(log_2n) O(log2n)
3、快速排序是一种不稳定的排序方法。

3.3 交换类排序的总结

排序算法改进思路时间复杂度最好情况最坏情况空间复杂度稳定性
冒泡排序 O ( n 2 ) O(n^2) O(n2) O ( n ) O(n) O(n) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)稳定
快速排序交换不相邻的两个元素,消除多个逆序 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n 2 ) O(n^2) O(n2) O ( l o g 2 n ) O(log_2n) O(log2n)不稳定

4 选择类排序

基本思想:每一趟在 n − i + 1 n-i+1 ni+1个记录中选择关键字最小的记录作为有序序列中的第 i i i个记录。

4.1 简单选择排序

算法思想:每次从序列中选择最小的记录。

#include "stdio.h"
#include "stdlib.h"

const int MaxLength = 100;
int arr[MaxLength];

void SelSort(int arr[], int length) {
	for (int i = 0; i < length - 1; i++) {
		int index = i;
		for (int j = i + 1; j < length; j++) {
			if (arr[j] < arr[index])
				index = j;
		}
		if (index != i) {
			int temp = arr[i];
			arr[i] = arr[index];
			arr[index] = temp;
		}
	}
}

void Print(int arr[], int length) {
	for (int i = 0; i < length; i++) {
		printf("%d ", arr[i]);
	}
	printf("\n");
}

int main() {

	int n;
	printf("请输入待排序的元素个数n,其中n必须大于0,并且小于等于100:");
	scanf_s("%d\n", &n);

	for (int i = 0; i < n; i++) {
		printf("请输入第%d个元素:", (i + 1));
		scanf_s("%d", &arr[i]);
	}

	Print(arr, n);
	SelSort(arr, n);
	Print(arr, n);

	system("pause");
	return 0;
}

注:
1、简单选择排序过程中需要进行的比较次数与初始状态下的待排序的记录序列的排列情况无关。
2、平均时间复杂度为 O ( n 2 ) O(n^2) O(n2)
3、最坏情况为:第一个记录最大,其余记录从小到大有序排列。
4、简单选择排序是一种不稳定的排序方法。

4.2 树形选择排序

算法改进:树形选择排序改进于简单选择排序,在简单选择排序中, n n n个记录需要 n − 1 n-1 n1次比较,而 n − 1 n-1 n1个记录则要 n − 2 n-2 n2次比较,…,比较的操作时间复杂度为 O ( n 2 ) O(n^2) O(n2)。每次比较没有利用上一次比较的结果,所以若要降低比较操作的时间复杂度,则需要把比较过程中的大小关系保存下来。
算法思想:先把待排序的 n n n个记录的关键字两两比较,取出较小者,然后再在 n / 2 n/2 n/2个较小中,采取同样的方法进行比较,选出每两个的较小者,如此反复,直至选出最小关键字记录为止。

树形选择排序的代码省略

注:
1、树形选择排序的时间复杂度为 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n),最好情况和最坏情况都是 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)
2、树形选择排序的空间复杂度为 O ( n ) O(n) O(n)
3、树形选择排序是一种稳定的排序算法

4.3 堆排序

算法改进:堆排序改进于树形选择排序,树形选择排序的空间复杂度为 O ( n ) O(n) O(n),为弥补这一缺陷,从而提出的堆排序。
算法思想:把待排序的记录的关键字存放在数组arr[1…n]中,将arr看成是一颗完全二叉树的顺序排序表示,每个结点表示一个记录,任意结点arr[i]的左孩子是arr[2i],右孩子是arr[2i+1]。堆排序的过程主要解决两个问题:一是按堆定义建初堆,二是去掉最大元后重建堆,得到次大元。
①:将一个任意序列看成是对应的完全二叉树,由于叶结点可以看成单元素的堆,反复利用重建堆算法,自底向上把所有子树调整为堆,直至将整个完全二叉树调整为堆。
②:重建堆过程:首先将与堆相对应的完全二叉树根结点中的记录移出,该记录称为待调整记录。此时根结点相当于空结点,从空结点的左右子树中挑选一个关键字较大的记录,如果该记录的关键字大于待调整记录的关键字,则将该记录上移至空结点中。此时,原来那个关键字较大的子结点相当于空结点,从空结点的左右子树中选出一个关键字较大的记录,如果该记录的关键字仍大于待调整记录的关键字,则将该记录上移至空结点中。重复上述移动过程,直到空结点左右子树的关键字均小于待调整记录的关键字。此时将待调整记录放入空结点即可。

#include "stdio.h"
#include "stdlib.h"

const int MaxLength = 100;
int arr[MaxLength];

void Print(int arr[], int length) {
	for (int i = 1; i <= length; i++) {
		printf("%d ", arr[i]);
	}
	printf("\n");
}

/*
	1、重建堆过程:假设arr[k...m]是以arr[k]为根的完全二叉树,且分别以arr[2k]和arr[2k+1]
				   为根的左右子树的大根堆,调整arr[k],使得整个序列arr[k...m]满足堆得性质。
*/
void sift(int arr[], int k, int m) {
	int temp = arr[k];
	int i = k;
	int j = 2 * i;  // 左孩子下标
	bool finished = false;  // 设立标记,一旦左右孩子没有大于待调整记录的结点,那么重建堆完成
	while (j <= m && !finished) {
		if ((j + 1) <= m && arr[j] < arr[j + 1])  // 如果右孩子的关键字大,那么沿右子树进行筛选
			j = j + 1;
		if (temp > arr[j])  // 如果堆尾移上来的元素直接大于左右子树的最大者,筛选结束
			finished = true;
		else {  // 否则,进一步往下筛选
			arr[i] = arr[j];
			i = j;
			j = 2 * i;
		}
	}
	arr[i] = temp;  // 将待调整元素放置恰当的位置
}

/*
	2、建初堆:对记录数组arr[]建堆,n为数组的长度。
*/
void crt_heap(int arr[], int n) {
	for (int i = n / 2; i >= 1; i--) {  // 从最后一个非叶子结点,自底向上逐层调整所有子树形成堆
		sift(arr, i, n);
	}
}

/*
	3、堆排序算法:对arr[1...n]进行堆排序,执行本算法后,arr中记录按关键字由小到大有序排序
*/
void HeaSort(int arr[], int n) {
	crt_heap(arr, n);  // 建初堆
	printf("建立大根堆如下:");
	Print(arr, n);
	for (int i = n; i > 1; i--) {  // n-1次筛选得到堆排序结果
		int temp = arr[1];  // 交换堆顶和堆底元素
		arr[1] = arr[i];
		arr[i] = temp;
		sift(arr, 1, i - 1);  // 重建堆
	}
}


int main() {
	int n;
	printf("请输入待排序的元素个数n,其中n必须大于0,并且小于100:");
	scanf_s("%d\n", &n);

	for (int i = 1; i <= n; i++) {
		printf("请输入第%d个元素:", i);
		scanf_s("%d", &arr[i]);
	}

	printf("待排序序列:");
	Print(arr, n);
	HeaSort(arr, n);
	printf("堆排序结果:");
	Print(arr, n);

	system("pause");
	return 0;
}

注:
1、堆排序的时间复杂度为 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n),最好情况和最坏情况都是 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)
2、堆排序的空间复杂度为 O ( 1 ) O(1) O(1)
3、堆排序是一种不稳定的排序算法

4.4 选择类排序的总结

排序算法改进思路时间复杂度最好情况最坏情况空间复杂度稳定性
简单选择排序 O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)不稳定
树形选择排序排序比较过程中记录元素大小关系 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n ) O(n) O(n)稳定
堆排序将存储在向量中的数据元素看成一颗完全二叉树,减少了辅助空间 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( 1 ) O(1) O(1)不稳定

5 归并排序

基本思想:将两个或两个以上有序表合并成一个新的有序表。

5.1 2路归并排序

算法思想:假设初始序列含有 n n n个记录,首先将这 n n n个记录看成 n n n个有序的子序列,每个子序列的长度为1,然后两两归并,得到 n / 2 n/2 n/2个长度为2的有序子序列,在此基础上,再对长度为2的子序列进行两两归并,直到得到长度为 n n n的有序序列。

#include "stdio.h"
#include "stdlib.h"

const int MaxLength = 100;
int arr01[MaxLength];

void Merge(int array01[], int low, int mid, int high) {
	int i = low;
	int j = mid + 1;
	int k = 0;
	int array02[MaxLength];
	while (i <= mid && j <= high) {
		if (array01[i] <= array01[j]) {
			array02[k] = array01[i];
			i++;
		}
		else {
			array02[k] = array01[j];
			j++;
		}
		k++;
	}
	while (i <= mid) {
		array02[k] = array01[i];
		k++;
		i++;
	}
	while (j <= high) {
		array02[k] = array01[j];
		k++;
		j++;
	}
	for (int m = low; m < low + k; m++) {
		array01[m] = array02[m - low];
	}
}

void MSort(int array01[], int low, int high) {
	if(low < high){
		int mid = (low + high) / 2;
		MSort(array01, low, mid);
		MSort(array01, mid + 1, high);
		Merge(array01, low, mid, high);
	}
}

void Print(int arr[], int length) {
	for (int i = 0; i < length; i++) {
		printf("%d ", arr[i]);
	}
	printf("\n");
}

int main() {
	int n;
	printf("请输入待排序的元素个数n,其中n必须大于0,并且小于等于100:");
	scanf_s("%d\n", &n);

	for (int i = 0; i < n; i++) {
		printf("请输入第%d个元素:", i + 1);
		scanf_s("%d", &arr01[i]);
	}

	Print(arr01, n);
	MSort(arr01, 0, n - 1);
	Print(arr01, n);


	system("pause");
	return 0;
}

注:
1、归并排序的时间复杂度为 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n),空间复杂度为 O ( n ) O(n) O(n)
2、归并排序是一种稳定的排序方法。
3、由于需要附加辅助空间,归并排序一般不用于内部排序,而是用于外部排序。

5.2 归并排序的总结

排序算法改进思路时间复杂度最好情况最坏情况空间复杂度稳定性
归并排序 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n ) O(n) O(n)稳定

6 分配类排序

基本思想:利用分配和收集两种基本操作实现排序。而之前所述的各种排序方法(插入类排序、交换类排序、选择类排序和归并排序)都是基于比较和交换。

6.1 多关键字排序

一般用例子来说明,了解思想即可。

6.2 链式基数排序

算法思想:基数排序属于上述“低位优先”排序法,通过反复进行分配和收集操作完成排序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
1.实验目的 掌握内排序,比较各种排序的优、缺点。 2 需求分析 2.1原理 2.1.1、直接排序 算法描述:经过i-1遍处理后,L[1..i-1]己排好序。第i遍处理仅将L[i]插入L[1..i-1]的适当位置,使得L[1..i]又是排好序的序列。要达到这个目的,我们可以用顺序比较的方法。首先比较L[i]和L[i-1],如果L[i-1]≤ L[i],则L[1..i]已排好序,第i遍处理就结束了;否则交换L[i]与L[i-1]的位置,继续比较L[i-1]和L[i-2],直到找到某一个位置j(1≤j≤i-1),使得L[j] ≤L[j+1]时为止。 2.1.2、冒泡排序 算法描述:核心思想是扫描数据清单,寻找出现乱序的两个相邻的项目。当找到这两个项目后,交换项目的位置然后继续扫描。重复上面的操作直到所有的项目都按顺序排好。 2.1.3、快速排序 算法描述:首先检查数据列表中的数据数,如果小于两个,则直接退出程序。如果有超过两个以上的数据,就选择一个分割点将数据分成两个部分,小于分割点的数据放在一组,其余的放在另一组,然后分别对两组数据排序。通常分割点的数据是随机选取的。这样无论你的数据是否已被排列过,你所分割成的两个字列表的大小是差不多的。而只要两个子列表的大小差不多。 2.1.4、选择排序 算法描述:首先找到数据清单中的最小的数据,然后将这个数据同第一个数据交换位置;接下来找第二小的数据,再将其同第二个数据交换位置,以此类推。 2.1.5、堆排序 (1) 基本思想:堆排序是一树形选择排序,在排序过程中,将R[1..N]看成是一颗完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系来选择最小的元素。 (2) 堆的定义: N个元素的序列K1,K2,K3,...,Kn.称为堆,当且仅当该序列满足特性: Ki≤K2i Ki ≤K2i+1(1≤ I≤ [N/2]) 2.1.6、希尔排序 算法描述:在直接插入排序算法中,每次插入一个数,使有序序列只增加1个节点,并且对插入下一个数没有提供任何帮助。如果比较相隔较远距离(称为增量)的数,使得数移动时能跨过多个元素,则进行一次比较就可能消除多个元素交换。 2.2要求 1.本程序对以下六种常用内部排序算法进行实测比较:冒泡排序插入排序,选择排序,希尔排序,快速排序,堆排序。 2.排序的元素的关键字为整数。用正序,逆序,不同乱序的数据作测试比较。比较的指标为有关键字参加的比较次数和关键字的移动次数。 3.程序以人机对话的形式进行,每次测试完毕显示各种比较指标值 。 2.3任务 设计一个测试程序比较几种内部排序算法的关键字比较次数和移动次数以取得直观感受。 2.4运行环境 (1)WINDOWSXP系统 (2)C++ 编译环境 3.实验方法 本实验主要是内排序,通过比较的次数和移动的次数判断排序的好坏。主要子函数的说明如下。 1.简单选择排序XuanzePaixu(); 2.冒泡排序MaopaoPaixu(); 3. 直接插入排序CharuPaixu(); 4. 快速排序KuaisuPaixu(); 5. 堆排序DuiPaixu(); 6. 希尔排序 XierPaixu(); 以上的排序算法均采用书中所用的算法。程序采用输入的时候仅输入所要的个数,具体的输入数据由程序随机产生个数,并且输出。
C语言内部排序算法有以下几种: 1. 冒泡排序(Bubble Sort) 冒泡排序是一种简单的排序算法,其基本思想是重复地遍历要排序的数列,每次比较相邻的两个元素,如果顺序错误就交换它们的位置,直到整个数列都有序为止。 2. 选择排序(Selection Sort) 选择排序是一种简单直观的排序算法,其基本思想是每次从待排序的数列中选择最小的元素,将其放在已排序数列的末尾,直到所有元素都排序完毕。 3. 插入排序(Insertion Sort) 插入排序是一种简单直观的排序算法,其基本思想是将待排序的数列分成已排序和未排序两个部分,每次从未排序部分中取出一个元素,插入到已排序部分的适当位置,直到所有元素都排序完毕。 4. 快速排序(Quick Sort) 快速排序是一种高效的排序算法,它的基本思想是通过一趟排序将待排序的数列分成两部分,其中一部分的所有元素都小于另一部分的所有元素,然后分别对这两部分再进行快速排序,直到整个数列都有序为止。 5. 归并排序(Merge Sort) 归并排序是一种稳定的排序算法,其基本思想是将待排序的数列分成若干个子序列,每个子序列都是有序的,然后将这些子序列两两合并,直到整个数列都有序为止。 6. 堆排序(Heap Sort) 堆排序是一种高效的排序算法,它的基本思想是将待排序的数列看作一棵完全二叉树,每次将最大的元素放到堆的末尾,并重新调整堆结构,直到整个数列都有序为止。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

是聪聪黄吖

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

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

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

打赏作者

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

抵扣说明:

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

余额充值