数据结构(十一)8种排序

1.直接插入排序

在这里插入图片描述
绿色是插入进去的元素,红色是未插入的的元素。
每插入进去一个数,都要用要插入的这个元素与前面插入的元素依次比较。比它大,就把要插入的元素位置覆盖,把要插入的元素放到前面一个元素的位置上,如果比它小,就在后面直接插入。

#include<stdio.h>
void InsertSort(int *a, int length)
{
	int i, j, tmp;
	for(i = 1; i < length; i++)		//因为10个数字,数组坐标的从0到9。 而第一个数不用排序。所以循环length - 2次数
	{
		tmp = a[i];  //记录插入的元素
		for(j = i - 1; j >= 0; j--) //因为j=i - 1是指前面剩下的元素,它要依次与要插入的元素比较
		{
			if(a[j] > tmp)  
			{
				a[j + 1] = a[j];   //如果前面的元素比要插入的这个元素大,就把前面的元素移动到这个插入元素的位置上
			}
			else  
			{
				break;  //如果比它小,就不执行,跳出这个循环,执行下面的命令。
			}
		}
		a[j + 1] = tmp;   //把记录的元素放进数组元素的下一位,就是已经比较过元素的后面。
	}
}

int main()
{
	int array[] = {32,45,65,12,56,76,56,12,84,23};
	int length = sizeof(array) / sizeof(array[0]);
	int i;
	for (i = 0; i < length; i++)
	{
		InsertSort(array,  length);
		printf("%d ", array[i]);
	}
	printf("\n");
	return 0;
}

2.希尔排序

在这里插入图片描述
在这里插入图片描述

#include<stdio.h>
void ShellSort(int *a, int length)
{
	int i, j, tmp, h;
	for(h = length / 2; h > 0; h = h / 2)  //定义增量,也就是步长的循环次数。 取数据的一半为最。
	{
		for(i = h; i < length; i++)  //定义循环次数,因为希尔排序需要通过步长进行比较。 
		{
			tmp = a[i];   //记录步长元素
			for(j = i - h; j >= 0; j = j -h) //步长元素比较的次数
			{
				if(a[j] > tmp)
				{
					a[j + h] = a[j];
				}
				else
				{
					break;
				}
			}
			a[j + h] = tmp;
		}
	}
}

int main()
{
	int array[] = {32,45,65,12,56,76,56,12,84,23};
	int length = sizeof(array) / sizeof(array[0]);
	int i;
	for (i = 0; i < length; i++)
	{
		ShellSort(array,  length);
		printf("%d ", array[i]);
	}
	printf("\n");
	return 0;
}

3.冒泡法排序

在这里插入图片描述

#include<stdio.h>

void maopaoSort(int *a, length)
{
	int i,j,tmp;
	for(i = 1; i < length ; i++) //循环总次数,找出最大的元素,根据冒泡法,最后一位冒出的数一定是最小的。
												不需要循环找寻。所以循环次数为length - 1 
	{
		for(j = 0; j < length -i -1; j++) // 依次比较元素,把大的放在后面
		{
			if(a[j] > a[j + 1])
			{
				tmp = a[j];
				a[j] = a[j+1];
				a[j+1] = tmp;
			}
		}
	}
}
int main()
{
	int array[] = {32,45,65,12,56,76,56,12,84,23};
	int length = sizeof(array) / sizeof(array[0]);
	int i;
	for (i = 0; i < length; i++)
	{
		maopaoSort(array,  length);
		printf("%d ", array[i]);
	}
	printf("\n");
	return 0;
}

4.快速排序

一个数组,选出一个分隔成(基数),把比基数小的放到右边,把比基数大的放到左边。
然后小的一部分和大的一部分又分为一个新数组,再从小的数组选出一个基数,在把小的这部分有分为更小的和较大的。在把这两部分分为两个新数组,在进行上面步骤。。。。
我们现在对(66,38,55,93,20,42,54,95,70,68)进行排序
首先我们定义三个量,i,j,flag(基数)。 i是数组第-一个值的下表即i=0。j是数组最后一个值的下表即j=9,flag就是数组的第一个值即flag=56,现在我们要做的就是讲这个数组中所有比基数小的数放到他的前面,把所有比flag大的数放到他的后面。

