八大排序

本文深入讲解了各种排序算法,包括插入排序、选择排序、希尔排序、堆排序、归并排序、基数排序、快速排序和冒泡排序。每种算法都详细介绍了其思想、时间复杂度和稳定性,并提供了C语言实现代码。

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

  • 插入排序
  • 最坏的时间复杂度是O(n²),最好是O(n),并且是稳定的

1、思想:插入排序通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入 ,如此重复,直至完成序列排序。

2、 算法分析

1. 从序列第一个元素开始,该元素可以认为已经被排序

2. 取出下一个元素,设为待插入元素,在已经排序的元素序列中从后向前扫描,如果该元素(已排序)大于待插入元素,将该元素移到下一位置。

3. 重复步骤2,直到找到已排序的元素小于或者等于待排序元素的位置,插入元素

4. 重复2,3步骤,完成排序。

红色框起来的部分是已排序序列

#include<stdio.h>
#include<stdlib.h>
void InsertSort(int arr[], int len)
{
	int tmp = 0;
	int i = 1;
	int j = i - 1;
	for (i; i < len; ++i)
	{
		tmp = arr[i];
		for (j = i - 1; j >= 0 && arr[j] > tmp; --j)
		{
			arr[j + 1] = arr[j];//将大元素后移
		}
		arr[j + 1] = tmp;
	}
}
int main()
{
	int arr[] = { 32, 1244, 32, 43, 45, 34, 6, 547, 65, 8679, 678, 8, 66 };
	int len = sizeof(arr) / sizeof(arr[0]);
	InsertSort(arr,len);
    for(int i=0;i<len;i++)
	{
		printf("%d ",arr[i]);
	}
	return 0;
}
  • 简单选择排序
  • 最好和最差的平均复杂度都是O(n²),并且是不稳定的
  1. 思想:每一趟从带排序的数据元素中选出最小(最大)元素,与待排序数列的第一个元素进行交换

红色框起来的是待排序数列的最小元素,绿色框起来的是待排序数列的第一个元素

