选择排序--简单选择排序,堆排序(大根堆,小根堆的建立,堆排序,插入删除元素)包含程序

 选择排序:每一趟从待排序列中选择最小的元素作为有序子序列中的元素,待元素只剩下一个,就不用选了。

一,简单选择排序

1.过程:假设以A[]表示数组

1.1最开始定义一个变量用来存储数组数组第一个元素的序号 i = 0; min = i,A[min] = 49;

数组序号01234567
待排序列4938659776132749

1.2用min对应数组中的元素依次往后作比较,A[min] = 49 > A[1] = 38,所以此时min = 1,A[min] =38

然后继续向后进行比较,A[min] = 38 < A[2] = 65;   A[min] = 38 < A[3] = 97;  A[min] = 38 < A[4]=76

A[min] = 38 > A[5] = 13,所以令 min = 5,A[min] = 13;  A[min] = 13 < A[6] = 27; A[min] = 13<A[7]=49

此时序号min就是数组中最小的元素,因此交换位置A[min]和A[i];

数组序号01234567
待排序列1338659776492749

2.代码展示

//简单选择排序
void SelectSort(Str &L)
{
	for(int i = 0; i < L.length-1; ++i)//一共进行n-1趟
	{
	  int min = i;//记录最小元素的位置
	  for(int j = i+1; j < L.length; ++j)//在A[i...n-1]中选择最小的元素
		  if(L.data[j] < L.data[min])
			  min = j;//更新最小元素的位置
	  if(min != i)
		  swap(L.data[min],L.data[i]);//在swap函数中交换元素位置,函数中元素共移动了3次
	}
}

3.结果:

4.分析

空间复杂度:仅使用了常数个辅助单元,空间复杂度为O(1)

时间复杂度:在简单选择排序过程中,元素移动的操作次数很少,不会超过3(n-1)(假如是n个元素的逆序,故n-1个都是需要移动,在swap函数中,每次交换元素位置的时候移动3次,故不会超过3(n-1)) ;元素之间的比较次数与序列的初始状态无关,始终是n(n-1)/2次(每次都是从待排序列的第一个元素开始往后进行比较n-1+....+1),所以时间复杂度为O(n^{2})。

二,堆排序

堆的定义:n个关键字序列L[1...n]称为堆,当且仅当该序列满足:

(1)L(i) >= L(2i) 且L(i) >= L(2i+1)或(2)L(i) <= L(2i)且L(i) <= L(2i+1)。可以将堆视为一棵完全二叉树,满足条件(1)的堆称为大根堆;满足条件(2)的堆称为小根堆。

1.过程

1.1创建堆的过程(以大根堆为例)

数组序号012345678
待排序列4938659776132749

 从左到右,从上到下,图的编号是1,2,3,4,5;

创建大根堆的步骤:

1.第1张图是待排序列按照完全二叉树的形式进行排版。

2.从完全二叉树的最后一个非终端结点开始,依次向上,与其左右孩子结点的最大值进行比较。

3.因为97只有左孩子且其值为49 ,97>49,所以不进行交换;因为13<27,所以65与其右孩子的值17进行比较,65>27,所以不进行交换;因为97>76,所以38与其左孩子的值97进行比较,38<97,所以进行交换,交换后如第2张图; 因为97>65, 所以49与其左孩子的值97进行比较,49<97,交换后如第3张图。

4.然后按照第3步进行检查,因为值为38的结点只有左孩子,所以38与其左孩子值为49进行比较,38<49,所以进行交换,交换后如第4张图;因为49<76,所以49与其右孩子值为76进行比较,49<76,所以进行交换,如第5张图。如此完成该例子的大根堆创建,结果就是第5张图。

创建大根堆的代码展示:

//以大根堆的形式调整元素所在位置
void MaxHeadAdjust(Str &L, int k)
{//将元素k为根的子树进行调整
	L.data[0] = L.data[k];//最开始将根结点元素放在序号为0的位置
	for(int i = 2*k; i <= L.length; i*=2)//沿着较大的子结点向下筛选
	{
		if(i < L.length  && L.data[i] < L.data[i+1])//当i < 待排序列的长度的时候才会,关键字才会有右孩子;如果左孩子的值小于右孩子的值,那么关键字就和右孩子的值进行比较
			i++;//i++就表示右孩子的序号
		if(L.data[0] >= L.data[i])//如果关键字大于等于孩子结点的值,那么就不需要进行交换
			break;//直接结束程序,也不需要再次下坠
		else
		{
			L.data[k] = L.data[i];//如果小于,那么就将孩子的值赋值到双亲结点
			k = i;//那么随之而来就是将关键字的序号进行改变
		}
	}
	L.data[k] = L.data[0];//确定最后位置之后就将原本存储到0序号的元素的值赋值到最终位置
}

