数据结构-八大排序算法总结


一.插入排序

 1.直接插入算法    时间复杂度o(n^2)  空间复杂度o(1)

算法思想,将一个数插入到前面的有序数列中,关键问题就是找到插入点,从有序的最后一个元素与带插入的元素进行比较,直到找到带插入元素的插入点为止

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

/*************************
*插入排序 直接插入排序
*************************/

void main()
{
	int n;          //输入数组的长度
	printf("请输入数组的长度:\n");
	scanf("%d",&n);

	int *a = (int *)malloc(n*sizeof(int));
	srand(time(0));

	//初始化数组
	for(int i=0; i<n; i++)
	{
		a[i] = rand()%100;
	}

	//输出排序前的数组
	printf("\n");
	printf("输出排序前的数组:\n");
	for(i=0; i<n; i++)
	{
		printf("%d\t",a[i]);
	}

	//排序
	for(i=1; i<n; i++)
	{
		int temp = a[i];
		for(int j=i-1; j>=0; j--)
		{
			if(a[j] > temp)
			{
				a[j+1] = a[j];
			}
			else
			{
				a[++j] = temp;
				break;
			}
		}
		if(j < 0)
		{
			a[++j] = temp;
		}
	}

	//输出排序后的数组
	printf("\n");
	printf("输出排序后的数组:\n");
	for(i=0; i<n; i++)
	{
		printf("%d\t",a[i]);
	}

	free(a);
}

2.希尔排序

时间复杂度与选取增量有关,空间复杂度o(1) 

算法思想:首先选取增量d,每个相隔d个元素的进行排序,每次排序都会是相隔d个元素的数列成为有序数列,然后修改d的值,直到d=1时排出来的就是整个数组的有序数列   其中增量d的选取和变化对希尔排序的效率有很大影响。

实现代码如下:

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

/**************************
*希尔排序
*************************/
void main()
{
	int n; //数组长度
    int d; //增量

	printf("请输入数组的长度:\n");
	scanf("%d",&n);

	int *a = (int *)malloc(n*sizeof(int));

	//初始化数组
	srand(time(0));
	for(int i=0; i<n; i++)
	{
		a[i] = rand()%100;
	}

	//输出排序前的序列
	printf("\n");
    printf("输出排序前的数列:\n");
	for(i=0; i<n; i++)
	{
		printf("%d\t",a[i]);
	}

	//排序
	d=n/2;
	while(d >= 1)
	{
		for(i=0; i<d; i++)
		{
			for(int j=i+d; j<n; j+=d)
			{
				int temp = a[j];
				for(int k=j-d; k>=0; )
				{
					if(a[k] > temp)
					{
						a[k+d] = a[k];
						k-=d;
					}
					else
					{
						break;
					}
				}
				a[k+d] = temp;
			}
		}
		d=d/2;
	}

	//输出排序后的序列
	printf("\n");
    printf("输出排序后的数列:\n");
	for(i=0; i<n; i++)
	{
		printf("%d\t",a[i]);
	}

	free(a);

}

二.交换排序

交换排序的特点就是在每一次循环后都会有一个元素确定位置

1.冒泡排序

时间复杂度为o(n^2),空间复杂度为o(1)

算法思想:循环n-1次,每次循环把最大的或者最小的数放到最后或者最前段

代码如下:

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

/*************************
*交换排序 冒泡排序
*************************/

void main()
{
	int n;          //输入数组的长度
	printf("请输入数组的长度:\n");
	scanf("%d",&n);

	int count=n;
	int *a = (int *)malloc(n*sizeof(int));
	srand(time(0));

	//初始化数组
	for(int i=0; i<n; i++)
	{
		a[i] = rand()%100;
	}

	//输出排序前的数组
	printf("\n");
	printf("输出排序前的数组:\n");
	for(i=0; i<n; i++)
	{
		printf("%d\t",a[i]);
	}

	//排序 大的往后排
	for(i=n-1;i>0;i--)
	{
		for(int j=0; j<i; j++)
		{
			if(a[j] > a[j+1])
			{
				int temp = a[j];
				a[j] = a[j+1];
				a[j+1] =temp;
			}			
		}
		count--;
	}

	//输出排序后的数组
	printf("\n");
	printf("输出排序后的数组:\n");
	for(i=0; i<n; i++)
	{
		printf("%d\t",a[i]);
	}

	free(a);
}


2.快速排序

平均时间复杂度为o(nlogn),空间复杂度为o(logn) 是平均性能最好的排序算法

最坏的时间复杂度为o(n^2)

