王道数据结构代码---第八章:排序

目录

插入排序

        直接插入排序

        折半插入排序

        希尔排序

交换排序

        冒泡排序

        快速排序

选择排序

        简单选择排序

        堆排序(重要)

归并排序

基数排序

排序算法时间复杂度的比较 


插入排序

        直接插入排序

//直接插入排序,从小到大排序,升序
void InsertSort(ElemType A[], int n)
{
	int i, j;
	//24 66 94  2 15 74 28 51 22 18  2
	for (i = 2; i <= n; i++)//第零个元素是哨兵,从第二个元素开始拿,往前面插入
	{
		if (A[i] < A[i - 1])
		{
			A[0] = A[i];//放到暂存位置,A[0]即是暂存,也是哨兵
			for (j = i - 1; A[0] < A[j]; --j)//移动元素,内层循环控制有序序列中的每一个元素和要插入的元素比较
				A[j + 1] = A[j];
			A[j + 1] = A[0];//把暂存元素插入到对应位置
		}
	}
}

        折半插入排序

//折半查找 插入排序
void MidInsertSort(ElemType A[], int n)
{
	int i, j, low, high, mid;
	for (i = 2; i <= n; i++)
	{
		A[0] = A[i];
		low = 1; high = i - 1;//low有序序列的开始,high有序序列的最后
		while (low <= high)//先通过二分查找找到待插入位置
		{
			mid = (low + high) / 2;
			if (A[mid] > A[0])
				high = mid - 1;
			else
				low = mid + 1;
		}
		for (j = i - 1; j >= high + 1; --j)
			A[j + 1] = A[j];
		A[high + 1] = A[0];
	}
}

        希尔排序

//希尔排序  
//多轮插入排序,同时效率并不如快排,堆排
//小题主要考步长的变化是如何的
void ShellSort(ElemType A[], int n)
{
	int dk, i, j;
	// 73 29 74 51 29 90 37 48 72 54 83
	for (dk = n / 2; dk >= 1; dk = dk / 2)//步长变化,步长变化
	{
		for (i = dk + 1; i <= n; ++i)//以dk为步长进行插入排序
		{
			if (A[i] < A[i - dk])
			{
				A[0] = A[i];
				for (j = i - dk; j > 0 && A[0] < A[j]; j = j - dk)
					A[j + dk] = A[j];
				A[j + dk] = A[0];
			}
		}
	}
}

完整代码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
typedef int ElemType;
typedef struct {
	ElemType* elem;//整型指针
	int TableLen;
}SSTable;

void ST_Init(SSTable& ST, int len)
{
	ST.TableLen = len + 1;//实际申请11个元素的空间
	ST.elem = (ElemType*)malloc(sizeof(ElemType) * ST.TableLen);
	int i;
	srand(time(NULL));
	for (i = 0; i < ST.TableLen; i++)
	{
		ST.elem[i] = rand() % 100;//随机了11个数,但是第一个元素是没有用到的
	}
}
void ST_print(SSTable ST)
{
	for (int i = 0; i < ST.TableLen; i++)
	{
		printf("%3d", ST.elem[i]);
	}
	printf("\n");
}

//直接插入排序,从小到大排序,升序
void InsertSort(ElemType A[], int n)
{
	int i, j;
	//24 66 94  2 15 74 28 51 22 18  2
	for (i = 2; i <= n; i++)//第零个元素是哨兵,从第二个元素开始拿,往前面插入
	{
		if (A[i] < A[i - 1])
		{
			A[0] = A[i];//放到暂存位置,A[0]即是暂存,也是哨兵
			for (j = i - 1; A[0] < A[j]; --j)//移动元素,内层循环控制有序序列中的每一个元素和要插入的元素比较
				A[j + 1] = A[j];
			A[j + 1] = A[0];//把暂存元素插入到对应位置
		}
	}
}