//创建大根堆
void BuildMaxHeap(Str &L)
{
	for(int i = L.length/2; i >= 1; --i)//从i = [n/2] -- 1,反复调整堆
		MaxHeadAdjust(L,i);
}

1.2堆排序的过程(以大根堆为例)

堆排序:每一趟将堆顶元素加入有序子序列(与创建堆后的待排序列的最后一个元素交换),并且将序列长度降低1,然后现在的待排序列再次调整成大根堆。(小元素不断”下坠“)。 

1.第一张图是创建堆的时候的完全二叉树,然后将堆顶元素与最后一个元素进行交换,输出堆顶元素,然后减少待排序列的长度。

2.因为76>63,所以将元素38"下坠",和76交换位置;得到图3,后续是同样步骤得到图4.

堆排序代码展示:

//大根堆堆排序算法
void MaxHeapSort(Str &L)
{
  BuildMaxHeap(L);
  for(int i = L.length; i >= 1; --i)
  {
	  printf("%d ",L.data[1]);
	  swap(L.data[1],L.data[i]);
	  L.length--;
	  MaxHeadAdjust(L,1);
  }
  printf("\n");
}

2.插入元素

基本思想:将元素插入到待排序列的后面一个位置,对于大根堆,向上比较双亲结点,构成符合大根堆的样子

代码展示:

//大根堆堆排序插入
void InsertMaxHeap(Str &L, int v)
{
	int i = ++L.length;//插入元素则数组的有效长度增加1
	int j = i/2;//双亲结点
	L.data[L.length] = v;//将值赋值给数组中
	while(L.data[i] > L.data[j])//进行比较
	{
		swap(L.data[i],L.data[j]);//大于则交换位置
		i = j;//继续向上比较
		j = i/2;
	}
}

 

3.删除元素

基本思想:将删除的元素用数组最后一个元素进行代替,然后再构造成大根堆

//大根堆堆排序删除
void DeletMaxHeap(Str &L, int &w)
{
  int i;
  printf("请输入想要删除数组元素的序号:\n");
  scanf_s("%d",&i);
  w = L.data[i];
  swap(L.data[L.length],L.data[i]);
  L.length--;
  MaxHeadAdjust(L,i);

}

 

 4.小根堆(过程和大根堆类似,改变符号就好了,此处就展示代码)

4.1创建小根堆

//以小根堆的形式调整数组中的元素
void MinHeadAdjust(Str &L, int k)
{
	L.data[0] = L.data[k];
	for(int i = 2*k; i <= L.length; i*=2)
	{
		if(i < L.length  && L.data[i] > L.data[i+1])
			i++;
		if(L.data[0] <= L.data[i])
			break;
		else
		{
			L.data[k] = L.data[i];
			k = i;
		}
	}
	L.data[k] = L.data[0];
}

//创建小根堆
void BuildMinHeap(Str &L)
{
	for(int i = L.length/2; i >= 1; --i)
		MinHeadAdjust(L,i);
}

4.2堆排序

//小根堆堆排序
void MinHeapSort(Str &L)
{
  BuildMinHeap(L);
  for(int i = L.length; i >= 1; --i)
  {
	  printf("%d ",L.data[1]);
	  swap(L.data[1],L.data[i]);
	  L.length--;
	  MinHeadAdjust(L,1);
  }
  printf("\n");
}

4.3插入元素

//小根堆堆排序插入
void InsertMinHeap(Str &L, int v)
{
	int i = ++L.length;
	int j = i/2;
	L.data[L.length] = v;
	while(L.data[i] < L.data[j])
	{
		swap(L.data[i],L.data[j]);
		i = j;
		j = i/2;
	}
}

4.4删除元素

//小根堆堆排序删除
void DeletMinHeap(Str &L, int &w)
{
  int i;
  printf("请输入想要删除数组元素的序号:\n");
  scanf_s("%d",&i);
  w = L.data[i];
  swap(L.data[L.length],L.data[i]);
  L.length--;
  MinHeadAdjust(L,i);

}

结果:

5.分析

在建含n个元素的堆时,关键字的比较次数不会超过4n,时间复杂度为O(n) 

空间复杂度:仅使用了常数个辅助单元1,所以空间复杂度为O(1)

