简单选择排序(顺序存储、链式存储)、堆排序(顺序存储)

  • Post author:
  • Post category:其他




简单选择排序(顺序存储、链式存储)、堆排序(顺序存储)

选择排序分为简单选择排序和堆排序。其基本思想是:每一趟(如第i趟)在后面n-i+1(i=1,2,…,n-1)个待排序元素中选关键字最小的元素,作为有序子序列的第i个元素,直到第n-1趟做完,待排序元素只剩下1个,就不用再选了。





简单选择排序


算法思想:假设排序表为L[1…n],第i趟排序即从L[i…n]中选取关键字最小的元素与L(i)交换,每一趟排序可以确定一个元素的最终位置,这样经过n-1趟排序就可以使得整个排序表有序。


顺序存储结构(数组)

/*
Title:简单选择排序(数组结构实现)
Author:F&S&L 
Time:2020.11.30 
*/
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 100

int A[MaxSize];        //初始化数组 

int CreateA()         //创建待排序数组A[] 
{
	int e,i=0;
	printf("请输入你需要排序的元素(空格隔开,以999结束):");
	while(1)
	{
		scanf("%d",&e);
		if(e!=999)    //当从键盘输入的元素不为999时,就存储到数组A[]中;反之,则结束输入 
		{
			i++;      //i记录的是待排序数组中元素的个数 
			A[i-1]=e;
		} 
		else break;
	}
	return i-1;	    //返回的i-1表示的是待排序数组中最后一个元素的下标 
} 

void SelectSort(int rear)  //简单选择排序函数,传入的参数rear表示的是最后一个元素的小标 
{
	int front=0,p,temp;   //front是进行比较的第一个元素的位置,p是用来记录当前比较过程中最小元素的位置,temp是交换元素的盒子 
	while(front<rear)  //结束循环的条件 
	{
		p=front;       //假设当前最小元素的front 
		for(int i=front+1;i<=rear;i++)   //如果i位置的元素小于p位置元素的值,则将i赋给p 
		{
			if(A[i]<A[p])
			{
				p=i;
			}
		}
		temp=A[front];    //一趟之后,就进行元素交换,把最小元素赋给front位置,同时front+1,再进行下一趟 
		A[front]=A[p];
		A[p]=temp;
		front++;
	}
}

void PrintfA(int rear)   //打印数组A[] 
{
	for(int i=0;i<=rear;i++)
	{
		printf("%d ",A[i]);	
	}
	printf("\n");	
} 

int main()
{
	int n;
	n=CreateA();
	printf("待排序的序列为:");
	PrintfA(n); 
	SelectSort(n);
	printf("排序后的序列为:");
	PrintfA(n); 
}

在这里插入图片描述


链式存储结构(单链表)

/*
Title:简单选择排序(单链表结构实现)
Author:F&S&L 
Time:2020.11.30 
*/
#include<stdio.h>
#include<stdlib.h>
#define ElemType int

typedef struct Lnode  //创建节点的数据结构 
{
	ElemType data;
	struct Lnode *next;
}LNode,*LinkList;

LinkList CreateList()  //尾插法创建单链表 
{
	ElemType e=0;
	LinkList L;
	L=(LinkList)malloc(sizeof(Lnode));
	LNode *s,*r=L;          //节点s用来存储待插入元素,指针r用来指向当前链表的尾部 
	printf("请输入待排序元素(空格隔开,以999结束):");
	while(e!=999)
	{
		scanf("%d",&e);
		if(e!=999)
		{
			s=(LNode*)malloc(sizeof(Lnode));
			s->data=e;
			r->next=s;
			r=s;
		}
		else
		{
			r->next=NULL;
			break;
		}
	}
	return L;
}

LinkList SelectSort(LinkList L)
{
	LNode *front=L->next;   //front指针指向待排序序列的第一个元素 
	LNode *p;       //指针p用来指向来比较的元素 
	LNode *min;     //指针min用来指向当前最小元素的位置 
	int temp;		//temp作为交换元素的空间 
	while(front->next!=NULL)   //当front没有指向最后一个元素时 
	{
		min=front;
		p=front->next;
		while(p->next!=NULL)
		{
			if(p->data<min->data)
			{
				min=p;
				p=p->next;
			}
			else 
			{
				p=p->next;
			}
		}
		if(p->data<min->data)min=p;   //当front指向最后一个元素时,比较最后一个元素和当前min的大小 
		temp=front->data;        //将一趟下来min指向的值和front指向的值交换 
		front->data=min->data;
		min->data=temp;
		front=front->next;     //再将front指针后移一个位置 
	}
	return L;
} 

