c / 数据结构中常见的排序算法,你想要的我都有

博主在雨天整理了之前学习和应用过的排序算法,包括各种数据结构排序方法,重温旧知,强调定期总结的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 外面下雨不方便出去,就趁着这个机会又把之前学过的、用过的排序算法给整理了一下。重新回过头来看看,倒是捡起了不少遗忘的知识,勤整理、勤汇总果然不会错。

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

/*插入类排序*/

void insertSort(int a[],int n)  //直接插入排序
{
	int i,j;
	int temp;
	//第一个元素(i=0)默认有序,故从第二个元素(i=1)开始找位置插入 
	for(i=1; i<n; ++i)
	{
		//首先将待排记录暂存在temp中,
		//避免后续的边比较边移位操作导致数据覆盖而丢失
		temp=a[i];
		
		//对有序序列的元素(a[i]之前的元素),temp从后往前与其比较,
		j=i-1;
		//j>=0防越界
		//如果大于待排关键字,则后移一位
		while(j>=0&&temp<a[j]) 
		{ 
			a[j+1]=a[j];
			--j;		//更新j继续比较,直至temp>=a[i]
		}
		//直到找到第一个大于temp的元素,插入记录到j指示位置的后面 
		a[j+1]=temp;
	}
}

void insertSort2(int a[],int n) 
{
	int i,j;
	//待排记录存放在1~n-1 ,从第2个元素开始比较
	for(i=2; i<n; i++)
	{ 
	//a[0]功能:备份(类似于上面的temp)、防越界 (类似于上面的j>=0)
		a[0]=a[i];
		j=i-1;

		while(a[0]<a[j]) 
		{
			a[j+1]=a[j];
			j--;
		}
		a[j+1]=a[0];
	}
}

void binSort(int a[],int n)//折半插入排序
{ 
	int low,high,mid;
	int i,j,x;
	
	//待排记录存放在0~n-1,low、high分别指向前i-1个有序元素的首末元素,
	//从第3个元素(i=2)开始与mid所指向的元素作比较
	for(i=2; i<n; i++)
	{ 
		x=a[i];//待插记录
		low=0;
		high=i-1;

		while(low<=high) //1.确定插入位置
		{ 
			mid=(low+high)/2;
			//每次都只与mid的左半边或右半边作比较,减少了比较次数
			if(x<a[mid])
				high=mid-1;
			else
				low=mid+1;
		}

		for(j=i-1; j>=low; --j) //2.记录后移
			a[j+1]=a[j];
		a[low]=x; 				//3.插入记录
	}
}

void shellInsert(int a[],int n,int delta) 
{
	int i,j;
	
	//从第1个子序列的第2个元素开始,顺序扫描整个待排序列,当
	//前元素属于哪个序列就对其在哪个序列上进行直接插入排序
	//delta+1表示第1个子序列的第2个元素下标 
	for(i=delta+1; i<n; i++) 
		if(a[i]<a[i-delta]) 
		{
			a[0]=a[i];//只备份,不监视
			
			//此处只能拿j>0做监视哨,因为j的变化以delta为增量,而不是减1,
			//只有delta等于1时才可实现以a[0]作监视
			//从后往前,与当前元素所在序列且位于当前元素前的元素比较,
			//寻找最终该插入的位置(直接插入操作) 
			for(j=i-delta; j>0&&a[0]<a[j]; j-=delta) 
				a[j+delta]=a[j];
			a[j+delta]=a[0];//插入记录
		}
}
//希尔排序 :将待排序列分为若干个子序列,对子序列直接插入排序
void shellSort(int a[],int n,int delta[],int m) 
{ 
	int i;
	for(i=0; i<m; i++) //依次以delta数组作为增量
		shellInsert(a,n,delta[i]);
}

void shellSort2(int a[],int n)
{
	int temp;
	//gap表示希尔增量,初始为n/2,直至减小为1 
	for(int gap=n/2;gap>0;gap/=2)
	{
		for(int i=gap;i<n;++i)
		{
			temp=a[i];
			int j;
			for(j=i;j>=gap&&a[j-gap]>temp;j-=gap)
				a[j]=a[j-gap];
			a[j]=temp;
		}
	}
} 

/*交换类排序*/

void bubbleSort(int a[],int n) //冒泡排序
{ 
	int i,j;
	int temp;
	int flag;

	for(i=n-1;i>=1;--i)
	{
		flag=0; 
		//从第二个元素开始,与其前一个元素比较,此时j可以一直移动到最后一个元素
		for(j=1;j<=i;++j) 
			if(a[j-1]>a[j]) //比较相邻元素,逆序则交换
			{
				temp=a[j];
				a[j]=a[j-1];
				a[j-1]=temp;
				flag=1;
			}
/*	for(i=1; i<n; i++) //n个元素最多比较n-1趟
	{ 
		flag=0; 
		 //从第一个元素开始,与其后一个元素比较 ,此时j只能移到倒数第二个元素 
		for(j=0; j<n-i; j++)
		{
			//比较相邻元素,逆序则交换
			flag=1;
		
		} 
*/	
//若某一趟比较中没有发现一个逆序,则直接结束整个排序过程
		if(flag==0)
			return;
	}
}