第一步从j开始向左(前)找,找到第一个比基数小的数,是下标为6的数54,我们就将54与基数66进行交换从而使数组变成
(54, 38,45, 93,20,42,66, 95, 70, 68) ,此时的j=6

第二步从i开始向右(后)找,找到第一个比基数大的数,是下标为3的数93,我们就将93-与基数66进行交换从而使数组变成
(54, 38,55,66,20,42,93,95,70,68),此时的i=3

第三步继续从j开始向左找 (此时j=6),找到比基数小的数,是下标为5的数42,我们将42与基数进行交换,
得到数组(54, 38,55,42,20,66, 93,95,70,68),此时j=5

第四步从i 开始向右找(此时i=3),找到比基数大的数,直到i=j, 我们发现在j之前已经找不到比基数更大的数,此时快速排序的第一轮就已经结束,这个时候在基数之前的数都是比他小的,在他之后都是比他大的,我们再将基数前后两片区域重新定义成新的两个无序的数组,分别对他们重复刚才的过程,直到分解到每个重新划分的区域内只有一个值(一个个体,分成的数组就只有一个元素),排序就算完成了。

#include<stdio.h>
void QuickSort(int *a, int low, int high) //low和high分别是这个数组的下标的头和尾。
{
	if(low >= high)
	{
		return;
	}
	int i = low;  //下标i的是小于基数的那一部分数,从数组下标从0往右
	int j = high; //下标j的是大于基数的那一部分数,从数组的下标从最后一位向左移动。
	int base = a[low]; //取基数,一般是找数组的第一个元素
	while(i < j)   //当i = j时,这个数组已经被分成两部分了
	{
		while(i < j && a[j] > base)  
		{
			j--;       //如果j位置的元素大于基数,那是正常的,只需下标j向左移动一位。接着找寻
		}
		if(i < j)
		{
			a[i++] = a[j];   //如果下标j的元素小于基数,就和基数交换位置
		}
		while(i < j && a[i] < base)   
		{
			i++;  //如果i位置的元素小于基数,那是正常的,只需下标i向右移动一位。接着找寻
		}
		if(i < j)
		{
			a[j--] = a[i]; //如果下标i的元素大于基数,就和基数交换位置
		}
	}
	QuickSort(a, low, i -1);      //分出的小数部分重新组成一个数组,在调用这个函数接着向下分。
	QuickSort(a, i + 1, high);   //分出的大数部分重新分成一个数组,在调用这个函数接着向下分。
}

int main()
{
	int array[] = {32,45,65,12,56,76,56,12,84,23};
	int length = sizeof(array) / sizeof(array[0]);
	int i;
	for (i = 0; i < length; i++)
	{
		QuickSort(array,  0, length - 1);
		printf("%d ", array[i]);
	}
	printf("\n");
	return 0;
}

5.简单选择排序。

对于给定的一组记录(一般取数组的第一个元素array[0]),记录它的下标的数据类容,然后依次比较大小,发现比它小的,记录下标,并且记录数据。经过第一轮比较后得到最小的记录,然后将记录与第一个记录的位置进行交换
接着对不包括第一个记录以外的其他记录进行第二轮排序,得到最小的记录并与第二个记录进行位置交换;
重负该过程,直到进行比较的记录只有一个为止。
在这里插入图片描述

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

void SelectSort(int *a, int length)
{
	int i, j, tmp, mIndex;  //(tmp是记录数据,mIndex是记录坐标)
	for(i = 0; i < length - 1; i++)
	{
		tmp = a[i];  //记录第一个元素的内容。
		mIndex = i; //记录第一个元素的下标。
		for(j = i + 1; j < length; j++)  //依次较大小,从第二个元素开始。
		{
			if(a[j] < tmp) 
			{
				mIndex = j;  //比它小,就更新下标
				tmp = a[j];  //比它小,就更新内容
			}
		}
		if(mIndex != i)
		{
			a[mIndex] = a[i];  //把最开始记录的小数赋予新的最小的数
			a[i] = tmp; // 在把这个最小的数放进第一个元素
		}
	}
}