void PrintfList(LinkList L)
{
	LNode *p=L->next;
	while(p->next!=NULL)
	{
		printf("%d ",p->data);
		p=p->next;
	}
	printf("%d",p->data);
	printf("\n");
}

int main()
{
	LinkList L;
	L=CreateList();
	printf("待排序元素序列为:");
	PrintfList(L);
	SelectSort(L);
	printf("排序后的元素序列为:");
	PrintfList(SelectSort(L)); 
}

在这里插入图片描述

空间效率:O(1)

时间效率:O(n^2)

稳定性:不稳定





堆排序


算法思想:首先将存放在L[1…n]中的n个元素建成初始堆,由于堆(大根堆)本身的特点,堆顶元素就是最大值。输出堆顶元素之后,通常将堆底元素送到堆顶,此时根节点已经不满足大根堆性质,堆被破坏,将堆顶元素向下调整使其继续保持大根堆的性质,再输出堆顶元素。如此重复,直到堆中只有一个元素为止。


数组实现,基于树的顺序存储特点,i节点的左孩子是2i,右孩子是2i+1

/*
Title:堆排序(数组实现,基于树的顺序存储特点,i节点的左孩子是2i,右孩子是2i+1)
Author:F&S&L 
Time:2020.12.1 
*/
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 100

int A[MaxSize];

//用户输入待排序元素序列
int CreateA()
{
    int e,len=0;
    printf("请输入待排序元素序列(空格隔开,以999结束):");
    while(1)
    {
        scanf("%d",&e);
        if(e!=999)
        {
            len++;
            A[len]=e;
        }
        else
        {
            break;
        }
        
    }
    return len;   //返回待排序元素序列的长度,即元素个数
}

//建立大根堆
void BuildMaxHeap(int A[],int len)   //预留0号位置来作为交换元素的空间
{
    int i=len/2;
    while(i>0)
    {
        if(2*i+1<=len)     //当i号位置的右孩子存在时
        {
            if(A[2*i]>A[i]&&A[2*i+1]>A[i])  //如果左孩子和右孩子同时大于父亲节点
            {
                if(A[2*i]-A[2*i+1]>=0)    //得比较左右孩子的值,较大的那个和父亲节点交换元素
                {
                    A[0]=A[2*i];
                    A[2*i]=A[i];
                    A[i]=A[0];
                }
                else
                {
                    A[0]=A[2*i+1];
                    A[2*i+1]=A[i];
                    A[i]=A[0];
                }                
            }
            if(A[2*i]>A[i])   //右孩子小于父亲节点,左孩子大于父亲节点
            {
                A[0]=A[2*i];
                A[2*i]=A[i];
                A[i]=A[0];
            }
            if(A[2*i+1]>A[i])   //左孩子小于父亲节点,右孩子大于父亲节点
            {
                A[0]=A[2*i+1];
                A[2*i+1]=A[i];
                A[i]=A[0];
            }
        }
        i--;     //交换元素后,使i的值减1
    }
}

//进行堆排序
void HeapSort(int A[],int len)
{
    BuildMaxHeap(A,len);
    for(int i=len;i>1;i--)     //交换根和当前最后一个元素的值
    {
        A[0]=A[i];
        A[i]=A[1];
        A[1]=A[0];
        BuildMaxHeap(A,i-1);   //交换结束后,最大的元素就在最后(就可以忽视它),再使当前数组长度减1,进行堆排序,使最大的元素跑到根节点位置
    }
}

//打印数组A中的元素
void PrintfA(int A[],int len)
{
    for(int i=1;i<=len;i++)
    {
        printf("%d ",A[i]);
    }
    printf("\n");
}

int main()
{
    int len=CreateA();
    printf("待排序元素序列为:");
    PrintfA(A,len);
    HeapSort(A,len);
    printf("排序后的元素序列为:");
    PrintfA(A,len);
}

在这里插入图片描述

空间效率:O(1)

时间效率:O(nlog2n)

稳定性:不稳定



版权声明:本文为qq_45821218原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。