【上机代码】选择排序——简单选择排序、堆排序

简单选择排序

思路

选择排序算法通过选择和交换来实现排序,其排序流程如下:
(1)序列表为L[1…n],每趟(第i趟)在L[i…n]中的n-i+1个(第一趟n个、第二趟n-1个…)待排元素中选取最小的元素,然后与L[i]交换。每趟确定一个元素的最终位置。
(2)然后不断重复,直到n-1趟,待排序列只剩一个元素就不需要再选择了。便完成了对原始序列的排序。

代码

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void print(int A[], int length)
{
	for (int i = 0; i < length; ++i)
	{
		printf("%d ", A[i]);
	}
}
void swap(int& a, int& b)
{
	int temp = a;
	a = b;
	b = temp;
}

//简单选择排序
void SelectSort(int A[], int n) {
	for (int i = 0; i < n - 1; ++i) {
		int min = i;
		for (int j = i + 1; j < n; ++j) {
			if (A[j] < A[min])
				min = j;
		}
		if (min != i)
			swap(A[i], A[min]);
	}
}

void test()
{
	int A[10];
	int length = sizeof(A) / sizeof(A[0]);
	srand(time(0));
	for (int i = 0; i < length; ++i)
	{
		A[i] = rand() % 100;//取0-99的随机数  0-99,都为原值,100-199为0-99,以此类推

	}
	printf("原始序列为:\n");
	print(A, length);
	SelectSort(A, length);
	printf("\n排序后为:\n");
	print(A, length);
}
int main()
{
	test();
}

链表实现

思路

关于链表的实现有两点疑问:
1,带头结点的单链表如何交换两个元素
A,B两个元素要设4个指针分别指向A、B的前后节点。交换时分相邻和不相邻两种情况:
(1)相邻只需要更改3个节点指向
A的前置指向B,B指向A,A指向B的后置

(2)不相邻要更改4个节点指向
A前置 A A后置 。。。。B前置 B B后置
A的前置指向B,B指向A的后置
B的前置指向A,A指向B的后置

2,简单选择排序中,链表如何区分两个元素
在数组的排序中,值是用下标来标识不同的元素,即使值相同也可区分。
在链表的排序中,在之前的遍历中已经找到的是<min的元素,找到的元素一定和min的值不相同,(相同的元素就不动了)故可以用p->data != min->data作为条件。或者结构体中加一个id来区分不同的元素。

代码

#include<stdio.h>
#include "malloc.h"
#include<stdlib.h>
#include<time.h>
//定义链表结构体
typedef struct Listnode
{
	int data;
	struct Listnode* next;
}Listnode;

//交换链表中两个数据
void swap(Listnode* p, Listnode* min, Listnode* pre, Listnode* lmin, Listnode* bmin)
{
	if (p->next == min)//min就在p后一位,交换相邻的两个节点
	{
		pre->next = min;
		p->next = lmin;
		min->next = p;
	}
	else//交换不相邻的两个节点
	{
		pre->next = min;
		min->next = p->next;
		p->next = lmin;
		bmin->next = p;
	}
};
//输出链表节点
void print(Listnode* L)
{
	Listnode* p = L;
	for (int i = 0; p->next!=NULL; ++i)//L为头结点不能动 否则每次遍历就会改变条件
	{
		printf("%d ", p->next->data);
		p = p->next;
	}
	printf("\n");
}
void select_sort(Listnode*& L)//简单选择排序(升序)
{
	Listnode* h  = (Listnode*)malloc(sizeof(Listnode)), * p, * q, * pmax, * lmax;
	h->data = L->data;
	h->next = L->next; 
	L->next = NULL;
	while (h->next!=NULL)
	{
		p = lmax = h->next;
		q = pmax = h;
		while (p!= NULL)
		{
			if (p->data > lmax->data)
			{
				lmax = p;
				pmax = q;
			}
			q = p;
			p = p->next;
		}
		if (lmax == h->next)
			h->next = h->next->next;//易错
		else
			pmax->next = lmax->next;//取出max
		lmax->next = L->next;
		L->next = lmax;
	}
}



void test()
{
	//建立链表
	Listnode* L = (Listnode*)malloc(sizeof(Listnode));
	if (L == NULL) {
		printf("内存分配不成功!\n");
	}
	else
	{
		L->data = 10;
		Listnode* p = L;
		srand(time(0));
		for (int i = 0; i < L->data; ++i)
		{
			p->next = (Listnode*)malloc(sizeof(Listnode));
			if (p->next) {
				p = p->next;
				p->data = rand() % 100;//取0-99的随机数  0-99,都为原值,100-199为0-99,以此类推
			}
		}
		p->next = NULL;
		printf("原始序列为:\n");
		print(L);
		select_sort(L);
		printf("\n排序后为:\n");
		print(L);
	}
}

int main()
{
	test();
}

堆排序

思路

(1)将L[1…n]中的n个元素构成初始堆(大根堆),则堆顶元素为最大值,输出堆顶元素后
(2)将堆底元素送入堆顶,此时根节点不满足堆的性质。将堆顶元素向下调整,直至满足堆的性质。然后输出堆顶元素
(3)重复,直到堆中只剩下一个元素。

问题:
1,为什么要用A[0]不用temp;相应的代码如何调整
如果A[0]处存放待排元素,那么从下标0出发找左右孩子节点就比较麻烦。(无法用i = i * 2来遍历)。故A[0]空出来存放元素。
给序列输入元素时,从A[1]开始输入。然后输出打印的时候也从A[1]开始输出。

