【C语言】【数据结构】内部排序(含算法、各种方法比较)(学习笔记)

14 篇文章 14 订阅
9 篇文章 2 订阅

#include <stdio.h>
#include <stdlib.h>
#define ERROR 0
#define OK 1

typedef int Status;

typedef int ElemType;
typedef struct SqList{
	ElemType *elem;
	int length;
}SqList;

Status CreateList_Sq(SqList & );	//构建
void Load_Sq(SqList );			//遍历打印

//插入排序 
void InsertSort(SqList & );		//直接插入排序

void BInsertSort(SqList & );	//折半插入排序

void ShellSort(SqList & );		//希尔排序 

//交换排序 
void BubbleSort(SqList & );				//冒泡排序

int Partition(SqList & , int , int );	//一趟
void QuickSort(SqList & , int , int );	//快速排序(递归)

//选择排序 
void SelectSort(SqList & );				//简单选择排序 

void HeapAdjust(SqList & , int , int );	//初始堆、调整堆 
void HeapSort(SqList & );				//堆排序 

//归并排序 
void Merge(SqList & , SqList & , int , int , int );
void MergeSort(SqList & );




int main()
{
	SqList L;
	int a;
	
	if(!CreateList_Sq(L)) printf("Create Error!\n");
	printf("插入排序:\n1:直接插入排序\n2:折半插入排序\n3:希尔排序\n");
	printf("交换排序:\n4:冒泡排序\n5:快速排序\n");
	printf("选择排序:\n6:简单选择排序\n7:堆排序\n");
	printf("归并排序:\n8:2路归并排序\n");
	printf("请选择:\n");
	scanf("%d", &a);
	switch(a)
	{
		case 1:	InsertSort(L); break;
		case 2:	BInsertSort(L); break;
		case 3:	ShellSort(L); break;
		case 4:	BubbleSort(L); break;
		case 5:	QuickSort(L,1,L.length); break;
		case 6:	SelectSort(L); break;
		case 7:	HeapSort(L); break;
		case 8:	MergeSort(L); break;
	}
	return 0;
}

Status CreateList_Sq(SqList &L)
{
	int n, i;
	
	printf("请输入待排序的关键字个数:\n");
	scanf("%d", &n);
	L.elem = (ElemType *) malloc ((n+1) * sizeof(ElemType));
	if(!L.elem) return ERROR;
	L.length = n;
	printf("请输入%d个关键字:\n", n);
	for(i=1; i<=n; i++)
		scanf("%d", &L.elem[i]);
	return OK;
}

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

插入排序

直接插入排序

直接插入排序:将一个记录插入到已排好序的有序表中,从而得到一个新的、记录数增1的有序表。

void InsertSort(SqList &L)
{
	int i, j;
	
	for(i=2; i<=L.length; i++)
	{
		if(L.elem[i] < L.elem[i-1])
		{
			L.elem[0] = L.elem[i];
			for(j=i-1; L.elem[j]>L.elem[0]; j--)
				L.elem[j+1] = L.elem[j];
			L.elem[j+1] = L.elem[0];
		}
		Load_Sq(L);
	}
}

折半插入排序

折半插入排序:在一个有序表中进行查找和插入,利用“折半查找”来实现查找。

void BInsertSort(SqList &L)
{
	int low, high, mid;
	int i, j;
	
	for(i=2; i<=L.length; i++)
	{
		low = 1; high = i-1;
		L.elem[0] = L.elem[i];
		while(low<=high)
		{
			mid = (low + high) / 2;
			if(L.elem[0] < L.elem[mid]) high = mid-1;
			else low = mid+1;
		}
		for(j=i-1; j>=high+1; j--)
			L.elem[j+1] = L.elem[j];
		L.elem[high+1] = L.elem[0];
		Load_Sq(L);
	}
}

希尔排序

希尔排序:又称为“缩小增量排序”。现将整个待排记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。
注意:应使增量序列中的值没有除1之外的公因子,并且最后一个增量必须等于1。
(希尔排序是对直接插入排序改进得到的方法)