算法思想:找一个基准值,定义两个指针分别为头指针和尾指针,如果此基准值不是数组的第一个元素就要和数组的第一个元素进行交换,然后尾指针从后往前遍历找到第一小于等于基准的值放到头指针指向的地方,头指针+1,头指针再往前遍历找到一个大于等于基准的数放到尾指针所指的地方。反复执行直到头指针和尾指针相等结束。这样就将大的数组以基准为界分为了一边大于基准的一边小于基准的两部分。反复的循环最总得到有序序列。

实现代码如下:

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

void quick_sort(int a[], int start, int end)
{
	int front = start;
	int tail = end;
	int temp = a[start];  
	while(tail > front)
	{
		while(a[tail]>temp && tail>front)tail--;
		if(tail>front)
		{
			a[front++] = a[tail] ;
		}
        while(a[front]<temp && front<tail)front++;
		if(tail>front)
		{
			a[tail--]=a[front];
		}
	}
	a[front] = temp;
	if(front-1 > start)
	{
		quick_sort(a,start,front-1);
	}
	if(end > front+1)
	{
		quick_sort(a,front+1,end);
	}
}
/*********************************************************
*交换排序   快速排序
*********************************************************/
void main()
{
	int n; //数组的长度
	
	printf("请输入数组的长度:\n");
	scanf("%d",&n);

	//初始化数组
	int *a = (int *)malloc(n*sizeof(int));
	srand(time(0));
	for(int i=0; i<n; i++)
	{
		a[i] = rand()%10;
	}

	//输出排序前的数组
	printf("\n");
	printf("排序之前的数组:\n");
	for(i=0; i<n; i++)
	{
		printf("%d\t",a[i]);
	}

	//排序
	quick_sort(a,0,n-1);

	//输出排序后的数组
	printf("\n");
	printf("排序后的数组:\n");
	for(i=0; i<n; i++)
	{
		printf("%d\t",a[i]);
	}

	free(a);

}


三.选择排序

每次排序后都会确定一个元素的最终位置

1.直接选择排序

时间复杂度o(n^2)   空间复杂度o(1)

算法思想:选择当前位置及其后面的数组中最小的值与当前的值进行交换,执行n-1次数组就为有序

比较次数不会受到数据的影响。

实现代码如下:

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

/*****************************************
*选择排序   直接选择排序
*****************************************/
void main()
{
	int n;   //记录数组的个数

	printf("请输入数组的个数:\n");
	scanf("%d",&n);

	int *a = (int *)malloc(n*sizeof(int));
	
	//初始化数组
	srand(time(0));
	for(int i=0; i<n; i++)
	{
		a[i] = rand()%100;
	}

	//输出排序前的数组
	printf("\n");
	printf("输出排序前的数组:\n");
	for(i=0; i<n; i++)
	{
		printf("%d\t",a[i]);
	}

	//直接选择排序
	for(i=0; i<n-1; i++)
	{
		int min = i;
		for(int j=i+1; j<n; j++)
		{
			if(a[min] > a[j])
			{
				min = j;
			}
		}
		int temp = a[min];
		a[min] = a[i];
		a[i] = temp;
	}


	//输出排序后的数组
	printf("\n");
	printf("输出排序后的数组:\n");
	for(i=0; i<n; i++)
	{
		printf("%d\t",a[i]);
	}
	free(a);
}



 2.堆排序

时间复杂度为o(nlogn)  空间复杂度为o(1)

算法思想:如果按从小到大的顺序输出,就要建立大顶堆。每次输出前都要建堆,要熟悉完全二叉树的性质,这里不用0号单元,数组从1开始方便数组的处理。构建完大顶堆后,将a[1]与a[n]进行交换,这样就确定一个元素的最终位置。然后再构建堆知道堆的元素只有一个时结束。

在大数据时一般不用堆排序,因为时间复杂度虽然低,但是在堆的构建时确存在着大量的乘除运算。

实现代码如下:

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

/*******************************
*选择排序   堆排序
*为了方便完全二叉树的操作,0号不用
*******************************/
void main()
{
	int n; //数组的长度
	
	printf("请输入数组的长度:\n");
	scanf("%d",&n);

	//初始化数组
	int *a = (int *)malloc((n+1)*sizeof(int));
	srand(time(0));
	for(int i=0; i<n+1; i++)
	{
		a[i] = rand()%100;
	}

	//输出排序前的数组
	printf("\n");
	printf("排序之前的数组:\n");
	for(i=1; i<n+1; i++)
	{
		printf("%d\t",a[i]);
	}

	//排序
	int max;
	int count=n;
	while(count > 1)
	{//建立大顶堆

		for(i=count/2; i>=1; i--)
		{
			int j=i;
			while(2*j+1<=count)
			{//说明此节点有右孩子
				max=a[2*j]>a[2*j+1]?(2*j):(2*j+1);
				if(a[max] > a[j])
				{
					int temp = a[j];
					a[j] = a[max];
					a[max] = temp;
				}
				j*=2;
			}
			if(2*j<=count)
			{//只有左孩子
				if(a[j] < a[2*j])
				{
					int temp = a[i];
					a[j] = a[2*j];
					a[2*j] = temp;
				}
			}
		}

		//交换
		int temp = a[1];
		a[1] = a[count];
		a[count] = temp;
		count--;
	}

	//输出排序后的数组
	printf("\n");
	printf("排序后的数组:\n");
	for(i=1; i<n+1; i++)
	{
		printf("%d\t",a[i]);
	}

	free(a);

}


