【数据结构---28】简单排序方法(上)

直接插入排序:

像打扑克牌一样,将要插入的元素与之前排好序的元素比较

<1>找出合适的插入位置,将其他元素向后搬移
<2>将要插入的元素插入

代码实现:

void insertSort(int* array, int size)
{
	 for (int i = 1; i < size; ++i)
	 {
		  int key = array[i];
		  int end = i - 1;
		  
		  while (key < array[end] && end >= 0)
		  {
			   array[end + 1] = array[end];
			   end--;
		  }
		  array[end + 1] = key;
	 }
}

希尔排序:

希尔排序是对直接插入排序的优化,又被称为缩小增量排序法
使用的也是插入排序的思想,但是gap>1时都是预排序
适用于大量且无序的数据,使用分组的方法来减少元素个数,对每一组进行排序

<1>将相同间隔的元素放在一组
<2>逐个取元素,比较的时候跳过gap个元素
<3>插入的时候也是插入到这个元素的gap位置后
<4>大佬计算得出的gap取值最好是gap/3+1,跳出条件与直接插入排序的gap>0不同,应该是gap>1

代码实现:

void shellSort(int* array, int size)
{
	 int gap = size;
	 
	 while (gap > 1)
	 {
		  gap = gap / 3 + 1;
		  
		  for (int i = gap; i < size; ++i)
		  {
			   int key = array[i];
			   int end = i - gap;
			   
			   while (key < array[end] && end >= 0)
			   {
				    array[end + gap] = array[end];
				    end -= gap;
			   }
			   
			   array[end + gap] = key;
		  }
		  
	  //gap--;
	 }
}

选择排序:

首先找出最大元素的下标,然后与最后一个元素交换,中间跳过元素所以是不稳定排序
缺陷是进行重复比较

<1>已经遍历过多少趟就代表j可以选取的元素少多少个,所以j取值小于size-i
<2>同理,最后把选取出来的元素放的位置的下标也是size-1的基础上减去i

代码实现:

void swap(int* a, int* b)
{
	 int tmp = *a;
	 *a = *b;
	 *b = tmp;
}

void selectSort(int* array, int size)
{
	 for (int i = 0; i < size - 1; ++i)
	 {
		  int maxPos = 0;
		  
		  for (int j = 1; j < size-i; ++j)
		  {
			   if (array[j]>array[maxPos])
			   {
				    maxPos = j;
			   }
		  }
		  
		  if (maxPos != size - i - 1)
		  {
			   swap(&array[maxPos], &array[size - i - 1]);
		  }
	 }
}

前后同时选择排序:

对选择的排序的简单优化,理论上可以使排序更快
一前一后的进行选择元素,选出最大的元素和end位置元素交换,选出最小的元素和begin位置元素交换

<1>如果找出的最大元素的下标已经在end位置就不用交换
<2>如果找出的最小元素的下标已经在begin位置就不用交换
<2>小元素如果刚好在end的位置,maxpos和end交换过之后,minpos的位置变到maxpos位置

代码实现:

void selectSort2(int* array, int size)
{
	 for (int i = 0; i < size - 1; ++i)
	 {
		  int begin = 0;
		  int end = size - 1;
		  
		  while (begin < end)
		  {
			   int maxPos = begin;
			   int minPos = begin;
			   int index = begin + 1;
			   
			   while (index <= end)
			   {
				    if (array[index]>array[maxPos])
				    {
					     maxPos = index;
				    }
				    if (array[index] < array[minPos])
				    {
					     minPos = index;
				    }
				    ++index;
			   }
			   
			   if (maxPos != end)
			   {
				    swap(&array[maxPos], &array[end]);
			   }
			   
			   //小元素如果刚好在end的位置,maxpos和end交换过之后,minpos的位置变到maxpos位置
			   if (minPos == end)
			   {
				    minPos = maxPos;
			   }
			   
			   if (minPos != begin)
			   {
				    swap(&array[minPos], &array[begin]);
			   }
			   
			   begin++;
			   end--;
		  }
	 }
}

堆排:

void HeapAdjust(int* array, int size, int parent)
{
	 int child = parent * 2 + 1; 
	 
	 while (child < size) 
	 {  
		  // 找左右孩子中较大的孩子  
		  if (child + 1 < size && array[child + 1] > array[child])
		  {
			   child += 1;
		  }
		  
		  if (array[child] > array[parent])  
		  {  
			   Swap(&array[child], &array[parent]); 
			   parent = child;   
			   child = parent * 2 + 1;  
		  } 
		  else 
		  {   
			   return; 
		  } 
	 }
} 

void HeapSort(int* array, int size)
{ 
	 //建堆 
	 int root = ((size - 1) >> 1);
	 
	 for (root; root >= 0; --root) 
	 {  
		  HeapAdjust(array, size, root); 
	 } 
	 
	 //排序
	 int end = size - 1; 
	 while (end != 0) 
	 {  
		  swap(&array[0], &array[end]); 
		  HeapAdjust(array, end, 0); 
		  end--; 
	 }
}

