数据结构:八大经典排序算法及代码实现

本文详细介绍了八种经典的排序算法:直接插入排序、希尔排序、折半插入排序、简单选择排序、堆排序、冒泡排序、快速排序和归并排序,包括它们的原理、代码实现和时间复杂度分析。这些排序算法在不同场景下有着各自的优缺点,理解它们对于优化算法性能至关重要。

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

一、插入排序

1、直接插入排序

从第一个元素开始,依次取出,比较取出的元素和其左边的所有元素,如果比左边所有元素大,则直接插入,否则依次将比该元素大的元素向后移动,然后插入即可。

例:原始数据:46 25 31 18 84 18 20 60
【46】 25 31 18 84 18 20 60
【25 46】 31 18 84 18 20 60
【25 31 46】 18 84 18 20 60
【18 25 31 46】 84 18 20 60
【18 25 31 46 84】 18 20 60
【18 18 25 31 46 84】 20 60
【18 18 20 25 31 46 84】 60
【18 18 20 25 31 46 60 84】

#include<stdio.h>
void InsertSort(int k[],int n) //n为元素个数
{
	int temp;//temp暂时存储取出的值
	for( int i = 0 ; i < n ; i++ )
	{
		if( k[i-1] > k[i] )
		{
			temp = k[i];
			//将比第i个元素大的左边所有元素向后移,给此元素找位置
			for( int j = i-1 ; k[j] > temp ; j-- )
			{
				k[j+1] = k[j];
			}
			//找到元素位置,插入
			k[j+1] = temp;
		}
	}
}
int main()
{
	int a[8]={46, 25, 31, 18, 84, 18, 20, 60};
	InsertSort(a,8);
	printf("排序后的结果是:");
	for( int i = 0 ; i < 8 ; i++ )
	{
		printf("%d\t",a[i]);
	}
	return 0;
}

时间复杂度: 最好复杂度:O(n);最坏复杂度:O(n2)
平均复杂度:O(n2) 稳定


2、希尔排序

用元素个数除以2或3求得间距d1,从第一个元素开始,每隔d1个间距的元素分为一组,将每组的元素排序,再将d1除以2或3求得间距d2,同上,直到间距变为1。

例:原始数据:46 25 31 18 84 18 20 60
d1=4排完序后 -------- 46 18 20 18 84 25 31 60
d2=2排完序后 -------- 20 18 31 18 46 25 84 60
d3=1排完序后 -------- 18 18 20 25 31 46 60 84

#include <stdio.h>
void InsertSort(int k[], int n)
{
	int i, j, temp;
	int d = n;
	do
	{
		d = d/2;
		for( i=d; i < n; i++ )
		{
			if( k[i-d] > k[i] )
			{
				temp = k[i];

				for( j=i-d; k[j] > temp; j-=d )
				{
					k[j+d] = k[j];
				}

				k[j+d] = temp;
			}
		}
	}while(d > 1);
}

int main()
{
	int i, a[8] = {46,25,31,18,84,18,20,60};
	InsertSort(a, 8);
	printf("排序后的结果是:");
	for( i=0; i < 8; i++ )
	{
		printf("%d\t", a[i]);
	}
	return 0;
}

时间复杂度: 平均复杂度:O(n1.3) 不稳定


3、折半插入排序(二分查找)

key为要查找的元素,先将low指向第一个元素,high指向最后一个元素,在low<high的条件下,mid指向中间的元素,如果midVal<key,low=mid+1;如果midVal>key,high=mid-1;如果midVal=key,则查找成功。low>high则查找失败。
注意:在有序的一组数中查找。