//折半查找 插入排序,考的很少
void MidInsertSort(ElemType A[], int n)
{
	int i, j, low, high, mid;
	for (i = 2; i <= n; i++)
	{
		A[0] = A[i];
		low = 1; high = i - 1;//low有序序列的开始,high有序序列的最后
		while (low <= high)//先通过二分查找找到待插入位置
		{
			mid = (low + high) / 2;
			if (A[mid] > A[0])
				high = mid - 1;
			else
				low = mid + 1;
		}
		for (j = i - 1; j >= high + 1; --j)
			A[j + 1] = A[j];
		A[high + 1] = A[0];
	}
}

//希尔排序  
//多轮插入排序,考大题的概率约等于零,因为编写起来复杂,同时效率并不如快排,堆排
//小题主要考步长的变化是如何的
void ShellSort(ElemType A[], int n)
{
	int dk, i, j;
	// 73 29 74 51 29 90 37 48 72 54 83
	for (dk = n / 2; dk >= 1; dk = dk / 2)//步长变化,步长变化
	{
		for (i = dk + 1; i <= n; ++i)//以dk为步长进行插入排序
		{
			if (A[i] < A[i - dk])
			{
				A[0] = A[i];
				for (j = i - dk; j > 0 && A[0] < A[j]; j = j - dk)
					A[j + dk] = A[j];
				A[j + dk] = A[0];
			}
		}
	}
}


int main()
{
	SSTable ST;
	ElemType A[10] = { 64, 94, 95, 79, 69, 84, 18, 22, 12 ,78 };
	ST_Init(ST, 10);//实际申请了11个元素空间
	memcpy(ST.elem + 1, A, sizeof(A));
	ST_print(ST);
	//InsertSort(ST.elem,10);
	//MidInsertSort(ST.elem,10);
	ShellSort(ST.elem, 10);
	ST_print(ST);
	system("pause");
}

交换排序

        冒泡排序

基本原理

 

 

void BubbleSort(ElemType A[], int n)  //从小到大排序
{
	int i, j;
	bool flag;
	for (i = 0; i < n - 1; i++)//i最多访问到8
	{
		flag = false;  //表示冒泡结束
		for (j = n - 1; j > i; j--)//把最小值就放在最前面
		{
			if (A[j - 1] > A[j])
			{
				swap(A[j - 1], A[j]);
				flag = true;
			}
		}
		if (false == flag)
			return;
	}
}

        快速排序

基本原理 

 

      法一:

// 挖坑法,王道书上使用的方法,最左边作为分割值
int Partition(ElemType A[], int low, int high)
{
	ElemType pivot = A[low];//把最左边的值暂存起来
	while (low < high)
	{
		while (low < high && A[high] >= pivot)//让high从最右边找,找到比分割值小,循环结束
			--high;
		A[low] = A[high];
		while (low < high && A[low] <= pivot)//让low从最左边开始找,找到比分割值大,就结束
			++low;
		A[high] = A[low];
	}
	A[low] = pivot;
	return low;
}

  法二:

//交换法
int Partition1(int* arr, int left, int right)
{
	int k, i;  //i用来遍历数组的下标
	//k记录要放入比分割值小的数据的位置
	for (i = left, k = left; i < right; i++)
	{
		if (arr[i] < arr[right])
		{
			swap(arr[k], arr[i]);
			k++;
		}
	}
	swap(arr[k], arr[right]);
	return k;
}
//快排的实现,递归实现
void QuickSort(ElemType A[], int low, int high)
{
	if (low < high)
	{
		int pivotpos = Partition(A, low, high);//分割点左边的元素都比分割点要小,右边的比分割点大
		QuickSort(A, low, pivotpos - 1);  //依次对两个元素进行递归排序
		QuickSort(A, pivotpos + 1, high);
	}
}

完整代码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

typedef int ElemType;

typedef struct {
	ElemType* elem;  //存储元素的起始地址
	int TableLen;  //元素个数
}SSTable;