void ShellSort(SqList &L)
{
	int i, j, d;
	
	for(d=L.length/2; d>=1; d=d/2)			//比直接插入排序多了最外一层循环 
	{
		for(i=d+1; i<=L.length; i++)
		{
			if(L.elem[i-d] > L.elem[i])
			{
				L.elem[0] = L.elem[i];
				for(j=i-d; j>0 && L.elem[j]>L.elem[0]; j-=d)
					L.elem[j+d] = L.elem[j];
				L.elem[j+d] = L.elem[0];
			}
		}
		Load_Sq(L);
	}
}

交换排序

冒泡排序

冒泡排序(起泡排序):相邻两个关键字比较
判别结束条件:在一趟排序过程中没有进行过交换记录的操作

void BubbleSort(SqList &L)
{
	int i, j, flag;
	ElemType temp;
	
	for(i=1; i<L.length; i++)
	{
		flag = 0;
		for(j=2; j<=L.length-i+1; j++)
		{
			if(L.elem[j-1] > L.elem[j])
			{
				temp = L.elem[j-1];
				L.elem[j-1] = L.elem[j];
				L.elem[j] = temp;
				flag = 1;
			}
		}
		Load_Sq(L);
		if(flag==0) break;
	}
}

快速排序

快速排序:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,已达到整个序列有序。

int Partition(SqList &L, int low, int high)		//一趟 
{
	ElemType pivotkey;
	
	L.elem[0] = L.elem[low];
	pivotkey = L.elem[low];
	while(low < high)
	{
		while(low<high && pivotkey<=L.elem[high]) high--;
		L.elem[low] = L.elem[high];
		while(low<high && pivotkey>=L.elem[low]) low++;
		L.elem[high] = L.elem[low];
	}
	L.elem[low] = L.elem[0];
	return low;
}

void QuickSort(SqList &L, int low, int high)
{
	int pivotloc;
	
	if(low < high)
	{
		pivotloc = Partition(L,low, high);
		Load_Sq(L);
		QuickSort(L, low, pivotloc-1);
		QuickSort(L, pivotloc+1, high);
	}
}

选择排序

简单选择排序

简单选择排序:通过n-i次关键字间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i(1<=i<=n)个记录交换之。

void SelectSort(SqList &L)
{
	int i, j, min;
	ElemType temp;
	
	for(i=1; i<=L.length; i++)
	{
		min = i;
		for(j=i+1; j<=L.length; j++)
			if(L.elem[j] < L.elem[min]) min = j;
		temp = L.elem[i];
		L.elem[i] = L.elem[min];
		L.elem[min] = temp;
		Load_Sq(L);
	}
}

堆排序

下面程序排序结果为“大顶堆”(非递减有序)!
先输出初始建堆后的结果;
其后各行输出交换堆顶元素并调整堆的结果。

void HeapAdjust(SqList &L, int s, int m)	//s是开始比较的父母结点,m是最后一个结点的位置 
{											//大顶堆 
	int i;
	ElemType rc;
	
	rc = L.elem[s];
	for(i=2*s; i<=m; i*=2)
	{
		if(i<m && L.elem[i]<=L.elem[i+1]) i++;
		if(rc >= L.elem[i]) break;
		L.elem[s] = L.elem[i];
		s = i;
	}
	L.elem[s] = rc;
}

void HeapSort(SqList &L)
{
	int i;
	ElemType temp;
	
	for(i=L.length/2; i>0; i--)
		HeapAdjust(L,i,L.length);
	Load_Sq(L);
	for(i=L.length; i>1; i--)
	{
		temp = L.elem[1];
		L.elem[1] = L.elem[i];
		L.elem[i] = temp;
		HeapAdjust(L,1,i-1);
		Load_Sq(L);
	}
}

归并排序

2-路归并排序

2-路归并排序:将一位数组中前后相邻的两个有序序列归并为一个有序序列。
初始n个记录可看成n个有序子序列,前后相邻两两归并。