2,输入的len为序列长度而不是数组长度
void HeapSort(int A[], int n)
void BuildMaxHeap(int A[], int n)
void HeadAdjust(int A[], int k, int n)
三个函数中的n都是待排序列长度,非数组的长度。输入时应把数组长度-1。

3,数组元素交换,必须用引用型
swap(A[i], A[1]);中输入的是数组值,而非指针。如果是传入A进去那就是指针,可以不用引用型
在这里插入图片描述

代码

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

void print(int A[], int length)
{
	for (int i = 1; i <= length; ++i)
	{
		printf("%d ", A[i]);
	}
}

void swap(int& a, int& b) {
	int temp = a;
	a = b;
	b = temp;
}
//从序列k位置元素向下,调整为堆
void HeadAdjust(int A[], int k, int n) {
	A[0] = A[k];
	for (int i = 2 * k; i <= n; i = i * 2)
	{
		if (i < n && A[i] < A[i + 1])
			++i;
		if (A[0] >= A[i])
			break;
		else {
			A[k] = A[i];
			k = i;
		}
	}
	A[k] = A[0];
}

//构建堆
void BuildMaxHeap(int A[], int n)
{
	for (int i = n / 2; i > 0; i--)
		HeadAdjust(A, i, n);
}
//堆排序
void HeapSort(int A[], int n)//n为待排序列长度,非数组长度
{
	BuildMaxHeap(A, n);
	for (int i = n; i > 1; i--) {
		swap(A[i], A[1]);
		HeadAdjust(A, 1, i-1);
	}
}

void test()
{
	int A[11];
	int length = sizeof(A) / sizeof(A[0])-1;
	srand(time(0));
	A[0] = -1;
	for (int i = 1; i <= length; ++i)
	{
		A[i] = rand() % 100;//取0-99的随机数  0-99,都为原值,100-199为0-99,以此类推

	}
	printf("原始序列为:\n");
	print(A, length);
	HeapSort(A, length);
	printf("\n排序后为:\n");
	print(A, length);
}
int main()
{

	test();
}

堆插入元素

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

void print(int A[], int length)
{
	for (int i = 1; i <= length; ++i)
	{
		printf("%d ", A[i]);
	}
}

void swap(int& a, int& b) {
	int temp = a;
	a = b;
	b = temp;
}

void HeadAdjust(int A[], int k, int n) {
	A[0] = A[k];
	for (int i = 2 * k; i <= n; i = i * 2)
	{
		if (i < n && A[i] > A[i + 1])
			++i;
		if (A[0] <= A[i])
			break;
		else {
			A[k] = A[i];
			k = i;
		}
	}
	A[k] = A[0];
}

//构建堆
void BuildMinHeap(int A[], int n)
{
	for (int i = n / 2; i > 0; i--)
		HeadAdjust(A, i, n);
}

void Insert(int A[], int& n, int a) {
	int i = ++n;
	A[i] = a;
	while (i / 2 > 0) {
		if (A[i] < A[i / 2])
			swap(A[i], A[i / 2]);
		else
			break;
		i = i / 2;
	}
}

void test()
{
	int A[12];
	int length = sizeof(A) / sizeof(A[0]) - 2;//代表序列有10个元素
	srand(time(0));
	A[0] = -1;
	for (int i = 1; i <= length; ++i)//赋值到序列最后一个元素
	{
		A[i] = rand() % 100;//取0-99的随机数  0-99,都为原值,100-199为0-99,以此类推
	}
	BuildMinHeap(A, length);//A[0]不算堆元素
	printf("原始堆为:\n");
	print(A, length);
	Insert(A, length, 2);//A[0]不算堆元素
	printf("\n插入后堆为:\n");
	print(A, length);//插入序列长度加1
}

int main()
{

	test();
}

堆删除元素

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

void print(int A[], int length)
{
	for (int i = 1; i <= length; ++i)//保证最后一个元素可输出
	{
		printf("%d ", A[i]);
	}
}


void HeadAdjust(int A[], int k, int n) {
	A[0] = A[k];
	for (int i = 2 * k; i <= n; i = i * 2)
	{
		if (i < n && A[i] > A[i + 1])
			++i;
		if (A[0] <= A[i])
			break;
		else {
			A[k] = A[i];
			k = i;
		}
	}
	A[k] = A[0];
}

//构建堆
void BuildMinHeap(int A[], int n)
{
	for (int i = n / 2; i > 0; i--)
		HeadAdjust(A, i, n);
}

void Delete(int A[], int& n, int i) {
	A[i] = A[n];
	--n;
	HeadAdjust(A, i, n);
}


void test()
{
	int A[11];//11个元素,A[0]-A[10]
	int length = sizeof(A) / sizeof(A[0])-1;//length指序列的10个元素,不含A[0]
	srand(time(0));
	A[0] = -1;
	for (int i = 1; i <= length; ++i)
	{
		A[i] = rand() % 100;//取0-99的随机数  0-99,都为原值,100-199为0-99,以此类推
	}
	BuildMinHeap(A, length);//堆元素不含A[0]
	printf("原始堆为:\n");
	print(A, length);
	Delete(A, length, 5);//A[0]不算堆元素,删除数组下标为5的元素,对应堆中第5个元素
	printf("\n插入后堆为:\n");
	print(A, length);
}


int main()
{

	test();
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

燕南路GISer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值