数据结构之排序(C语言实现)

本文详细介绍了排序的基本概念,包括稳定性、内部排序和外部排序的区别,以及常见的插入排序、选择排序、冒泡排序、快速排序、归并排序和非比较排序如计数排序。同时对各算法的复杂度和稳定性进行了分析。
摘要由CSDN通过智能技术生成

一、排序的概念以及常用排序

1.1 排序中的一些重要概念

  • 排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
  • 稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
  • 内部排序:数据元素全部放在内存中的排序。
  • 外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。
     

1.2 常用的排序算法

接下来我会详细的介绍这几种排序。

二、常见的排序算法

2.1 插入排序

       插入排序的大体思路是在有序序列末尾插入数据,然后向前比较调整位置,使得插入后的序列变为有序序列。

       代码实现如下:

void InsertSort(int* a, int n)
{
	int i;
	for (i = 1; i < n; i++)
	{
		int end = i - 1;
		int temp = a[i];
		while (end >= 0)
		{
			if (a[end] > temp)
			{
				a[end + 1] = a[end];
				end--;
			}
			else
				break;
		}
		a[end+1] = temp;
	}
}

 2.2 选择排序

       选择排序的思路比较简单 ,每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。

       代码实现如下:

void SelectSort(int* arr, int size)
{
	int i = 0;
    for (i = 0; i < size-1; i++)
    {
        int min = i;
        int j = 0;
        for (j = i+1; j < size; j++)
        {
            if (arr[j] < arr[min])
            {
                min = j;
            }
        }
        Swap(&arr[i], &arr[min]);
    }
}

 2.3 交换排序

(1)冒泡排序

       冒泡排序是一种很经典的排序方法 ,其思路也很简单,就是创建一个二重循环每次把最小(最大)的那个元素排到最后去。

       实现代码如下:

void BubbleSort(int* a, int n)
{
	int i, j;
	int flag = 0;
	for (i = 0; i < n; i++)
	{
		flag = 0;
		for (j = 0; j < n - i - 1; j++)
		{
			if (a[j] > a[j + 1])
			{
				Swap(&a[j], &a[j + 1]);
				flag = 1;
			}
		}
		if (flag == 0)
		{
			break;
		}
	}
}

  (2)快速排序

       快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。
        实现代码如下:

int getminIndex(int* arr,int left,int right)
{
	int mid = (left + right) / 2;
	if (arr[left] > arr[mid])
	{
		if (arr[left] < arr[right])
		{
			return left;
		}
		else
		{
			if (arr[right] > arr[mid])
			{
				return right;
			}
			else
				return mid;
		}
	}
	else
	{
		if (arr[right] > arr[mid])
		{
			return mid;
		}
		else
		{
			if (arr[right] > arr[left])
				return right;
			else
				return left;
		}
	}
}
int Sort(int* arr,int left,int right)
{
	int index = getminIndex(arr, left, right);
	Swap(&arr[left], &arr[index]);
	int key = arr[left];
	int keyi = left;
	while (left<right)
	{
		while (arr[right] >= key && right > left)
		{
			right--;
		}
		while (arr[left] <= key && left < right)
		{
			left++;
		}
		Swap(&arr[left], &arr[right]);
	}
	Swap(&arr[keyi], &arr[left]);
	return left;
}
//挖坑法
int Sort2(int* arr, int left, int right)
{
	int index = getminIndex(arr, left, right);
	Swap(&arr[left], &arr[index]);
	int key = arr[left];
	int hole = left;
	while (left < right)
	{
		while (arr[right] >= key && right > left)
		{
			right--;
		}
		arr[hole] = arr[right];
		hole = right;
		while (arr[left] <= key && left < right)
		{
			left++;
		} 
		arr[hole] = arr[left];
		hole = left;
	}
	arr[hole] = key;
	return hole;
}
// 快速排序前后指针法
int Sort3(int* arr,int left,int right)
{
	int index = getminIndex(arr, left, right);
	Swap(&arr[left], &arr[index]);
	int key = arr[left];
	int pre = left;
	int cur = left+1;
	while (cur <= right)
	{
		if (arr[cur] < key)
		{
			pre++;
			Swap(&arr[pre], &arr[cur]);
		}
		cur++;
 
 
	}
	Swap(&arr[left], &arr[pre]);
	return pre;
}
 
 
void quickSort(int* arr,int begin,int end)
{
	if (begin >= end)
		return;
	int keyi = Sort3(arr, begin, end);
 	quickSort(arr, begin, keyi - 1);
	quickSort(arr, keyi + 1, end);
}

2.4 归并排序

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序核心步骤:

实现代码如下:

void MergeSort(int* a, int* tmp, int begin, int end)
{
	if (begin >= end)
		return;
	int mid = (begin + end) / 2;
	MergeSort(a, tmp, begin, mid);
	MergeSort(a, tmp, mid + 1, end);
	int begin1 = begin;
	int begin2 = mid+1;
	int len = 0;
	while (begin1 <= mid && begin2 <= end)
	{
		if (a[begin1] <= a[begin2])
		{
			tmp[len++] = a[begin1++];
		}
		else
		{
			tmp[len++] = a[begin2++];
		}
	}
	while (begin1 <= mid)
	{
		tmp[len++] = a[begin1++];
	}
	while (begin2 <= end)
	{
		tmp[len++] = a[begin2++];
	}
	memcpy(a + begin, tmp, sizeof(int)*(end-begin+1));
}

2.5 非比较排序

      (1)计数排序

       计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。 实现方法为先统计相同元素出现次数再根据统计的结果将序列回收到原来的序列中。

       代码实现如下:

void CountSort(int* a, int n)
{
	int min = 0, max = 0;
	for (int i = 0; i < n; i++)
	{
		if (i == 0)
		{
			min = a[i];
			max = a[i];
		}
		else
		{
			if (a[i] > max)
				max = a[i];
			if (a[i] < min)
				min = a[i];
		}
	}
	int* tmp = (int*)malloc(sizeof(int) * (max - min+1));
	for (int i = 0; i < max - min + 1; i++)
	{
		tmp[i] = 0;
	}
	for (int i = 0; i < n; i++)
	{
		tmp[a[i] - min]++;
	}
	int k = 0;
	for (int i = 0; i < max-min+1; i++)
	{
		while (tmp[i])
		{
			a[k++] = i + min;
			tmp[i]--;
		}
	}
}

三、排序算法复杂度及稳定性分析

  • 15
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值