int main()
{
	srand(time (NULL));
	int array[10] = {43,54,12,54,34,67,87,97,23,64};
	int i, length = sizeof(array) / sizeof(array[0]) ;
	for(i = 0; i < length; i++)
	{
		SelectSort(array, length);
		printf("%d ", array[i]);
	}
	printf("\n");
}

6.堆排序

      堆排序是一种特殊的树形数据结构,其每个节点都有一个值,通常提到的堆都是指一棵完全二叉树,根节点的值小于(或大于)两个子节点的值,同时根节点的两个子树也分别是一个堆。堆排序主要包括两个过程:一是构建堆, 二是交换堆顶元素与最后一个元素的位置。步骤:
  1. 将序列构造成一棵完全二叉树 ;
  2. 把这棵普通的完全二叉树改造成堆,便可获取最小值 ;
  3. 输出最小值 ;
  4. 删除根结点,继续改造剩余树成堆,便可获取次小值 ;
  5. 输出次小值 ;
  6. 重复改造,输出次次小值、次次次小值,直至所有结点均输出,便得到一个排序 。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void HeapAdjust(int *a, int root, int last)   //root表示根节点下标  last表示最后一个下标
{
	int i;
	int tmp = a[root];

	for (i = 2 * root + 1; i <= last; i = i * 2 + 1)
	{
		if (i + 1 <= last && a[i] < a[i + 1])   //找出两个数中的最大数
		{
			i++;
		}
		if (a[i] > tmp)
		{
			a[root] = a[i];    //用较大数覆盖根节点
			a[i] = tmp;
			tmp = a[i];
			root = i;
		}
		else
		{
			break;
		}

	}
}

void swap(int *x, int *y)
{
	int t = *x;
	*x = *y;
	*y = t;
}

void HeapSort(int *a, int length)
{
	int i;
	for (i = length / 2 - 1; i >= 0; i--)
	{
		HeapAdjust(a, i, length - 1);    //构建大顶堆
	}

	for (i = length - 1; i >= 1; i--)
	{
		swap(&a[0], &a[i]);
		HeapAdjust(a, 0, i - 1);
	}
}

int main()
{
	srand(time(NULL));
	//int array[10] = {4, 5, 3, 8, 0, 78, 5, 3, 9, 10};
	int array[2048] = {0};

	int i;
	for (i = 0; i < sizeof(array) / sizeof(array[0]); i++)
	{
		array[i] = rand() % 1000;
	}
	
	printf("开始排序\n");
	HeapSort(array, sizeof(array) / sizeof(array[0]));
	printf("排序结束\n");

	for (i = 0; i < sizeof(array) / sizeof(array[0]); i++)
	{
		printf("%d ", array[i]);
	}
	printf("\n");

	return 0;
}

7.归并排序

原理如下:对于给定的一组记录,首先将两个相邻的长度为1的子序列进行归并,得到n/2个长度为2或者1的有序子序列,在将其两两归并,反复执行此过程,直到得到一个有序的序列为止。
在这里插入图片描述
将这个数组分成一半,在尽量把左右数组弄成有序数组,又在分一半,直到左右都归并成有序数组。
归并操作:两个数组的第一个元素比较大小,小的放在原数组的第一个元素,接着又用两个数组的第一位元素接着比…
(相当于除了原数组,要重新建立两个数组)

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

