六大排序算法

文章目录

  • 1. 冒泡排序
  • 2. 选择排序
  • 3. 插入排序
  • 4. 希尔排序
  • 5. 归并排序
  • 6. 快速排序

下面介绍几种排序算法,C语言中qsort虽然可以排序,但还是了解了解内部构造比较好。

1. 冒泡排序

冒泡排序是我最开始学习C语言时候,第一个接触的排序算法,说实话,第一次写出来的时候,感觉是很神奇的,但是第二天又忘了,也是真的很痛苦。
六大排序算法_第1张图片

  • j 从 i + 1的位置遍历数组,将最小的哪一个数据和 nums[i]交换即可。
//冒泡排序
void BubbleSort1(int* nums, int numsSize)
{
	int i, j,count = 0;
	for (i = 0; i < numsSize - 1; i++)
	{
		for (j = i + 1; j < numsSize; j++)
		{
			if (nums[i] > nums[j])
			{
				count++;
				Swap(&nums[i], &nums[j]);
			}
		}
	}
	printf("BubbleSort1排序结束: count = %d 结果如下", count);
	PrintNums(nums, numsSize);
}

上面是我在学习C语言中第一次学习冒泡排序时候别人教的,但是看上面那张图,
六大排序算法_第2张图片

  • 2本来就那么小,但是经过一次遍历,位置都没动,而下面的3就更离谱了,它竟然被移动到了最后。
  • 而解决这个问题的办法就是,j从后往前遍历,使nums[j] = Max(nums[j],nums[j - 1]);
  • 这样一来,就可以做到,每一次的用j遍历数组时候,会将大的永远靠后,小的永远靠前。
void BubbleSort2(int* nums, int numsSize)
{
	int i, j, count = 0;
	for (i = 0; i < numsSize - 1; i++)
	{
		for (j = numsSize - 1; j > i; j--)
		{
			if (nums[j - 1] > nums[j])
			{
				count++;
				Swap(&nums[j-1], &nums[j]);
			}
		}
	}
	printf("BubbleSort2排序结束: count = %d 结果如下", count);
	PrintNums(nums, numsSize);
}

冒泡排序的时间复杂度还是O(n^2)

2. 选择排序

选择排序,顾名思义就是靠选择来排序嘛。

  • i 还是从 0 索引处开始,一点点的向后改变
  • 而 j 的话还是和冒泡排序一样,从 i + 1 的位置开始,遍历一遍数组,而不一样的是,它不用去来回的交换数据,它只需要选择出那个最小就好了。
  • 选出来后将其与nums[i]进行交换即可。

    代码如下:
//选择排序
void SelectionSort(int* nums, int numsSize)
{
	int i,j,count = 0;
	for (i = 0; i < numsSize - 1; i++)
	{
		int minIndex = 0;
		for (j = i + 1; j < numsSize; j++)
		{
			//选择最小的出来
			if (nums[j] < nums[minIndex])
			{
				minIndex = j;
			}
		}
		if (i != minIndex)
		{
			//交换最小的
			Swap(&nums[i], &nums[minIndex]);
			count++;
		}
	}
	printf("SelectionSort 排序结束: count = %d 结果如下", count);
	PrintNums(nums, numsSize);
}

六大排序算法_第3张图片

而它的交换次数相比于冒泡排序减少了很多次,优化了不少。
但是其时间复杂度还是O(n^2)

3. 插入排序

  • 默认索引0的位置已经排好,然后i从1的索引处开始,判断 i 是否比前一个小,
  • 如果小的话,将nums[i] 利用一个tmp来存储,然后将将比tmp大的数,全部向后挪动,
  • 直到找到合适的位置后,就停下来,插入即可
    六大排序算法_第4张图片
//插入排序
void InserctionSort(int* nums, int numsSize)
{
	int i, j;
	//i 从 1索引处开始,默认 0处已经排好了
	for (i = 1; i < numsSize; i++)
	{
		//当前的数据,比前面小
		if (nums[i] < nums[i - 1])
		{
			int tmp = nums[i];
			//挪动数据
			for (j = i - 1; nums[j] > tmp; j--)
			{
				nums[j + 1] = nums[j];
			}
			//找到合适的位置了
			nums[j + 1] = tmp;
		}
	}
	printf("InserctionSort 排序结束 结果如下");
	PrintNums(nums, numsSize);
}

4. 希尔排序

希尔排序我个人认为它就是插入排序的进阶版,而它是怎样去执行的,它是以一个区间一个区间去排序的。