四. 归并排序

时间复杂度为0(nlogn)     空间复杂度o(n)

算法实现:归并排序需要一个辅助数组,先把每一个数据作为一个单位两两合并,然后再以两个元素作为一个单位两两合并,一次类推。

在代码实现过程中经常会忘记对最后一段(没有段和它一组)的处理。

实现代码如下:

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

void meger(int a[], int b[], int start, int mid, int end)
{
	int count = start;
	for(int i=start,j=mid; i<mid && j<end;)
	{
		if(a[i]>a[j] )
		{
			b[count++] = a[j++];
		}
		else
		{
			b[count++] = a[i++];
		}
	}
	while(i>=mid && j<end)
	{
		b[count++] = a[j++];
	}
	while(i<mid && j>=end)
	{
		b[count++] = a[i++];
	}
}

void copy(int a[], int b[], int n)
{
	for(int i=0; i<n; i++)
	{
		a[i] = b[i];
	}
}
/****************************************
*归并排序,d=2,d=4.......
****************************************/
void main()
{
	int n; //数组长度

	printf("请输入数组的长度:\n");
	scanf("%d",&n);

	//初始化数组
	int *a = (int *)malloc(n*sizeof(int));
	int *b = (int *)malloc(n*sizeof(int));
	srand(time(0));
	for(int i=0; i<n; i++)
	{
		a[i] = rand()%100;
	}

	//输出排序前的数组
	printf("\n");
	printf("输出排序前的数组:\n");
	for(i=0; i<n; i++)
	{
		printf("%d\t",a[i]);
	}

	//排序
	int d = 1;
	while(d < n)
	{
		for(i=0; i+2*d<n;i+=2*d)
		{
			meger(a,b,i,i+d,i+2*d);
		}
		if(i+d<n)
		{
			meger(a,b,i,i+d,n);
		}
		d=d*2;
		copy(a,b,n);
	}

	//输出排序后的数组
	printf("\n");
	printf("输出排序后的数组:\n");
	for(i=0; i<n; i++)
	{
		printf("%d\t",a[i]);
	}

	free(a);
	free(b);
}


 五.基数排序

时间复杂度为o(nlog(r)m)  空间复杂度为o(m*(n+1))

n为数组的个数,m为特征取值的范围  r为特征值的个数

算法思想:首先按最低位进行排序,然后按照次地位排序,一次类推

基数排序的要求比较严格。

代码实现如下:

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <time.h>
/***************************************
*根据位来获取位数
****************************************/
int getNum(int num, int pos)
{
	int temp=1;
	for(int i=0; i<pos-1; i++)
	{
		temp*=10;
	}
	return (num/temp)%10;
}
/****************************************
*基数排序
*使用条件比较严格,数据必须要有规律
****************************************/
void main()
{
	int n;  //数组的个数
    int m;  //数据位数
	printf("请输入数组的个数:\n");
	scanf("%d",&n);
	printf("请输入数据的位数:\n");
	scanf("%d",&m);

	//初始化数组
	srand(time(0));
	int *a = (int *)malloc(n*sizeof(int));
	int *b[10];   //十个序列空间
	for(int i=0; i<10; i++)
	{
		b[i] = (int *)malloc((n+1)*sizeof(int));    //a[i][0]代表第i个序列中数据的个数
		b[i][0] = 0;
	}
	int temp=1;
	for(i=0; i<m; i++)
	{
		temp*=10;
	}
	for( i=0; i<n; i++)
	{
		a[i] = rand()%temp;
	}

	//输出排序前的数组
	printf("\n输出排序前的数组:\n");
	for(i=0; i<n; i++)
	{
		printf("%d\t",a[i]);
	}

	//排序
    for(int pos=1; pos<=m; pos++)
	{
		for(int j=0; j<n; j++)
		{//分配到各个序列中
			int num=getNum(a[j],pos);
			int index = ++b[num][0];
			b[num][index]=a[j];
		}

		for(j=0,i=0; j<10; j++)
		{
			for(int k=1; k<=b[j][0]; k++)
			{
				a[i++]=b[j][k];
			}
			b[j][0]=0;
		}

	}
	//输出排序后的数组
	printf("\n输出排序后的数组:\n");
	for(i=0; i<n; i++)
	{
		printf("%d\t",a[i]);
	}
}


 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值