#include<stdio.h>
int binarySearch(int a[],int n,int key)
{
	int low=1,high=n;
	while(low<=high){
		int mid=(low+high)/2;
		int midVal=a[mid];
		if(midVal<key){
			low=mid+1;
		}
		else if(midVal>key){
			high=mid-1;
		}
		else 
			return mid;
	}
	return -1;
 } 
 int main(){
 	int i,val,ret;
 	int a[8]={1,2,3,4,5,6,7,8};
 	for(i=0;i<8;i++){
 		printf("%d\t",a[i]);	
	}  
	printf("\n请输入要查找的元素:");
	scanf("%d",&val);
	ret=binarySearch(a,8,val);
	if(-1==ret){//ret为返回值,必须在等号右边
		printf("查找失败\n");
	} 
	else{
		printf("查找成功%d\n",val);
	}
	return 0;
 }

时间复杂度: O(n2)


4、简单选择排序(直接选择排序)

首先从1到n这n个记录中找出最小关键字所在的记录,然后把它与第1个记录交换位置,接着再从2到n这n-1个记录中,找出最小(也就是整个文件中次小的)关键字所在的记录和第2个记录交换位置,依次进行,直到从n-1到n,最后两个记录中,找出最小关键字所在记录把它和n-1位置上的记录交换位置为止,排序结束。

例:原始数据:46 25 31 18 84 18 20 60
【18】 25 31 46 84 18 20 60
【18 18】 31 46 84 25 20 60
【18 18 20】 46 84 25 31 60
【18 18 20 25】 84 46 31 60
【18 18 20 25 31】 46 84 60
【18 18 20 25 31 46】 84 60
【18 18 20 25 31 46 60】 84
【18 18 20 25 31 46 60 84】

#include <stdio.h>

void SelectSort(int k[], int n)
{
	int i, j, min, temp, count1=0, count2=0;

	for( i=0; i < n-1; i++ )
	{
		min = i;
		
		for( j=i+1; j < n; j++ )
		{
			count1++;
			if( k[j] < k[min] )
			{
				min = j;
			}
		}

		if( min != i )
		{
			count2++;
			temp = k[min];
			k[min] = k[i];
			k[i] = temp;
		}
	}
	printf("总共进行了%d次比较,进行了%d次移动!", count1, count2);
}

int main()
{
	int i, a[8] = {46,25,31,18,84,18,20,60};
	SelectSort(a, 8);
	printf("排序后的结果是:");
	for( i=0; i < 8; i++ )
	{
		printf("%d\t", a[i]);
	}
	return 0;
}

时间复杂度: O(n2) 不稳定


5、堆排序

a.将无序序列构建成一个堆(完全二叉树),根据升序降序需求选择大顶堆或小顶堆;
b.将堆顶元素与末尾元素互换,将最大(小)元素沉到数组末端;
c.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。

#include <stdio.h>
int count = 0;
void swap(int k[], int i, int j)
{
	int temp = k[i];
	k[i] = k[j];
	k[j] = temp;
}
void HeapAdjust(int k[], int s, int n)
{
	int temp = k[s];
	for( int i=2*s; i <= n; i*=2 )
	{
		count++;
		if( i < n && k[i] < k[i+1] )
		{
			i++;
		}
		if( temp >= k[i] )
		{
			break;
		}
		k[s] = k[i];
		s = i;
	}

	k[s] = temp;
}

void HeapSort(int k[], int n)
{
	for(int i=n/2; i > 0; i-- )
	{
		HeapAdjust(k, i, n);
	}

	for(int i=n; i > 1; i-- )
	{
		swap(k, 1, i);
		HeapAdjust(k, 1, i-1);
	}
}

int main()
{
	int a[8] = {46,25,31,18,84,18,20,60};
	HeapSort(a, 7);
	printf("总共执行 %d 次比较!", count);
	printf("排序后的结果是:");
	for( int i=1; i < 8; i++ )
	{
		printf("%d\t", a[i]);
	}
	return 0;
}

时间复杂度: O(nlog2n) 不稳定



二、交换排序

6、冒泡排序

