简单选择排序
思路
选择排序算法通过选择和交换来实现排序,其排序流程如下:
(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();
}