void quickSort(int a[],int low,int high) //快速排序 :一次消除多个逆序
{ 
	int temp;
	int i=low,j=high;//low  high分别指向数组首末

	if(low<high) 
	{
		temp=a[low];//假设首元素为枢轴 。此时a[low]看做空单元 

		while(i<j) 
		{
			//首先,j从后往前直到找出比枢轴小的元素的位置
			while(i<j&&a[j]>=temp)
				--j;
			//移入空单元a[low]中 ,此时a[high]为空单元
			if(i<j) 
			{ 
				a[low]=a[j];
				++i;
			}

			while(i<j&&a[i]<temp)//i从前往后直到找到比枢轴大的元素,然后交换
				++i;
			//移入空单元a[high]中 ,此时a[low]为空单元
			if(i<j) 
			{ 
				a[high]=a[i];
				--j;
			}
		}
		a[i]=temp;//将枢轴放到最终确定的位置,即i=j的位置

		//一次划分后,将待排序列分为两个子序列
		quickSort(a,low,i-1);//对temp左边的子序列排序
		quickSort(a,i+1,high);//对temp右边的子序列排序
	}

}

/*选择类排序*/

//简单选择排序:第i趟选择排序,从第i个元素开始,比较n-i次,
//从n-i+1个元素中找到关键字最小(大)的并和第i个元素交换
void selectSort(int a[],int n)
{ 
	int i,j,k;
	int temp;

	for(i=0; i<n; i++) //共n趟
	{ 
		k=i;//初始时总是假设当前无序序列的第一个元素为最小值 
		for(j=i+1; j<n; ++j) //找出值最小的元素的位置
			if(a[k]>a[j])
				k=j;
		//最小关键字与当前无序序列的第一个关键字交换 
		temp=a[i];
		a[i]=a[k];
		a[k]=temp;

	}

}

void shift(int a[],int i,int n)//筛选法调整大根堆
{ 
	int temp=a[i];
	//从i节点的左孩子开始,即从2i+1开始
	for(int j=2*i+1; j<n; j=2*j+1) 
	{ 
	//如果存在右孩子 ,且左孩子小于右孩子,j指向右孩子
		if(j+1<n&&a[j]<a[j+1])
			j++;
	//如果孩子节点大于双亲节点,直接将子节点值赋给双亲节点
		if(a[j]>temp) 
		{ 
			a[i]=a[j];
			i=j;
		} 
		else
			break;
	}
	a[i]=temp;//将temp放到最终的位置

}

void shift1(int a[],int low,int high)
{
	int i=low,j=2*i+1;
	int temp=a[i];
	while(j<=high)
	{
		if(j<high&&a[j]<a[j+1])
			++j;
		if(temp<a[j])
		{
			a[i]=a[j];
			i=j;
			j=2*i+1;
		}
		else
			break;
	}
	a[i]=temp;
}

 //堆排序 。任意元素序列看做完全二叉树,升序则建立大根堆,降序则建立小根堆
void heapSort(int a[],int n)
{ 
	int temp;

	//建立初始堆 :筛选法。
	//i从0开始。故从第n/2-1个元素(最后一个非叶子元素)开始逐层向上倒退,
	//直到根节点
	for(int i=n/2-1; i>=0; i--)
		//shift(a,i,n);
		shift1(a,i,n-1);

	//交换堆顶元素与末尾元素,继续调整堆结构
	for(int j=n-1; j>0; j--) 
	{
		temp=a[0];
		a[0]=a[j];
		a[j]=temp;

		//shift(a,0,j);
		shift1(a,0,j-1);
	}
}

void Sift(int a[],int low,int high)//low,high表示调整范围 
{
	int i=low,j=2*i;//i指向双亲,j为其左孩子 
	int temp=a[i];//对位置i上的节点进行调整 
	
	while(j<=high)//至少得有左孩子才进入循环 
	{
		//如果也有右孩子,且左孩子小于右孩子,则j指向右孩子 
		if(j<high&&a[j]<a[j+1])
			++j;
		//如果孩子节点中的较大者大于其双亲,则该孩子被交换到双亲位置上 
		if(temp<a[j])
		{
			a[i]=a[j];
			
			i=j;	//i,j向下平移一个位置 
			j=2*i;
		}
		else
			break;
	}
	a[i]=temp;//被调整节点放到最终位置 
	
 } 
 void heapSort2(int a[],int n)
 {
 	int i;
 	int temp;
 	
 	for(i=n/2;i>=1;--i)//从最后一个非叶子节点开始调整 ,建立初始堆 
 		Sift(a,i,n);
 	for(i=n;i>=2;--i)//进行n-1次循环,完成堆排序 
 	{
 		temp=a[1];//换出根节点的关键字,放入最终位置 
 		a[1]=a[i];
 		a[i]=temp;
 		
 		Sift(a,1,i-1);
	 }
 }
 