void ST_Init(SSTable& ST, int len)
{
	ST.TableLen = len;
	ST.elem = (ElemType*)malloc(sizeof(ElemType) * ST.TableLen);
	int i;
	srand(time(NULL)); //随机数生成,每一次执行代码就会得到随机的10个元素
	for (i = 0; i < ST.TableLen; i++)
	{
		ST.elem[i] = rand() % 100;//生成的是0-99之间
	}
}

void ST_print(SSTable ST)
{
	for (int i = 0; i < ST.TableLen; i++)
	{
		printf("%3d", ST.elem[i]);
	}
	printf("\n");
}

//交换值
void swap(ElemType& a, ElemType& b)
{
	ElemType tmp;
	tmp = a;
	a = b;
	b = tmp;
}

// 64 94 95 79 69 84 18 22 12 78
// 12 64 94 95 79 69 84 18 22 78
void BubbleSort(ElemType A[], int n)  //从小到大排序
{
	int i, j;
	bool flag;
	for (i = 0; i < n - 1; i++)//i最多访问到8
	{
		flag = false;  //表示冒泡结束
		for (j = n - 1; j > i; j--)//把最小值就放在最前面
		{
			if (A[j - 1] > A[j])
			{
				swap(A[j - 1], A[j]);
				flag = true;
			}
		}
		if (false == flag)
			return;
	}
}

//自己写的冒泡排序
void BubbleSort1(ElemType A[], int n)
{
	int i, j, flag;
	for (i = 0; i < n - 1; i++)//i是控制有多少个有序了
	{
		flag = 0;
		for (j = n - 1; j > i; j--)//内层控制比较,交换
		{
			if (A[j - 1] > A[j])
			{
				swap(A[j - 1], A[j]);
				flag = 1;
			}
		}
		if (0 == flag)
		{
			break;
		}
	}
}

// 64 94 95 79 69 84 18 22 12 78
//比64小的放在左边,比64大的放在右边
// 挖坑法,王道书上使用的方法,最左边作为分割值
int Partition(ElemType A[], int low, int high)
{
	ElemType pivot = A[low];//把最左边的值暂存起来
	while (low < high)
	{
		while (low < high && A[high] >= pivot)//让high从最右边找,找到比分割值小,循环结束
			--high;
		A[low] = A[high];
		while (low < high && A[low] <= pivot)//让low从最左边开始找,找到比分割值大,就结束
			++low;
		A[high] = A[low];
	}
	A[low] = pivot;
	return low;
}

//交换法
int Partition1(int* arr, int left, int right)
{
	int k, i;  //i用来遍历数组的下标
	//k记录要放入比分割值小的数据的位置
	for (i = left, k = left; i < right; i++)
	{
		if (arr[i] < arr[right])
		{
			swap(arr[k], arr[i]);
			k++;
		}
	}
	swap(arr[k], arr[right]);
	return k;
}
//交换法
int Partition2(int* arr, int left, int right)
{
	int k, i;
	for (k = i = left; i < right; i++)
	{
		if (arr[i] < arr[right])
		{
			swap(arr[i], arr[k]);
			k++;
		}
	}
	swap(arr[k], arr[right]);
	return k;
}

//快排的实现,递归实现
void QuickSort(ElemType A[], int low, int high)
{
	if (low < high)
	{
		int pivotpos = Partition(A, low, high);//分割点左边的元素都比分割点要小,右边的比分割点大
		QuickSort(A, low, pivotpos - 1);  //依次对两个元素进行递归排序
		QuickSort(A, pivotpos + 1, high);
	}
}


int main()
{
	SSTable ST;
	ElemType A[10] = { 64, 94, 95, 79, 69, 84, 18, 22, 12 ,78 };
	ST_Init(ST, 10);//初始化
	memcpy(ST.elem, A, sizeof(A));//内存copy接口,当你copy整型数组,或者浮点型时,要用memcpy
	ST_print(ST);
	//BubbleSort(ST.elem, 10);//冒泡排序
	QuickSort(ST.elem, 0, 9);
	ST_print(ST);
	return 0;
}