时间复杂度:建堆时间为O(n),之后有n-1次向下调整,每次调整时间的复杂度为O(h),h = \log n为树高,故在最好最坏的平均条件下,堆排序的时间复杂度为O(n)+O(n\log n)  = O(n\log n

三,总结:

选择排序空间复杂度时间复杂度稳定性
简单选择排序O(1)O(n^{2})不稳定
堆排序O(1)O(n\log n不稳定

四,完整代码

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

//定义数组结构体
typedef struct
{
  int *data;
  int length;
}Str;

//函数说明
void CreatString(Str &L);
void CreatString1(Str &L);
void swap(int &a, int &b);
void SelectSort(Str &L);
void PrintStr(Str L);
void PrintStr1(Str L);
//大根堆
void BuildMaxHeap(Str &L);
void MaxHeadAdjust(Str &L, int k);
void MaxHeapSort(Str &L);
void InsertMaxHeap(Str &L, int v);
void DeletMaxHeap(Str &L, int &w);

//小根堆
void BuildMinHeap(Str &L);
void MinHeapSort(Str &L);
void MinHeadAdjust(Str &L, int k);
void InsertMinHeap(Str &L, int v);
void DeletMinHeap(Str &L, int &w);

int main(void)
{
  Str L;
  CreatString(L);
  SelectSort(L);
  printf("简单选择排序之后数组元素为:\n");
  PrintStr(L);
  //大根堆
  Str L1;
  CreatString1(L1);
  printf("大根堆堆排序之后数组元素为:\n");
  MaxHeapSort(L1);//堆排序之后元素是有序的
  Str L2;
  CreatString1(L2);
  BuildMaxHeap(L2);
  printf("创建大根堆之后数组元素为:\n");
  PrintStr1(L2);//创建完堆之后输出数组中的元素,数组中元素不一定是有序的
  printf("请输入你想插入的元素:\n");
  int v;
  scanf_s("%d",&v);
  InsertMaxHeap(L2,v);
  printf("插入元素之后数组元素为:\n");
  PrintStr1(L2);
  Str L2_1 = L2;
  printf("堆排序之后数组元素为:\n");
  MaxHeapSort(L2);
  int w;
  DeletMaxHeap(L2_1,w);
  printf("删除元素%d之后数组元素为:\n",w);
  PrintStr1(L2_1);
  printf("删除元素之后堆排序为:\n");
  MaxHeapSort(L2_1);
  //小根堆
  Str L3;
  CreatString1(L3);
  printf("小根堆堆排序之后数组元素为:\n");
  MinHeapSort(L3);//堆排序之后元素是有序的
  Str L4;
  CreatString1(L4);
  BuildMinHeap(L4);
  printf("创建小根堆之后数组元素为:\n");
  PrintStr1(L4);//创建完堆之后输出数组中的元素,数组中元素不一定是有序的
  printf("请输入你想插入的元素:\n");
  int x;
  scanf_s("%d",&x);
  InsertMinHeap(L4,x);
  printf("插入元素之后数组元素为:\n");
  PrintStr1(L4);
  Str L4_1 = L4;
  int y;
  DeletMinHeap(L4_1,y);
  printf("删除元素%d之后数组元素为:\n",y);
  PrintStr1(L4_1);
  printf("小根堆堆排序之后元素为:\n");
  MinHeapSort(L4_1);
  return 0;
}


//创建数组
void CreatString(Str &L)
{
	L.data = (int *)malloc(sizeof(int)*8);
	L.length = 8;
	int val;
	for(int i = 0; i < L.length; ++i)
	{
	  printf("请输入第%d个元素的值:",i+1);
	  scanf_s("%d",&val);
	  L.data[i] = val;
	}
}

void CreatString1(Str &L)
{
 	L.data = (int *)malloc(sizeof(int)*12);
	L.length = 8;
	int val;
	for(int i = 1; i <= L.length; ++i)
	{
	  printf("请输入第%d个元素的值:",i);
	  scanf_s("%d",&val);
	  L.data[i] = val;
	} 
}

//简单选择排序
void SelectSort(Str &L)
{
	for(int i = 0; i < L.length-1; ++i)//一共进行n-1趟
	{
	  int min = i;//记录最小元素的位置
	  for(int j = i+1; j < L.length; ++j)//在A[i...n-1]中选择最小的元素
		  if(L.data[j] < L.data[min])
			  min = j;//更新最小元素的位置
	  if(min != i)
		  swap(L.data[min],L.data[i]);//在swap函数中交换元素位置,函数中元素共移动了3次
	}
}

//元素交换位置
void swap(int &a, int &b)
{
  int temp = a;
  a = b;
  b = temp;
}

//遍历输出
void PrintStr(Str L)
{
	for(int i = 0; i < L.length; ++i)
	{
		printf("%d ",L.data[i]);
	}
	printf("\n");
}

void PrintStr1(Str L)
{
	for(int i = 1; i <= L.length; ++i)
	{
		printf("%d ",L.data[i]);
	}
	printf("\n");
}



//以大根堆的形式调整元素所在位置
void MaxHeadAdjust(Str &L, int k)
{//将元素k为根的子树进行调整
	L.data[0] = L.data[k];//最开始将根结点元素放在序号为0的位置
	for(int i = 2*k; i <= L.length; i*=2)//沿着较大的子结点向下筛选
	{
		if(i < L.length  && L.data[i] < L.data[i+1])//当i < 待排序列的长度的时候才会,关键字才会有右孩子;如果左孩子的值小于右孩子的值,那么关键字就和右孩子的值进行比较
			i++;//i++就表示右孩子的序号
		if(L.data[0] >= L.data[i])//如果关键字大于等于孩子结点的值,那么就不需要进行交换
			break;//直接结束程序,也不需要再次下坠
		else
		{
			L.data[k] = L.data[i];//如果小于,那么就将孩子的值赋值到双亲结点
			k = i;//那么随之而来就是将关键字的序号进行改变
		}
	}
	L.data[k] = L.data[0];//确定最后位置之后就将原本存储到0序号的元素的值赋值到最终位置
}

//创建大根堆
void BuildMaxHeap(Str &L)
{
	for(int i = L.length/2; i >= 1; --i)//从i = [n/2] -- 1,反复调整堆
		MaxHeadAdjust(L,i);
}

//大根堆堆排序算法
void MaxHeapSort(Str &L)
{
  BuildMaxHeap(L);
  for(int i = L.length; i >= 1; --i)
  {
	  printf("%d ",L.data[1]);
	  swap(L.data[1],L.data[i]);
	  L.length--;
	  MaxHeadAdjust(L,1);
  }
  printf("\n");
}

//大根堆堆排序插入
void InsertMaxHeap(Str &L, int v)
{
	int i = ++L.length;//插入元素则数组的有效长度增加1
	int j = i/2;//双亲结点
	L.data[L.length] = v;//将值赋值给数组中
	while(L.data[i] > L.data[j])//进行比较
	{
		swap(L.data[i],L.data[j]);//大于则交换位置
		i = j;//继续向上比较
		j = i/2;
	}
}

//大根堆堆排序删除
void DeletMaxHeap(Str &L, int &w)
{
  int i;
  printf("请输入想要删除数组元素的序号:\n");
  scanf_s("%d",&i);
  w = L.data[i];
  swap(L.data[L.length],L.data[i]);
  L.length--;
  MaxHeadAdjust(L,i);

}



//以小根堆的形式调整数组中的元素
void MinHeadAdjust(Str &L, int k)
{
	L.data[0] = L.data[k];
	for(int i = 2*k; i <= L.length; i*=2)
	{
		if(i < L.length  && L.data[i] > L.data[i+1])
			i++;
		if(L.data[0] <= L.data[i])
			break;
		else
		{
			L.data[k] = L.data[i];
			k = i;
		}
	}
	L.data[k] = L.data[0];
}

//创建小根堆
void BuildMinHeap(Str &L)
{
	for(int i = L.length/2; i >= 1; --i)
		MinHeadAdjust(L,i);
}

//小根堆堆排序
void MinHeapSort(Str &L)
{
  BuildMinHeap(L);
  for(int i = L.length; i >= 1; --i)
  {
	  printf("%d ",L.data[1]);
	  swap(L.data[1],L.data[i]);
	  L.length--;
	  MinHeadAdjust(L,1);
  }
  printf("\n");
}


//小根堆堆排序插入
void InsertMinHeap(Str &L, int v)
{
	int i = ++L.length;
	int j = i/2;
	L.data[L.length] = v;
	while(L.data[i] < L.data[j])
	{
		swap(L.data[i],L.data[j]);
		i = j;
		j = i/2;
	}
}

//小根堆堆排序删除
void DeletMinHeap(Str &L, int &w)
{
  int i;
  printf("请输入想要删除数组元素的序号:\n");
  scanf_s("%d",&i);
  w = L.data[i];
  swap(L.data[L.length],L.data[i]);
  L.length--;
  MinHeadAdjust(L,i);

}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值