冒泡排序:

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

快速排序基准值分割的三种方法:

方法一:

<1>设定一个基准值,为了方便起见,设为最后一个元素
<2>采用两个指针(元素下标)的方式,从前往后找比基准值大的元素,从后往前找比基准值小的元素
<3>找到之后将两个位置的元素互换
<4>极端情况是一开始找的基准值就是整个数据中最大的或者最小的,所以begin与end不相等时交换
<5>基准值最大的情况,begin与end相等,基准值最小的情况,end与begin相等
<6>最后放置基准值时必须与right-1位置的元素交换,不能与K交换,与K交换的话,righ-1位置的元素不变

int partion1(int* array, int left, int right)
{
	 int key = array[right - 1];
	 int begin = left;
	 int end = right-1;
	 
	 while (begin < end)
	 {
		  while (array[begin] <= key && begin < end)
		  {
			   begin++;
		  }
		  while (array[end] >= key && begin < end)
		  {
			   end--;
		  }
		  
		  if (begin != end)
		  {
			   swap(&array[begin], &array[end]);
		  }
	 }
	 
	 //放好基准值
	 //这里必须和right-1比较,因为end是会动的
	 if (begin != right-1)
	 {
		  swap(&array[begin], &array[right-1]);
	 }
	 return begin;
}

方法二:

<1>与方法一类似,一个从前往后找比基准值大的元素,另一个从后往前找比基准值小的元素
<2>begin<end表示还有元素,如果不满足这个条件说明找完整个数据也没找到
<3>找到比基准值大的元素就填充到end位置,然后end自减
<4>找到比基准值小的元素就填充到begin位置,然后begin自增
<5>最后把基准值插入到begin或者end的位置都行,因为那时begin和end相等

int partion2(int* array, int left, int right)
{
	 int key = array[right - 1];
	 int begin= left;
	 int end = right - 1;
	 
	 while (begin < end)
	 {
		  //从前往后找比基准值大的元素
		  while (array[begin] < key && begin < end)
		  {
			   begin++;
		  }
		  
		  //填充最后的end位置
		  if (begin<end)
		  {
			   array[end] = array[begin];
			   end--;
		  }
		  
		  //从后往前找比基准值小的元素
		  while (array[end] > key && begin < end)
		  {
			   end--;
		  }
		  
		  if (begin < end)
		  {
			   array[begin] = array[end];
			   begin++;
		  }
	 }
	 
	 array[begin] = key;
	 return begin;
}

方法三:

<1>和方法一类似,不过这个两个都从前开始,还是先设置基准值,最后一个元素
<2>将cur放在第一个元素的位置,pre放在cur的前一个位置
<3>cur标记的元素如果比基准值大,pre不动,cur继续往后走
<4>cur标记的元素如果比基准值小,pre走一步然后看是否与cur相等
<5>相等话什么也不做,cur继续往后走,如果不相等,交换pre和cur位置的元素
<6>最后将基准值放入pre+1位置

int partion3(int* array, int left, int right)
{
	 int cur = left;
	 int pre = cur - 1;
	 int key = array[right - 1];
	 
	 while (cur < right)
	 {
		  //cur标记的元素比基准值小,并且pre走一步不和cur相同,说明中间的都比基准值大,交换
		  //cur标记的元素比基准值大,cur继续走,但是pre是不动的,pre走和cur标记的比基准值小同步
		  if (array[cur] < key && ++pre != cur)
		  {
			    swap(&array[pre], &array[cur]);
		  }
		  cur++;
	 }
	 
	 //交换的是基准值位置的值,不是和key保存的值交换
	 if ((pre + 1) != right)
	 {
		  swap(&array[pre + 1], &array[right - 1]);
	 }
	 
	 return pre + 1;
}

快速排序的框架:

void QuickSort(int* array, int left,int right)
{
	 //元素个数最少一个
	 if (right - left > 1)
	 {
		  //int div = partion1(array, left, right);
		  //int div = partion2(array, left, right);
		  int div = partion3(array, left, right);
		  QuickSort(array, left, div);
		  QuickSort(array, div + 1, right);
	 }
}

主函数:

int main()
{
	 int a[] = { 0, 1, 9, 5, 3, 8, 6, 7, 25 };
	 
	 //insertSort(a,sizeof(a)/sizeof(a[0]));
	 
	 //shellSort(a, sizeof(a) / sizeof(a[0]));
	 
	 //selectSort(a, sizeof(a) / sizeof(a[0]));
	 
	 //selectSort2(a, sizeof(a) / sizeof(a[0]));
	 
	 //BubbleSort(a, sizeof(a) / sizeof(a[0]));
	 
	 QuickSort(a, 0, sizeof(a) / sizeof(a[0]));
	 
	 for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
	 {
		  printf("%d  ", a[i]);
	 }
	 printf("\n");
	 
	 system("pause");
	 return 0;
}

代码运行测试图:

在这里插入图片描述

在这里插入图片描述

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

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值