选择排序

        简单选择排序

 

//简单选择排序
void SelectSort(ElemType A[], int n)
{
	int i, j, min;//min记录最小的元素的下标
	for (i = 0; i < n - 1; i++)//最多可以为8
	{
		min = i;
		for (j = i + 1; j < n; j++)//j最多可以为9
		{
			if (A[j] < A[min])
				min = j;
		}
		if (min != i)
		{
			swap(A[i], A[min]);
		}
	}
}

 

        堆排序(重要)

建立大根堆的算法

//调整某个父亲节点
void AdjustDown(ElemType A[], int k, int len)
{
	int i;
	A[0] = A[k];
	for (i = 2 * k; i <= len; i *= 2)
	{
		if (i < len && A[i] < A[i + 1])//左子节点与右子节点比较大小
			i++;
		if (A[0] >= A[i])
			break;
		else {
			A[k] = A[i];
			k = i;
		}
	}
	A[k] = A[0];
}
//用数组去表示树   层次建树
void BuildMaxHeap(ElemType A[], int len)
{
	for (int i = len / 2; i > 0; i--)
	{
		AdjustDown(A, i, len);
	}
}

 堆排序的实现算法

//堆排序实现算法
void HeapSort(ElemType A[], int len)
{
	int i;
	BuildMaxHeap(A, len);//建立大顶堆
	for (i = len; i > 1; i--)
	{
		swap(A[i], A[1]);
		AdjustDown(A, 1, i - 1);
	}
}

完整代码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
typedef int ElemType;
typedef struct {
	ElemType* elem;
	int TableLen;
}SSTable;

void ST_Init(SSTable& ST, int len)//申请空间,并进行随机数生成
{
	ST.TableLen = len;
	ST.elem = (ElemType*)malloc(sizeof(ElemType) * ST.TableLen);
	int i;
	srand(time(NULL));
	for (i = 0; i < ST.TableLen; i++)
	{
		ST.elem[i] = rand() % 100;
	}
}
void ST_print(SSTable ST)
{
	for (int i = 0; i < ST.TableLen; i++)
	{
		printf("%3d", ST.elem[i]);
	}
	printf("\n");
}
void swap(ElemType& a, ElemType& b)
{
	ElemType tmp;
	tmp = a;
	a = b;
	b = tmp;
}

//简单选择排序
void SelectSort(ElemType A[], int n)
{
	int i, j, min;//min记录最小的元素的下标
	for (i = 0; i < n - 1; i++)//最多可以为8
	{
		min = i;
		for (j = i + 1; j < n; j++)//j最多可以为9
		{
			if (A[j] < A[min])
				min = j;
		}
		if (min != i)
		{
			swap(A[i], A[min]);
		}
	}
}

//调整某个父亲节点
void AdjustDown(ElemType A[], int k, int len)
{
	int i;
	A[0] = A[k];
	for (i = 2 * k; i <= len; i *= 2)
	{
		if (i < len && A[i] < A[i + 1])//左子节点与右子节点比较大小
			i++;
		if (A[0] >= A[i])
			break;
		else {
			A[k] = A[i];
			k = i;
		}
	}
	A[k] = A[0];
}
//用数组去表示树   层次建树
void BuildMaxHeap(ElemType A[], int len)
{
	for (int i = len / 2; i > 0; i--)
	{
		AdjustDown(A, i, len);
	}
}

//堆排序实现算法
void HeapSort(ElemType A[], int len)
{
	int i;
	BuildMaxHeap(A, len);//建立大顶堆
	for (i = len; i > 1; i--)
	{
		swap(A[i], A[1]);
		AdjustDown(A, 1, i - 1);
	}
}

