八大排序 上 :直接插入排序 希尔排序 堆排序 选择排序

直接插入排序

思想:

把待排序的元素按其的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为
止,得到一个新的有序序列
 直接插入单趟 思想:
end 是当前元素的下标 
1.先保存end 的下一个元素 到 tmp
2. 判断 a[end] 是否 大于 tmp  若 a[end] > tmp  将 end 下标的元素 移动到 [end+1] 位置(前面已经 把[end+1]的元素保存到tmp 中 就不担心[end+1] 位置的元素被覆盖)
然后 [--end]  [end的前一个元素] 称为新的 end  继续判断 数组的下标[0,n-1]  直到 end 小于 0 结束  
若 end 不大于 tmp 就退出循环 将 tmp 放进 end的下一个位置
void InsertSort(int* a, int n)
{
	
	
	for (int i = 0; i < n; i++)
	{
		int end = i;
		int tmp = a[end + 1];

		while (end >= 0)
		{
			if (a[end] > tmp)
			{
				a[end + 1] = a[end];
				--end;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;
	}
}

运行结果:

 当 i < n ;  最后一个 end 的下是 n-1  tmp 的下标是 n  (已当前为例)有效的数组下标 [0,n-1] tmp指向n 数组越界 

 当 i < n-1 ;  最后一个 end 的下是 n-2  tmp 的下标是 n-1 (已当前为例)有效的数组下标 [0,n-1] tmp指向n-1  完全ok 

修改后的代码:


// 直接插入单趟 思想:
// end 是当前元素的下标 
// 1.先保存end 的下一个元素 到 tmp
// 2. 判断 a[end] 是否 大于 tmp  若 a[end] > tmp  将 end 下标的元素 移动到 [end+1] 位置(前面已经 把[end+1]的元素保存到tmp 中 就不担心[end+1] 位置的元素被覆盖)
// 然后 [--end]  [end的前一个元素] 称为新的 end  继续判断 数组的下标[0,n-1]  直到 end 小于 0 结束  
// 若 end 不大于 tmp 就退出循环 将 tmp 放进 end的下一个位置
void InsertSort(int* a, int n)
{
	//for (int i = 0; i < n; i++)
	// 当 i < n ;  最后一个 end 的下是 n-1  tmp 的下标是 n  (已当前为例)有效的数组下标 [0,n-1] tmp指向n 数组越界 
	
	// 当 i < n-1 ;  最后一个 end 的下是 n-2  tmp 的下标是 n-1 (已当前为例)有效的数组下标 [0,n-1] tmp指向n-1  完全ok 
	for (int i = 0; i < n-1; i++)
	{
		int end = i;
		int tmp = a[end + 1];

		while (end >= 0)
		{
			if (a[end] > tmp)
			{
				a[end + 1] = a[end];
				--end;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;
	}
}

运行结果:


直接插入排序的特性总结:

  •    元素集合越接近有序,直接插入排序算法的时间效率越高
  •    时间复杂度:O(N ^ 2) 但是再接近有序的情况 比 冒泡排序好 
  •    空间复杂度:O(1),它是一种稳定的排序算法
  •    稳定性:稳定

希尔排序  

 思想:和插入排序很像

思路:1 先预排序  使数组接近有序
           2.再直接插入

希尔排序单趟 思想:
end 是当前元素的下标 
1.先保存end+gap 的元素 到 tmp
2. 判断 a[end] 是否 大于 tmp  若 a[end] > tmp  将 end 下标的元素 移动到 [end+gap] 位置(前面已经 把[end+gap]的元素保存到tmp 中 就不担心[end+gap] 位置的元素被覆盖)
 然后 [end-= gap]  [end的前gap 的元素] 称为新的 end  继续判断 end有效的下标[0,n-gap)  直到 end 小于 0 结束  
若 end 不大于 tmp 就退出循环 将 tmp 放进 end+gap的位置
 

gap = 5  第一趟    为 (n/2)  gap 一次跳过5个元素  
gap = 2  第二趟           gap 一个跳过2 个元素
gap = 1  第三趟    相当于直接插入 

gap 越大  gap 跳的越快   大的数 更快到后面  

 gap 越小 gap 跳的越慢    

代码实现:


void ShellSort(int* a, int n)
{
	int gap = n;

	while (gap > 1)
	{
		gap = gap / 2;
		// i < n -gap 防止数组越界
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;
			int tmp = a[end + gap];

			while (end >= 0)
			{
				if (a[end] > tmp)
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
}


希尔排序的特性总结:
   希尔排序是对直接插入排序的优化。
   时间复杂度:O(N^1.25)
   空间复杂度:O(1)
   稳定性:不稳定

 

堆排序

堆排序 (Heapsort) 是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是
通过堆来进行选择数据。 需要注意的是排升序要建大堆,排降序建小堆。
思路:
(这里已升序为例)
思想 ; 找到最后一个非叶子节点 向下调整建堆 当前树 的左右子树 都是 大堆 继续调整 根节点 向下调整建堆  直到 整个树结构为大堆
用删除的思想来 实现排序 
1.将堆顶部 的元素 和 最后一个元素交换 
2.再把最后一个元素不看进堆里面的(是顶部的元素) 
3.向下调整建堆
继续 进行 1 2 3  直到堆里面没有元素

//(这里已升序为例)
//找到最后一个非叶子节点 向下调整建堆 当前树 的左右子树 都是 大堆 继续调整 根节点 向下调整建堆  直到 整个树结构为大堆
void AdjustDown(int* a, int n , int parent)
{
	//假设左孩子 是左右孩子 较大的
	int child = parent * 2 + 1;

	while (child < n)
	{
		if ((child + 1 < n) && a[child + 1] > a[child])//如果右孩子大于 左孩子 就把 右孩子赋值给 child
		{
			++child; //就把 右孩子赋值给 child
		}
		//孩子大于父亲就交换
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);

			parent = child;
			child = parent * 2 + 1;
		}
		else //堆已成直接返回
		{
			break;
		}
	}
}

void HeapSort(int* a, int n)
{
	// 找到最后一个非叶子节点
	// (n-1)/2 找到它的父亲
	for (int i = (n - 2 / 2); i >= 0; i--)
	{
		AdjustDown(a, n, i);
	}

	//用删除的思想来 实现排序 
	int end = n-1;

	while (end >0)
	{
		Swap(&a[0], &a[end]);
		end--; //再把最后一个元素不看进堆里面的(是顶部的元素)
		AdjustDown(a, end, 0);
	}
}

  堆排序的特性总结:

  •     堆排序使用堆来选数,效率就高了很多。
  •     时间复杂度:O(N * logN)
  •     空间复杂度:O(1)
  •     稳定性:不稳定

选择排序  

思想: 先选出最大的元素 和最小的元素 把最大的元素放到起始位置 begin 后 begin++ 把最小的元素放到结束位置end 后 end-- 再选出次大的和次小的 重复前面的操作
 当 begin == end  它们之间已经没有元素了   排完了

代码实现:


void SelectSort(int* a, int n)
{
	int min =0, max=0;
	int begin = 0, end = n - 1;
	//	[begin ,end]

	while (begin < end)
	{
		min = begin;
		max = begin;
		
		for (int i= begin; i <= end; i++)
		{
			if (a[i] < a[min])
				min = i;
			if (a[i] > a[max])
				max = i;
		}

	
		
		Swap(&a[end], &a[max]);
		//若最后一个就是最小的 就再 更新下
		if (end == min)
			min = max;

		Swap(&a[begin], &a[min]);


		begin++;
		end--;
	}
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值