void merge(int array[], int p, int q, int r) //动态申请数组空间 
{
	int n1 = q - p + 1;//子序列1的长度
	int n2 = r - q;//子序列2的长度

	int *L;
	L = (int*)malloc(sizeof(int)*n1);
	int *R;
	R = (int*)malloc(sizeof(int)*n2);

	int i = 0; //i,j分别指向两个子序列 
	int j = 0;

	for(;i < n1; i++)//L,R暂存两子序列的元素 
		L[i] = array[i + p];
	for(;j < n2; j++)
		R[j] = array[j + q  +1];

	i = j = 0;
	int k = p;

	while(i!=n1 && j!= n2) //比较两子序列的元素,较小者保存到数组中 
	{
		if(L[i] <= R[j])
			array[k++] = L[i++];
		else
			array[k++] = R[j++];
	}

	while(i < n1)//序列1还有元素 
		array[k++] = L[i++];
	while(j < n2)//序列2还有元素 
		array[k++] = R[j++];

	free(L);
	free(R);
}

void merge2(int a[],int low,int mid,int high) 
{
	int i,j,k;
	
	int n1=mid-low+1;
	int n2=high-mid;
	int L[n1],R[n2];
	for(i=0;i<n1;i++)
		L[i]=a[low+1];
	for(j=0;j<n2;j++)
		R[j]=a[mid+i+j];
		
	i=0;
	j=0;
	k=low;
	while(i<n1&&j<n2)
	{
		if(L[i]<R[j])
			a[k]=L[i++];
		else
			a[k]=R[j++];
		k++;	
	}
	while(i<n1)
		a[k++]=L[i++];
	while(j<n2)
		a[k++]=R[j++]; 
}

 //2-路归并排序 :先不断2分(未必完全平均)直至每个小序列只有一个元素为止,然后两两合并
void mergeSort(int a[],int low,int high) 
{ 
	if(low<high) {
		//分解过程
		int mid=(low+high)/2;
		mergeSort(a,low,mid);
		mergeSort(a,mid+1,high);

		//合并过程
		merge2(a,low,mid,high);
	}
}

//传入暂存数组 ,这个更好理解 
void Merge2(int sourceArr[],int tempArr[], int startIndex, int midIndex, int endIndex)
{
    int i = startIndex, j=midIndex+1, k = startIndex;
    
    while(i!=midIndex+1 && j!=endIndex+1)
    {
        if(sourceArr[i] > sourceArr[j])
            tempArr[k++] = sourceArr[j++];
        else
            tempArr[k++] = sourceArr[i++];
    }
    while(i != midIndex+1)
        tempArr[k++] = sourceArr[i++];
    while(j != endIndex+1)
        tempArr[k++] = sourceArr[j++];
    //最终排序好的元素还是保存回原数组,tempArr只用于暂时保存用     
    for(i=startIndex; i<=endIndex; i++)
        sourceArr[i] = tempArr[i];
}
 
void MergeSort2(int sourceArr[], int tempArr[], int startIndex, int endIndex)
{
    int midIndex;
    if(startIndex < endIndex)
    {
        midIndex = startIndex + (endIndex-startIndex) / 2;//避免溢出int
        MergeSort2(sourceArr, tempArr, startIndex, midIndex);
        MergeSort2(sourceArr, tempArr, midIndex+1, endIndex);
        Merge2(sourceArr, tempArr, startIndex, midIndex, endIndex);
    }
}

void printArray(int a[],int n) {
	int i;
	for(i=0; i<n; i++)
		printf("%d\t",a[i]);

	printf("\n");
}


int main() {
	int a[5]= {2,1,4,3,6};
	int b[8]= {0,1,4,3,6,7,2,9};
	int c[8]= {8,62,35,77,55,14,36,98};

	printf("直接插入排序1:\n");
	insertSort(a,5);
	printArray(a,5);

	printf("\n直接插入排序2:\n");
	insertSort2(b,8);
	printArray(b,8);

	printf("\n折半插入排序:\n");
	binSort(a,5);
	printArray(a,5);

	printf("\n希尔排序:\n");
	//int delta[3]= {4,2,1}; //n/2
	//shellSort(b,8,delta,3);
	shellSort2(b,8);
	printArray(b,8);
	

	printf("\n冒泡排序:\n");
	bubbleSort(a,5);
	printArray(a,5);

	printf("\n快速排序:\n");
	quickSort(a,0,4);
	printArray(a,5);

	printf("\n简单选择排序:\n");
	selectSort(a,5);
	printArray(a,5);

	printf("\n堆排序:\n");
	heapSort(c,7);
	printArray(c,8);

	printf("\n2-路归并排序:\n");
	int d[8];
	MergeSort2(c,d,0,7); 
	//mergeSort(c,0,7);
	printArray(c,8);

	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值