c语言中6大排序算法实现和解析

#include <stdio.h>

void showIntOne(int *Arr, int n);

//插入排序
void insertSort(int *Arr, int n);
//添加哨兵之后的插入排序
void sentinelInsertSort(int *Arr, int n);
//使用二分查找的插入排序
void binInsertSort(int *Arr, int n);


//归并排序
//left : 开始的下标  right : 结束的下标
void mnergeSort(int *ArrMain, int *ArrTemp, int left,int right);

//快速排序
void quickSort(int *Arr, int left, int right);

//冒泡排序
void bubbleSort(int *Arr, int n);

//选择排序
void selectionSort(int *Arr, int n);

//累堆排序
void heapSort(int *Arr, int n);
//使root为根的子树成为最大堆
void maxHeapify(int *Arr, int heapSize, int root);
//第一次将数组建造为最大堆
void buildMaxHeap(int *Arr, int n);

int main(void)
{
	int arr[8] = {1, 4, 3, 5, 7, 8, 4, 9};
	int heapArr[11] = {0, 4, 8, 7, 5, 3, 2, 5, 9, 0, 3};
	int arrSize = 8;
	int heapArrSize = 11;
	int arrTemp[8];
	showIntOne(heapArr, heapArrSize);
//	insertSort(arr, arrSize);
//	sentinelInsertSort(arr, arrSize);
//	binInsertSort(arr, arrSize);
//	mnergeSort(arr, arrTemp, 0, 10);
//	quickSort(arr, 0, 10);
//	bubbleSort(arr, arrSize);
//	selectionSort(arr, arrSize);
	heapSort(heapArr, heapArrSize - 1);
	showIntOne(heapArr, heapArrSize);
	return 0;
}
/****************插入排序原始版本****************/
/*
 * 原理:将未排好序的元素依次插入到已经排好序的队伍中去
 * 实现方法:1.选择数组的第一个元素作为已经排好序的队伍
 			 2.将下一个未排好序的元素和已经排好序的队伍中的元素一次进行比较交换,知道找到合适的位置。
			 3.重复执行步骤2,直到所有的元素都排好序
 * 代码:
 */
void insertSort(int *Arr, int n)
{
	int i, j;	//i 排好序的队伍中最大的下标 j 
	int temp = 0;
	for(i = 0; i < n - 1; ++ i)	//步骤3  每次循环就会排好一个元素
	{
		for(j = i + 1; j > 0; -- j)	//步骤2.
		{
			if(Arr[j] < Arr[j - 1])
			{
				temp = Arr[j];
				Arr[j] = Arr[j - 1];
				Arr[j - 1] = temp;
			}
			else 
				break;
		}
	}
}
/***************插入排序改进版1*****************/
/*改进方法:添加一个哨兵位置,每次排序需要插入时,先把这个元素放入哨兵位置,			找到合适的位置之后再进行插入。
*/
void sentinelInsertSort(int *Arr, int n)
{
	int sentinel = 0;	//哨兵
	int i, j;
	for(i = 0; i < n - 1; ++ i)
	{
		sentinel = Arr[i + 1];
		for(j = i; j >= 0; -- j)
		{
			if(Arr[j] > sentinel)
				Arr[j + 1] = Arr[j];
			else 
				break;
		}
		Arr[j + 1] = sentinel;
	}
}