void Merge(SqList &L, SqList &T, int i, int m, int n)	//L是表一,T是表二,i是表一起点,m是表一终点,n是表二终点 (两个表排序)
{
	int j, k;
	
	k = i; j=m+1;
	while(i<=m && j<=n)
	{
		if(L.elem[i] <= L.elem[j]) 
			T.elem[k++] = L.elem[i++];
		else T.elem[k++] = L.elem[j++];
	}
	while(i<=m) T.elem[k++] = L.elem[i++];
	while(j<=n) T.elem[k++] = L.elem[j++];
}

void MergeSort(SqList &L)
{
	SqList T;
	int start1, end1, start2, end2, i, j;
	
	T.elem = (ElemType *) malloc ((L.length+1) * sizeof(ElemType));
	T.length = L.length;
	
	for(i=1; i<=L.length; i*=2)	//找到两个表的起始位置
	{
		for(start1=1; start1+i-1<L.length; start1=end2+1)
		{
			end1 = start1+i-1;
			start2 = end1+1;
			end2 = start2+i-1;
			if(end2 > L.length) end2 = L.length;
			Merge(L, T, start1, end1, end2);
		}
		for(j=1; j<=L.length; j++) L.elem[j] = T.elem[j];
		Load_Sq(L);
	}	
}

基数排序

基数排序:是和前面所述各类排序方法完全不相同的一种排序方法。前面的方法通过关键字间的比较和移动,而基数排序借助多关键字排序的思想(“分配”和“收集”)。

#include<stdio.h>
#include<string.h>

#define MAX_NUM_OF_KEY 8
#define RADIX 10
#define MAX_SPACE 10000

typedef int KeysType;
typedef struct{
	KeysType keys[MAX_NUM_OF_KEY];
	int next;
}SLCell;
typedef struct{
	SLCell r[MAX_SPACE];
	int keynum;
	int recnum;
}SLList;
typedef int ArrType[RADIX];

void CreateSList(SLList & );
void PrintSList(SLList );
void Distribute(SLList & , int , ArrType & , ArrType & );
void Collect(SLList & , int , ArrType , ArrType );
void RadixSort(SLList & );

int main()
{
	SLList L;
	
	CreateSList(L);
	RadixSort(L);
}

void CreateSList(SLList &L)	//创建
{
	int n, key, i, j, max=0;
	
	printf("请输入待排序关键字个数:\n");
	scanf("%d", &n);
	printf("请输入%d个待排序关键字(用空格隔开):\n", n);
	for(i=1; i<=n; i++)
	{
		scanf("%d", &key);
		for(j=0; key!=0; j++)
		{
			L.r[i].keys[j] = key % 10;
			key = key / 10;
		}
		if(j>max) max = j;
		L.r[i-1].next = i;
	}
	L.keynum = max;
	L.recnum = n;
	L.r[L.recnum].next = 0;
}

void PrintSList(SLList L)	//输出
{
	int p, i;
	
	for(p=L.r[0].next; p; p=L.r[p].next)
	{
		for(i=L.keynum-1; i>=0; i--)
			printf("%d", L.r[p].keys[i]);
		printf(" ");
	}
	printf("\n");
}

void Distribute(SLList &L, int i, ArrType &f, ArrType &e)	//分配
{
	KeysType j;
	int p;
	
	for(j=0; j<RADIX; j++) f[j] = 0;
	for(p=L.r[0].next; p; p=L.r[p].next)
	{
		j = L.r[p].keys[i];
		if(!f[j]) f[j] = p;
		else L.r[e[j]].next = p;
		e[j] = p;
	}
}

void Collect(SLList &L, int i, ArrType f, ArrType e)	//收集
{
	int j;
	int t;
	
	for(j=0; !f[j]; j++);
	L.r[0].next = f[j];
	t = e[j];
	for(j++; j<RADIX; j++)
		if(f[j])
		{
			L.r[t].next = f[j];
			t = e[j];
		}
	L.r[t].next = 0;
}

void RadixSort(SLList &L)
{
	ArrType f, e;
	int i;
	
	for(i=0; i<L.keynum; i++)
	{
		Distribute(L, i, f, e);
		Collect(L, i, f, e);
		PrintSList(L);
	}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 3
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值