void Merge(int *a, int start, int middle, int end)   //(数组,数组头下标,数组中间下标,数组尾下标)
{
	int left_length = middle - start + 1;   //左边的长度为中间下标减去头下标加1
	int right_length = end - middle;
	int *L = (int *)malloc(sizeof(int) * left_length);  //给左边申请连续的左长度的字节空间
	int *R = (int *)malloc(sizeof(int) * right_length);

	int k, i, j;    //k表示原数组下标   i表示L下标   j表示R下标

	for (k = start, i = 0; i < left_length; i++, k++) 
	{ 
		L[i] = a[k];   //把左边数组的元素放进申请的左边空间里
	} 

	for (k = middle + 1, j = 0; j < right_length; j++, k++)
	{
		R[j] = a[k]; //把右边的数组元素放进申请的右空间里
	}

	for (i = 0, j = 0, k = start; i < left_length && j < right_length; k++)
	{
		if (L[i] < R[j]) 
		{
			a[k] = L[i];
			i++;
		}
		else
		{
			a[k] = R[j];
			j++;
		}
	}
//如果左边或者右边的数组还有剩下的,直接放进去。
	for (; i < left_length; i++, k++)  
	{
		a[k] = L[i];
	}

	for (; j < right_length; j++, k++)
	{
		a[k] = R[j];
	}
}

void MergeSort(int *a, int start, int end)    //拆分  (数组,数组头的下标,数组尾的下标)
{
	if (start >= end)   //当头下标大于尾下标时,跳出这个循环(分成单一的个体时)
	{
		return;
	}

	int middle = (start + end) / 2; // 找出中间点
	MergeSort(a, start, middle); //把左边的数组接着拆分
	MergeSort(a, middle + 1, end);   //把右边的数组接着拆分

	Merge(a, start, middle, end); //归并操作
}

int main()
{
	srand(time(NULL));
	//int array[10] = {4, 5, 3, 8, 0, 78, 5, 3, 9, 10};
	int array[2048] = {0};

	int i;
	for (i = 0; i < sizeof(array) / sizeof(array[0]); i++)
	{
		array[i] = rand() % 1000;
	}
	
	printf("开始排序\n");
	MergeSort(array, 0, sizeof(array) / sizeof(array[0]) - 1);
	printf("排序结束\n");

	for (i = 0; i < sizeof(array) / sizeof(array[0]); i++)
	{
		printf("%d ", array[i]);
	}
	printf("\n");

	return 0;
}

8.基数排序

基数排序(Radix Sorting)是一种借助多关键字排序的思想对单逻辑关键字进行关系的方法。基数排序不需要进行记录关键字间的比较。
主要分为两个过程:
(1)分配,先从个位开始,根据位值(0-9)分别放到0~9号桶中(比如53,个位为3,则放入3号桶中)
(2)收集,再将放置在0~9号桶中的数据按顺序放到数组中
在这里插入图片描述
收集的新数组顺序从0-9号桶的里面的元素依次排序
再分别按顺序放进0-9号桶里

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

void RadixSort(int *a, int length)    //拆分
{
	int max = a[0], i, radix = 1;
	for (i = 1; i < length; i++)
	{
		if (a[i] > max)
			max = a[i];
	}

	int *tmp = (int *)malloc(sizeof(int) * length);

	while (max / radix != 0)
	{
		int bucket[10] = {0};
		for (i = 0; i < length; i++)             //获取每个元素的个位(十位。。。。)
		{
			tmp[i] = a[i] / radix % 10;     
			bucket[tmp[i]]++;                   //统计每个桶元素的个数
		}

		for (i = 1; i < length; i++)
		{
			bucket[i] += bucket[i - 1];
		}

		for (i = length - 1; i >= 0; i--)    //收集 把a[i]元素按顺序放在tmp数组中
		{
			tmp[bucket[a[i] / radix % 10] - 1] = a[i];
			bucket[a[i] / radix % 10]--;
		}

		for (i = 0; i < length; i++)
		{
			a[i] = tmp[i];
		}

		radix = radix * 10;
	}

	free(tmp);
}

int main()
{
	srand(time(NULL));
	//int array[10] = {4, 5, 3, 8, 0, 78, 5, 3, 9, 10};
	int array[2048] = {0};

	int i;
	for (i = 0; i < sizeof(array) / sizeof(array[0]); i++)
	{
		array[i] = rand() % 1000;
	}
	
	printf("开始排序\n");
	RadixSort(array, sizeof(array) / sizeof(array[0]));
	printf("排序结束\n");

	for (i = 0; i < sizeof(array) / sizeof(array[0]); i++)
	{
		printf("%d ", array[i]);
	}
	printf("\n");

	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值