/**************插入排序改进版2****************/
/*改进方法:在插入排序中,未排序元素要找到合适的插入位置时,采用折半法
 *折半法:
 * 1.循环实现:
 * 2.递归实现:
*/
//循环
void binInsertSort(int *Arr, int n)
{
//4, 8, 9, 7, 5, 3, 2 ,5, 9, 0}
	int i, j;
	int start = 0, end = 0, mid = 0;
	int find = 0;
	int ArrJ = 0;
	for(i = 0; i < n - 1; ++ i)
	{
		j = i + 1;
		start = 0;
		end = i;
		while(1)
		{
			mid = (start + end) / 2;
			//getchar();
			if(start >= end)
			{
				if(Arr[start] > Arr[j])
					find = start;
				else 
					find = start + 1;
				break;
			}
			if(Arr[j] > Arr[mid])
				start = mid + 1;
			if(Arr[j] <= Arr[mid])
				end = mid - 1;
			//printf("%d %d %d\n", start, mid, end);
			//for(ArrJ = 0; ArrJ < 10; ArrJ ++)
			//	printf("%d ", Arr[ArrJ]);
		}
		ArrJ = Arr[i + 1];
		//printf("%d ", find);
		for(j = i + 1; j > find; -- j)
		{
			Arr[j] = Arr[j - 1];
		}
		Arr[find] = ArrJ;
	}
}
/******************归并排序**********************/
/*原理:将两个已经排好序的数组进行归并结合成一个新的排好序的数组
 *实现方法:1.传入一个数组,每次将这个数组分割成两个数组,如果这两个数组已经排好序了,就只需要将这两个数组归并为一个数组就可以完成排序。
 *			2.要将分割的两个数组排好序,只要把分割出的两个数组分别用步骤1排序就好了。
 *			3.如果在步骤1中传入的数组为一个数字,则这个数字已经是排好序的,直接返回。
 *			4.重复步骤1, 2,3.
*/
void mnergeSort(int *ArrMain, int *ArrTemp, int left, int right)
{
	int mid = (left + right) / 2;
	int sizeOfArrOne = mid - left + 1;
	int sizeOfArrTwo = right - mid;
	int sizeOfArrTemp = right - left + 1;
	int i = 0, j = 0, k = 0;
	if(left >= right)
		return ;
	else
		mnergeSort(ArrMain, ArrTemp, left, mid);
		mnergeSort(ArrMain, ArrTemp, mid + 1, right);
	while(i < sizeOfArrOne && j < sizeOfArrTwo)
	{
		if(ArrMain[left + i] <= ArrMain[mid + 1 + j])
		{
			ArrTemp[k] = ArrMain[left + i];
			++ i;
			++ k;
		}
		if(ArrMain[mid + 1 + j] < ArrMain[left + i])
		{
			ArrTemp[k] = ArrMain[mid + 1+ j];
			++ j;
			++ k;
		}
	}
		while(i < sizeOfArrOne)
		{
			ArrTemp[k] = ArrMain[left + i];
			++ i;
			++ k;
		}
		while(j < sizeOfArrTwo)
		{
			ArrTemp[k] = ArrMain[mid + 1 + j];
			++ j;
			++ k;
		}
	for(i = 0; i < sizeOfArrTemp; i ++)
	{
		ArrMain[left + i] = ArrTemp[i];
	}
	
}
/**********************快速排序**********************/
/*
 * 原理:每次递归之后确定一个数字的位置,并且这个数字前面的元素都是比它小的,后前的元素都是比它大的。
 * 实现方法:1.选择数组第一个元素作为主元,将数组中所有比主元小的元素放在前面,所有比主元大的元素放在后面,将主元放在合适的位置。
 * 			 2.用主元将数组分为两个数组,将这两个数组使用步骤1进行操作。
 * 			 3.如果数组中只有一个元素,则直接返回。
 * 			 4.重复1, 2, 3.
*/
void quickSort(int *Arr, int left, int right)
{
	int head = Arr[left];
	int i = left + 1, j = right;
	int temp = 0;
	if(left >= right)
			return;
	while(i <= j)
	{
		while(Arr[i] <= head)
		{
			++ i;
		}
		while(Arr[j] > head)
		{
			-- j;
		}
		if(i < j)
		{
			temp = Arr[i];
			Arr[i] = Arr[j];
			Arr[j] = temp;
		}
	}
	temp = Arr[left];
	Arr[left] = Arr[j];
	Arr[j] = temp;
	//showIntOne(Arr, 11);
	//getchar();
	quickSort(Arr, left, j - 1);
	quickSort(Arr, j + 1, right);

}
/*******************冒泡排序*******************/
/*原理:两两依次进行比较,大的在后,小的在前,每次循环得出的较大值排在后面
*/
void bubbleSort(int *Arr, int n)
{
	int i, j, temp = 0;
	for(i = 0; i < n - 1; ++ i)
	{
		for(j = 0; j < n - i - 1; ++ j)
		{
			if(Arr[j] > Arr[j + 1])
			{
				temp = Arr[j];
				Arr[j] = Arr[j + 1];
				Arr[j + 1] = temp;
			}
		}
	}
}
/*****************选择排序*********************/
/*原理:每次循环遍历之后,找到当前未排序的队伍中的最小元素的下标,然后将这个这个最小元素放到队伍的最前面,下次循环从下个位置开始。
*/
void selectionSort(int *Arr, int n)
{
	int i, j, k;
	int temp = 0;
	for(i = 0; i < n - 1; i ++)
	{
		k = i;
		for(j = i + 1; j < n; j ++)
		{
			if(Arr[k] > Arr[j])
					k = j;
		}
		temp = Arr[k];
		Arr[k] = Arr[i];
		Arr[i] = temp;
	}
}
/*****************累堆排序*******************/
/*原理:建立最大堆,最大堆的根结点是堆中的最大元素,每次将建好的最大堆的根结点与最后一个元素交换,再重新维持最大堆。
 *实现方法:1.第一次建立最大堆的时候,应该从后往前建立,将堆中的前n/2个元素从后往前分别作为根结点建立最大堆。
 			2.最大堆的根结点是堆中的最大元素,将根结点与堆中的最后一个结点交换并且堆的大小要减一,如果这时候堆的大小为1,直接返回,否则重新从根结点开始建立最大堆。
			3.重复2步骤。
 */
void heapSort(int *Arr, int n)
{
	int i, temp = 0;
	int heapSize = n;
	buildMaxHeap(Arr, n);	//开始先建造一个最大堆
	for(i = n; i > 1; -- i)
	{
		temp = Arr[1];
		Arr[1] = Arr[i];
		Arr[i] = temp;
		-- heapSize;
		maxHeapify(Arr, heapSize, 1);
	}
}

//
void maxHeapify(int *Arr, int heapSize ,int root)
{
	int leftChild = root * 2;
	int rightChild = root * 2 + 1;	//最后一个结点的父结点没有右孩子时越界
	int largest = root;
	int temp = 0;
	if(root > (heapSize / 2))
		return ;
	if(Arr[largest] < Arr[leftChild])
	{
		largest = leftChild;
	}
	if(rightChild < heapSize)	//判断最后一个结点的父结点的右孩子是否存在
	{
	if(Arr[largest] < Arr[rightChild])	//最后一个结点的父结点没有右孩子时越界 Arr[right]里面出现不确定值
	{
		largest = rightChild;
	}
	}
	if(largest != root)
	{
		temp = Arr[largest];
		Arr[largest] = Arr[root];
		Arr[root] = temp;
		maxHeapify(Arr, heapSize, largest);
	}
}

//
void buildMaxHeap(int *Arr, int n)
{
	int i;
	int heapSize = n;
	for(i = n / 2; i > 0; -- i)
	{
		maxHeapify(Arr, heapSize, i);
	}
}
void showIntOne(int *Arr, int n)
{
	int i = 0;
	for(i = 0; i < n; ++ i)
		printf("%d ", Arr[i]);
	printf("\n");
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值