常用排序算法

前言:常用的排序算法主要包括冒泡排序、选择排序、插入排序、快速排序、希尔排序和归并排序


目录

一、冒泡排序

二、选择排序

三、插入排序

四、快速排序

五、希尔排序

六、归并排序

总结


一、冒泡排序

冒泡排序是排序算法中最为简单的排序之一,其思想就像水泡从水底一步一步冒到最上层,不断通过比较和交换来把小的数放到最前面。举个例子,对无序序列8,9,3,1,4,5进行冒泡排序

  1. 首先5和4作比较,由于4比5小,所以不用交换(8,9,3,1,4,5);4和1比较,由于1比4小,还是不用交换(8,9,3,1,4,5);1和3比较,由于1比3小,所以要交换(8,9,1,3,4,5);1和9比较(8,9,1,3,4,5);1和8比较(1,8,9,3,4,5)。第一轮比较完后结果为(1,8,9,3,4,5)。
  2. 同理进行第二轮比较,结果为(1,3,8,9,4,5)
  3. 第三轮结果为(1,3,4,8,9,5)
  4. 第四轮结果为(1,3,4,5,8,9)
  5. 第五轮结果为(1,3,4,5,8,9)

代码实现:

#include <stdio.h>

static void swap(int *arr, int i, int j)
{
	int temp = arr[i];
	arr[i] = arr[j];
	arr[j] = temp;
}

static void bubble(int *arr, int size)
{
	int i = 0, j = 0;
	for (i = 0; i < size - 1; i++)
	{
		for (j = size - 1; j > i; j--)
		{
			if (arr[j] < arr[j - 1])
			{
				swap(arr, j, j -1);
			}
		}
	}
}