下面是第一层循环的图片:当前的 区间增量是 4,然后区间增量会是一个这样的变化过程。
9/2 = 4(第一次) 4/2 = 2(第二次) 2/2 = 1(最后一次)
那么最后一次时候增量是1,它不就变成了上面刚刚说过的插入排序嘛?
所以前面的其实也是插入排序,不过就是有间隔的插入排序而已

看下图的比较,将incremen 变成1 不久和插入排序一样了吗?
六大排序算法_第5张图片
下面是代码。

void ShellSort(int* nums, int numsSize)
{
	int increment = numsSize;
	while (increment > 1)
	{
		increment /= 2;
		int i, j, tmp, end;
		for (i = 0, j = i + increment; j < numsSize; i++, j++)
		{
			tmp = nums[j];
			for (end = i; end >= 0 && nums[end] > tmp; end -= increment)
			{
				nums[end + increment] = nums[end];
			}
			nums[end + increment] = tmp;
		}
	}## 标题
	printf("ShellSort 排序结束 结果如下");
	PrintNums(nums, numsSize);

}

其时间复杂度是O(n^(3/2))d

5. 归并排序

归并排序的话充分的利用分治的思想,这个东西是递归,文字实在是不好太好表达。

  • 收件就是利用二分的原理,将要排序的区间越来越小,直到left == right(此时只有一个元素)
  • 当数组有两个以上的数据时候,给数组进行排序,需要先利用一个tmp数组来存放拍好序的序列。
  • 然后再拷贝回去。要注意拷贝时候的其实位置应该是从left开始。
  • 然后一只递归下去就好。

代码如下:

void Merge(int* nums, int* tmpArr, int left, int mid, int right)
{
	int i = left, j = mid+1, k = left; //i 代表mid左边的数组下标 j代表 mid 右边的数组下标, k则代表数组的开始位置,已经tmp数组的下标
	//将有序序列纳入tmp数组
	while (i < mid + 1 && j <= right)
	{
		if (nums[i] < nums[j])
		{
			tmpArr[k++] = nums[i++];
		}
		else
		{
			tmpArr[k++] = nums[j++];
		}
	}
	//判断是否全部纳入
	while (i < mid + 1)
	{
		tmpArr[k++] = nums[i++];
	}
	while (j <= right)
	{
		tmpArr[k++] = nums[j++];
	}

	//最后再拷贝回去
	for (i = left; i < k; i++)
	{
		nums[i] = tmpArr[i];
	}

}


void Msort(int* nums, int* tmpArr, int left, int right)
{
	//数组中只有一个元素
	if (left == right)
	{
		return;
	}
	int mid = (left + right) / 2;
	Msort(nums, tmpArr, left, mid);
	Msort(nums, tmpArr, mid + 1, right);
	Merge(nums,tmpArr,left,mid,right);
}
void MergeSort(int* nums, int numsSize)
{
	int* tmpArr = (int*)malloc(sizeof(int) & numsSize);
	Msort(nums, tmpArr, 0, numsSize - 1);
	printf("MergeSort 排序结束 结果如下");
	PrintNums(nums, numsSize);
}

其时间复杂度是O(n * logn)

6. 快速排序

快速排序和前面的归并排序同样也是需要递归来实现的,在C语言中的qsort库函数就是快速排序。

  • 首先确立一个key,一般是左边的第一个,或者右边的第一个都行,只是遍历的顺序不一样而已。
  • 然后利用两个指针,left和right分别取找大值于小值
  • right 先走, 当nums[right] < nums[key]的时候停下来(找小值)
  • 找到之后left再取走,当nums[left] > num[key] 时候停下来(找大值)
  • 然后去交换他俩,交换完成后重复上面的过程,直到left == right时候。
  • 将nums[key] 和 nums[right(left)]交换
  • 此时,左边全部小于key 右边全部大于key。
  • 然后将左右两边分别用快排即可[begin,key - 1] [key + 1, end];
    下面是代码:
void QSort(int* nums, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	int key = begin, left = begin, right = end;
	while (left < right)
	{
		//找小的
		while (left < right && nums[key] <= nums[right])
		{
			right--;
		}
		 
		//找大的
		while (left < right && nums[left] <= nums[key])
		{
			left++;
		}

		//交换两者
		Swap(&nums[left], &nums[right]);
	}
	//于key进行交换
	Swap(&nums[key], &nums[left]);
	key = left;
	//交换后,此时key左边的全部小于key右边的
	QSort(nums, begin, key - 1);
	QSort(nums, key+1, end);
}


void QuickSort(int* nums, int numsSize)
{

	QSort(nums, 0, numsSize - 1);
	printf("QuickSort 排序结束 结果如下");
	PrintNums(nums, numsSize);
}

其时间复杂度是O(n * logn)

你可能感兴趣的:(排序算法,算法,数据结构,c语言)