//调整子树
void AdjustDown1(ElemType A[], int k, int len)
{
	int dad = k;
	int son = 2 * dad + 1; //左孩子下标
	while (son <= len)
	{
		if (son + 1 <= len && A[son] < A[son + 1])//看下有没有右孩子,比较左右孩子选大的
		{
			son++;
		}
		if (A[son] > A[dad])//比较孩子和父亲
		{
			swap(A[son], A[dad]);
			dad = son;
			son = 2 * dad + 1;
		}
		else {
			break;
		}
	}
}
void HeapSort1(ElemType A[], int len)
{
	int i;
	//建立大顶堆
	for (i = len / 2; i >= 0; i--)
	{
		AdjustDown1(A, i, len);
	}
	swap(A[0], A[len]);//交换顶部和数组最后一个元素
	for (i = len - 1; i > 0; i--)
	{
		AdjustDown1(A, 0, i);//剩下元素调整为大根堆
		swap(A[0], A[i]);
	}
}

//《王道C督学营》课程
//选择排序与堆排序
int main()
{
	SSTable ST;
	ElemType A[10] = { 64, 94, 95, 79, 69, 84, 18, 22, 12 ,99 };
	ST_Init(ST, 10);//初始化
	memcpy(ST.elem, A, sizeof(A));
	ST_print(ST);
	//SelectSort(ST.elem,10);
	HeapSort(ST.elem, 9);//王道书零号元素不参与排序
	//HeapSort1(ST.elem,9);//所有元素参与排序
	ST_print(ST);
	system("pause");
}

归并排序

//Merge的功能是将前后相邻的两个有序表归并为一个有序表
void Merge(ElemType A[], int low, int mid, int high)
{
	ElemType B[N];
	int i, j, k;
	for (k = low; k <= high; k++)//复制元素到B中
		B[k] = A[k];
	for (i = low, j = mid + 1, k = i; i <= mid && j <= high; k++)//合并两个有序数组
	{
		if (B[i] <= B[j])
			A[k] = B[i++];
		else
			A[k] = B[j++];
	}
	while (i <= mid)//如果有剩余元素,接着放入即可
		A[k++] = B[i++];
	while (j <= high)
		A[k++] = B[j++];
}
//归并排序算法的实现
void MergeSort(ElemType A[], int low, int high)//递归分割
{
	if (low < high)
	{
		int mid = (low + high) / 2;
		MergeSort(A, low, mid);
		MergeSort(A, mid + 1, high);
		Merge(A, low, mid, high);
	}
}

完整代码

#include <stdio.h>
#include <stdlib.h>

#define N 7
typedef int ElemType;
//49,38,65,97,76,13,27
//Merge的功能是将前后相邻的两个有序表归并为一个有序表
void Merge(ElemType A[], int low, int mid, int high)
{
	ElemType B[N];
	int i, j, k;
	for (k = low; k <= high; k++)//复制元素到B中
		B[k] = A[k];
	for (i = low, j = mid + 1, k = i; i <= mid && j <= high; k++)//合并两个有序数组
	{
		if (B[i] <= B[j])
			A[k] = B[i++];
		else
			A[k] = B[j++];
	}
	while (i <= mid)//如果有剩余元素,接着放入即可
		A[k++] = B[i++];
	while (j <= high)
		A[k++] = B[j++];
}
//归并排序不限制是两两归并,还是多个归并
// 1 3 5 7 9
// 2 4
// 1 2 3 4 5 7 9  主要的代码逻辑
//归并排序算法的实现
void MergeSort(ElemType A[], int low, int high)//递归分割
{
	if (low < high)
	{
		int mid = (low + high) / 2;
		MergeSort(A, low, mid);
		MergeSort(A, mid + 1, high);
		Merge(A, low, mid, high);
	}
}

void print(int* a)
{
	for (int i = 0; i < N; i++)
	{
		printf("%3d", a[i]);
	}
	printf("\n");
}

// 归并排序
int main()
{
	int A[7] = { 49,38,65,97,76,13,27 };//数组,7个元素
	MergeSort(A, 0, 6);
	print(A);
	system("pause");
}

基数排序

排序算法时间复杂度的比较 

 

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值