int main(int argc, char **argv)
{
	int i = 0;
	int arr[] = {8,9,3,1,4,5};
	int size = sizeof(arr)/sizeof(arr[0]);
	
	bubble(arr, size);

	printf("result is ");
	for (i = 0; i < size; i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\r\n");
	
	return 0;
}


二、选择排序

选择排序和冒泡排序比较接近,只是选择排序每次选择一个最小的值然后放到第一位,比冒泡好的地方就是减少了交换次数。举个例子,对无序序列8,9,3,1,4,5进行选择排序

  1. 第一轮选择一个最小值1,和8交换,结果为(1,9,3,8,4,5)
  2. 第二轮选择一个最小值3,和9交换,结果为(1,3,9,8,4,5)
  3. 第三轮选择一个最小值4,和9交换,结果为(1,3,4,8,9,5)
  4. 第四轮选择一个最小值5,和8交换,结果为(1,3,4,5,9,8)
  5. 第五轮选择一个最小值8,和9交换,结果为(1,3,4,5,8,9)

代码实现:

#include <stdio.h>

static void swap(int *arr, int i, int j)
{
	int temp = arr[i];
	arr[i] = arr[j];
	arr[j] = temp;
}

static void select(int *arr, int size)
{
	int i = 0, j = 0;
	for (i = 0; i < size - 1; i++)
	{
		int min_idx = i;
		for (j = i + 1; j < size; j++)
		{
			if (arr[j] < arr[min_idx])
			{
				min_idx = j;
			}
		}
		if (min_idx != i)
		{
			swap(arr, i, min_idx);
		}
	}
}

int main(int argc, char **argv)
{
	int i = 0;
	int arr[] = {8,9,3,1,4,5};
	int size = sizeof(arr)/sizeof(arr[0]);
	
	select(arr, size);

	printf("result is ");
	for (i = 0; i < size; i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\r\n");
	
	return 0;
}

三、插入排序

插入排序类似对扑克牌进行排序,开始是会从第二张牌往前面找,找到可以插入的位置进行插入,然后拿第三张牌进行插入,同理第四张、第五张...。举个例子,对无序序列8,9,3,1,4,5进行插入排序

  1. 第一轮选择9作为需要插入的牌,往前找可以插入的地方,发现前面的8比自己小,所以不需要插入,结果为(8,9,3,1,4,5)
  2. 第二轮选择3作为需要插入的牌,往前找可以插入的地方,发现前面的8和9都比自己大,所以插到最前面,结果为(3,8,9,1,4,5)
  3. 第三轮选择1作为需要插入的牌,同理结果为(1,3,8,9,4,5)
  4. 第四轮选择4作为需要插入的牌,同理结果为(1,3,4,8,9,5)
  5. 第五轮选择5作为需要插入的牌,同理结果为(1,3,4,5,8,9)

代码实现:

#include <stdio.h>

static void insert(int *arr, int size)
{
	int i = 0, j = 0;
	for (i = 1; i < size; i++)
	{
		int wait_insert = arr[i];
		int j = i;
		while (j > 0 && (wait_insert < arr[j - 1]))
		{
			arr[j] = arr[j - 1];
			j--;
		}
		
		if (j != i)
		{
			arr[j] = wait_insert;
		}
	}
}

int main(int argc, char **argv)
{
	int i = 0;
	int arr[] = {8,9,3,1,4,5};
	int size = sizeof(arr)/sizeof(arr[0]);
	
	insert(arr, size);

	printf("result is ");
	for (i = 0; i < size; i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\r\n");
	
	return 0;
}

四、快速排序

快速排序在实际应用中是表现最好的排序算法,快速排序首先会选择一个基准数,一般是第一个元素,然后左边和右边一起往中间搜索

  1. 首先右指针往左边搜索,当遇到比基准数小时,停止搜索
  2. 左指针往右边搜索,当发现有比基准数大的,停止搜索
  3. 然后把左边的值和右边的值交换。
  4. 然后重读1,2,3。直到左右指针相等,然后把当前值和基准值交换。
  5. 进过上面步骤,就把序列以基准数分成了两部分,然后再把左右部分再进行快速排序(递归)
  6. 最终完成排序。

举个例子,对无序序列8,9,3,1,4,5进行快速排序

第一轮(循环上面的1,2,3):(8,9,3,1,4,5)->(8,5,3,1,4,9)->(4,5,3,1,8,9)

第二轮把序列分成(4,5,3,1)和(9),再对这两个序列进行快速排序(4,5,3,1)->(4,1,3,5)->(3,1,4,5)

...

代码实现:

#include <stdio.h>

static void swap(int *arr, int i, int j)
{
	int temp = arr[i];
	arr[i] = arr[j];
	arr[j] = temp;
}

static int part(int *arr, int left, int right)
{
	int base = arr[left];
	int base_idx = left;

	while(left < right)
	{
		while ((left < right) && (arr[right] >= base))
		{
			right--;
		}
		while ((left < right) && (arr[left] <= base))
		{
			left++;
		}
		swap(arr, left, right);
	}
	swap(arr, base_idx, left);

	return left;
}

static void sort(int *arr, int left, int right)
{
	if (left >= right)
	{
		return;
	}

	int pos = part(arr, left, right);
	sort(arr, left, pos - 1);
	sort(arr, pos + 1, right);
}

static void quick(int *arr, int size)
{
	sort(arr, 0, size - 1);
}


int main(int argc, char **argv)
{
	int i = 0;
	int arr[] = {8,9,3,1,4,5};
	int size = sizeof(arr)/sizeof(arr[0]);
	
	quick(arr, size);

	printf("result is ");
	for (i = 0; i < size; i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\r\n");
	
	return 0;
}

五、希尔排序

希尔排序其实是插入排序的一种高效率体现,简单的插入排序中,如果序列是基本有序的,使用直接插入排序效率会很高,希尔排序实际就是利用这个特点,首先是待排序序列分割成若干子序列分别进行直接插入排序,使得整个序列基本有序,然后再对全体记录进行一次直接插入排序。

 

代码实现:

#include <stdio.h>

static void sort(int *arr, int size, int d)
{
	int i = 0;
	for (i = d; i < size; i++)
	{
		int wait_insert = arr[i];
		int j = i - d;

		while ((j >= 0) && (arr[j] > wait_insert))
		{
			arr[j + d] = arr[j];
			j -= d;
		}
		if (j != (i - d))
		{
			arr[j + d] = wait_insert;
		}
	}
}

static void shell(int *arr, int size)
{
	int d = size / 2;

	while (d >= 1)
	{
		sort(arr, size, d);
		d /= 2;
	}
}

int main(int argc, char **argv)
{
	int i = 0;
	int arr[] = {23,64,24,12,9,16,53,57,71,79,87,97};
	int size = sizeof(arr)/sizeof(arr[0]);
	
	shell(arr, size);

	printf("result is ");
	for (i = 0; i < size; i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\r\n");
	
	return 0;
}

六、归并排序

归并排序首先将无序序列进行划分,不可分割后就行排序重组,就是两两合并,然后四四合并,...最终成为有序序列。举个例子,对无序序列(23,64,24,12,9,16,53,57,71,79,87,97)进行合并排序。

如下图所示:

代码实现:

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

static void sort(int *arr, int left, int mid, int right)
{
	
	int i = left;
	int j = mid + 1;
	int k = 0;
	int *temp = (int *)malloc((right - left + 1) * sizeof(int));
	if (NULL == temp)
	{
		return;
	}

	memset(temp, 0, (right - left + 1) * sizeof(int));
	
	while ((i <= mid) && (j <= right))
	{
		if (arr[i] <= arr[j])
		{
			temp[k++] = arr[i++];
		}
		else
		{
			temp[k++] = arr[j++];
		}
	}

	while (i <= mid)
	{
		temp[k++] = arr[i++];
	}
	while (j <= right)
	{
		temp[k++] = arr[j++];
	}

	for (k = 0; k < (right - left + 1); k++)
	{
		arr[left + k] = temp[k];
	}

	free(temp);
}

static void part(int *arr, int left, int right)
{
	if (left >= right)
	{
		return;
	}

	int mid = (left + right)/ 2;

	part(arr, left, mid);
	part(arr, mid + 1, right);

	sort(arr, left, mid, right);
}

static void merge(int *arr, int size)
{
	part(arr, 0, size - 1);
}

int main(int argc, char **argv)
{
	int i = 0;
	int arr[] = {23,64,24,12,9,16,53,57,71,79,87,97};
	int size = sizeof(arr)/sizeof(arr[0]);
	
	merge(arr, size);

	printf("result is ");
	for (i = 0; i < size; i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\r\n");
	
	return 0;
}


总结

下面总结一下各排序的复杂度,如下图所示

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值