#include<stdio.h>
#include<stdlib.h>
void SimpleSelectSort(int arr[],int len)
{
	int i=0;
	int j=i+1;
	int min=i;
	for(i;i<len-1;i++)
	{
		for(j=i+1;j<len;j++)
		{
			if(arr[j]<arr[min])
				min=j;
		}
		if(min!=i)
		{
			int tmp=arr[min];
			arr[min]=arr[i];
			arr[i]=tmp;
		}
	}
}
int main()
{
	int arr[]={9,2,8,3,7,4,6,5,1};
	int len = sizeof(arr) / sizeof(arr[0]);
	SimpleSelectSort(arr,len);
	for(int i=0;i<len;i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\n");
	return 0;
}
  • 希尔排序
  • 最坏的时间复杂度是O(n²),最好是O(n),并且是不稳定的

希尔排序又称“缩小增量排序”,也是一种插入排序类的方法,在时间效率上有较大的改进。

  1. 思想:先将整个待排序序列分割成若干个子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,在对全体记录进行一次直接插入排序

#include<stdio.h>
#include<stdlib.h>
void Shell(int arr[],int len,int k)
{
	int tmp=0;
	int i=k;
	int j=i-k;
	for(int i;i<len;i++)
	{
		tmp=arr[i];
		for(j=i-k;j>=0&&arr[j]>tmp;j-=k)
		{
			arr[j+k]=arr[j];
		}
		arr[j+k]=tmp;
	}
}
void ShellSort(int arr[],int len,int k[],int klen)
{
	for(int i=0;i<klen;i++)
	{
		Shell(arr,len,k[i]);
	}
}
int main()
{
	int arr[]={49,38,65,97,76,13,27,49,55,04};
	int len=sizeof(arr)/sizeof(arr[0]);
	int k[]={5,3,1};
	int klen=sizeof(k)/sizeof(k[0]);
	ShellSort(arr,len,k,klen);
	for (int i = 0; i < len; ++i)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}
  • 堆排序
  • 最好和最坏和平均时间复杂度都是O(nlogn),并且是不稳定的

1.思想:堆实质上是一种完全二叉树,分为打定队和小顶堆,大顶堆就是根节点始终大于等于子节点,两个子节点之间大小随意,小顶堆反之。

堆排序首先就是要把一个无序序列排成一个大顶堆(升序)然后用排好的大顶堆的根节点和最后一个子节点交换,就得到最大值(最后一个子节点),剔除这个值,之后重复之前的动作(将交换后的二叉树重新排成大顶堆),再进行交换,重复直至剩下一个数。

给定一个无序序列:2,7,6,9,3

 

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

void Heap(int arr[],int pos,int len)
{
	int i=pos;
	int j=i*2+1;
	int tmp=0;
	for(j;j<len;j=i*2+1)
	{
		if(j<len-1&&arr[j+1]>arr[j])
			++j;
		if(arr[i]>=arr[j])
			break;
			tmp=arr[i];
			arr[i]=arr[j];
			arr[j]=tmp;
			i=j;
	}
}
void Sort(int arr[],int len)
{
	int tmp;
	for(int i=len/2-1;i>=0;i--)
	{
		Heap(arr,i,len);
	}
	for(int i=len-1;i>0;i--)
	{
		tmp=arr[0];
		arr[0]=arr[i];
		arr[i]=tmp;
		Heap(arr,0,i);
	}
} 
void Show(int arr[], int len)
{
	for (int i = 0; i < len; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}
int main()
{
	int arr[]={31, 231, 23, 21, 3, 21, 4, 2, 41, 23, 1, 232};
	int len=sizeof(arr)/sizeof(arr[0]);
	Sort(arr,len);
	Show(arr, len);
	return 0;
}
  • 归并排序
  • 最好和最坏和平均时间复杂度都是O(n*logn),并且是稳定的

  1. 思想:将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

创建一个空的数组,将将要合并的两个序列从小到大依次取出合并到新的数组中。

#include<stdio.h>
#include<stdlib.h>
void Gui(int arr[],int a[],int mid,int front,int back)
{
	int i=front;
	int k=front;
	int j=mid+1;
	while(i<mid+1&&j<back+1)
	{
		if(arr[i]<=arr[j])
			a[k++]=arr[i++];
		if(arr[i]>arr[j])
			a[k++]=arr[j++];
	}
	while(i<mid+1)
	{
		a[k++]=arr[i++];
	}
	while(j<back+1)
	{
		a[k++]=arr[j++];
	}
	for(int i=front;i<=back;i++)
	{
		arr[i]=a[i];
	}
}
void GuiBing(int arr[],int a[],int front,int back)
{
	int mid=(front+back)/2;
	if(front<back)
	{
		//int mid=(front+back)/2;
		GuiBing(arr,a,front,mid);
		GuiBing(arr,a,mid+1,back);
		Gui(arr,a,mid,front,back);
	}
}
void Sort(int arr[], int len)
{
	int *a = (int*)malloc(sizeof(arr[0])*len);
	GuiBing(arr, a, 0, len - 1);
	free(a);
}
void Show(int arr[],int len)
{
	for(int i=0;i<len;i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\n");
}
int main()
{
	int arr[]={5,7,3,6,9,2,4,1};
	int len=sizeof(arr)/sizeof(arr[0]);
	Sort(arr,len);
	Show(arr,len);
	return 0;
}
  • 基数排序
  • 最好和最坏和平均时间复杂度都是O(n*k),并且是稳定的

  1. 思想:基数排序又称为“桶子法”,从低位开始将待排序的数按照这一位的值放到相应的编号为0~9的桶中。等到低位排完得到一个子序列,再将这个序列按照次低位的大小进入相应的桶中,一直排到最高位为止,数组排序完成。LSD——从低位向高位排,MSD——从高位向低位排。

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define MAXSIZE 10
int FindMax(int arr[],int len)
{
	int max=arr[0];
	for(int i=0;i<len;i++)
	{
		if(max<arr[i])
		{
			max=arr[i];
		}
	}
	int count=0;
	while(max!=0)
	{
		max/=10;
		count++;
	}
	return count;
}
int FindFin(int num, int fin)
{
	return num / (int)pow(10.0, fin) % 10;
}
void Radix(int arr[], int len, int fin)
{
	int backet[10][MAXSIZE] = {};
	int finnum = 0;
	int num[10] = {};
	for (int i = 0; i < len; ++i)
	{
		finnum = FindFin(arr[i], fin);
		backet[finnum][num[finnum]] = arr[i];
		num[finnum]++;
	}
	int aindex = 0;
	int bindex = 0;
	for (int i = 0; i < 10; ++i)
	{
		bindex = 0;
		while (bindex != num[i])
		{
			arr[aindex++] = backet[i][bindex++];
		}
	}
}
void RadixSort(int arr[], int len)
{
	int max = FindMax(arr, len);
	for (int i = 0; i < max; ++i)
	{
		Radix(arr, len, i);
	}
}
void Show(int arr[],int len)
{
	for(int i=0;i<len;i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\n");
}
int main()
{
	int arr[] = {99,87,107,231,67,45,32,123,8,36 };
	int len = sizeof(arr) / sizeof(arr[0]);
	RadixSort(arr, len);
	Show(arr, len);
	return 0;
}
  • 快速排序
  • 平均实际复杂度为O(nlogn),最差时间复杂度为O(n2),并且是不稳定的

  1. 思想:

#include<stdio.h>
void quicksort(int arr[],int left,int right)
{
	int i=left;
	int j=right;
	int tmp=arr[left];
	int t;
	if(left>right)
		return;
	while(i!=j)
	{
		while(tmp>=arr[j]&&i<j)
			j--;
		while(tmp<=arr[i]&&i<j)
			i++;
		if(i<j)
		{
			t=arr[i];
			arr[i]=arr[j];
			arr[j]=t;
		}	
	}
	arr[left]=arr[i];
	arr[i]=tmp;
	quicksort(arr,left,j-1);
	quicksort(arr,i+1,right);
}
void Show(int arr[],int len)
{
	for(int i=0;i<len;i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\n");
}
int main()
{
	int arr[]={7,3,2,4,5,9,8,1,6};
	int len=sizeof(arr)/sizeof(arr[0]);
	quicksort(arr,0,len);
	Show(arr,len);
	return 0;

}
  • 冒泡排序
  • 最好和最差的平均复杂度都是O(n²),并且是稳定的

1.思想:从数组头部开始遍历,不断比较相邻的两个元素的大小,让较大的元素往后移,直到数组末尾,经过第一轮的比较,就将最大的元素移动到最后一个位置。

第一轮结束后继续第二轮,仍然从数组头部开始比较,让较大的元素后移,就可以找到次大的元素,以此类推。

​
 #include<stdio.h>
#include<stdlib.h>
void BubbleSort(int arr[],int len)
{
	int tmp=0;
	for(int i=0;i<len-1;i++)
	{
		for(int j=0;j<len-i-1;j++)
		{
			if(arr[j]>arr[j+1])
			{
				 tmp=arr[j];
				 arr[j]=arr[j+1];
				 arr[j+1]=tmp;
			}
		}
	}
}
int main()
{
	int arr[] = { 31, 2, 342, 5, 34, 6, 45, 7, 56, 7 };
	int len = sizeof(arr) / sizeof(arr[0]);
	BubbleSort(arr, len);
	for(int i=0;i<len;i++)
	{
		printf("%d ",arr[i]);
	}
	return 0;
}

​

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值