#include<stdio.h>
void BubbleSort(int k[], int n)
{
	int temp;
	for(int i=0;i<n-1;i++)
	{
		for(int j=0;j<n-1-i;j++)
		{
			if(k[j]>k[j+1])
			{
				temp=k[j];
				k[j]=k[j+1];
				k[j+1]=temp;
			}
		}
	}
}
int main()
{
	int i, a[8] = {46,25,31,18,84,18,20,60};
	BubbleSort(a, 8);
	printf("排序后的结果是:");
	for( i=0; i < 8; i++ )
	{
		printf("%d\t", a[i]);
	}
	return 0;
}

时间复杂度: 最好复杂度:O(n) ; 最坏复杂度:O(n2); 平均复杂度:O(n2) 稳定


7、快速排序

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

快排第i趟至少应有i个元素就位。(元素的左边元素都小于该元素,元素的右边元素都小于该元素。)
a.设置两个变量i、j,排序开始的时候:i=0,j=N-1;
b.以第一个数组元素作为关键数据,赋值给key,即key=A[0];
c.从j开始向前搜索,即由后开始向前搜索(j–),找到第一个小于key的值A[j],将A[j]和A[i]的值交换;
d.从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]的值交换;
e.重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。

例:原始数据:46 25 31 18 84 18 20 60
一次-------------【20 25 31 18 18】 46 【84 60】
二次-------------【18 18】 20 【31 25】 46 【60】 84
三次------------- 18 【18】 20 【25】 31 46 60 84
排序结果------- 18 18 20 25 31 46 60 84

#include <stdio.h>

void swap(int k[], int low, int high)
{
	int temp = k[low];
	k[low] = k[high];
	k[high] = temp;
}

int Partition(int k[], int low, int high)
{
	int point;
	point = k[low];
	while( low < high )
	{
		while( low < high && k[high] >= point )
		{
			high--;
		}
		swap(k, low, high);

		while( low < high && k[low] <= point )
		{
			low++;
		}
		swap(k, low, high);
	}

	return low;
}

void QSort(int k[], int low, int high)
{
	int point;

	if( low < high )
	{
		point = Partition(k, low, high);
		QSort(k, low, point-1);
		QSort(k, point+1, high);
	}
}

void QuickSort(int k[], int n)
{
	QSort(k, 0, n-1);
}

int main()
{
	int i, a[8] = {46,25,31,18,84,18,20,60};
	QuickSort(a, 8);
	printf("排序后的结果是:");
	for( i=0; i < 8; i++ )
	{
		printf("%d\t", a[i]);
	}
	return 0;
}

时间复杂度: O(nlog2n) 不稳定



二、归并排序

8、归并排序

将两个顺序序列合并成一个顺序序列。(两两归并)

例:原始数据:46 25 31 18 84 18 20 60
八个文件----[46] [25] [31] [18] [84] [18] [20] [60]
一次归并----[25 46] [18 31] [18 84] [20 60]
二次归并----[18 25 31 46] [18 20 60 84]
三次归并----[18 18 20 25 31 46 60 84]

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

#define MAXSIZE 8

void MergeSort(int k[], int n)
{
	int i, next, left_min, left_max, right_min, right_max;
	int *temp = (int *)malloc(n * sizeof(int));

	for( i=1; i < n; i*=2 ) 
	{
		for( left_min=0; left_min < n-i; left_min = right_max )
		{
			right_min = left_max = left_min + i;
			right_max = left_max + i;

			if( right_max > n )
			{
				right_max = n;
			}

			next = 0;

			while( left_min < left_max && right_min < right_max )
			{
				if( k[left_min] < k[right_min] )
				{
					temp[next++] = k[left_min++];
				}
				else
				{
					temp[next++] = k[right_min++];
				}
			}

			while( left_min < left_max )
			{
				k[--right_min] = k[--left_max];
			}

			while( next > 0 )
			{
				k[--right_min] = temp[--next];
			}
		}
	}
}

int main()
{
	int i, a[8] = {46,25,31,18,84,18,20,60};
	MergeSort(a, 8);
	printf("排序后的结果是:");
	for( i=0; i < 8; i++ )
	{
		printf("%d\t", a[i]);
	}
	return 0;
}

时间复杂度: O(nlog2n) 稳定

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值