排序算法

0. 排序基本概念

  1. 定义:整理文件的记录次序,使其按关键码递增(或递减)次序进行排列。
  2. 稳定性:多个关键吗星通的记录,经过排序后,这些具有相同关键码记录之间的相对次序保持不变,则称排序是稳定的
  3. 原地排序:不需要额外的空间(允许少量空间)进行排序

1. 插入排序

定义:将待排序的记录,按其关键码的大小插入到已经排好序的有序子表中,直至全部插入完成为止。

1.1 直接插入排序

一次将记录序列中的每一个记录插入到有序段中,使有序段的长度不断扩大,最初的有序段为第一个元素本身。

void InsertSort(int s[],int len)
{
	for (int i = 1; i < len; i++)
	{
		int j, tmp = s[i];
		for (j = i - 1; j >= 0; j--)
		{
			if (tmp < s[j])
				s[j + 1] = s[j];
			else break;
		}
		s[j + 1] = tmp;
	}
}

1.2 二分插入排序

  1. 前提是对有序表插入
  2. 先二分查找找到插入的位置
  3. 再将后面的元素后移,留出空位
  4. 插入

1.3 表插入排序

  1. 不移动记录的情况下排序
  2. 通过移动指针进行排序
  3. 在插入第 i 个记录 Ri 时,R1,R2,R3,……Ri-1 已经通过各自的指针排好序了,然后依次比较找到合适的位置插入

1.4 希尔排序(缩小增量排序)

算法思想:将待排序的记录分成几组,从而减少参与直接插入排序的数据量,当经过几次分组排序后,记录的排列已经基本有序了,这个时候在对所有的记录实施直接插入排序。

void ShellSort( ElementType A[], int N )
{ /* 希尔排序 - 用Sedgewick增量序列 */
     int Si, D, P, i;
     ElementType Tmp;
     /* 这里只列出一小部分增量 */
     int Sedgewick[] = {929, 505, 209, 109, 41, 19, 5, 1, 0};
     
     for ( Si=0; Sedgewick[Si]>=N; Si++ ) 
         ; /* 初始的增量Sedgewick[Si]不能超过待排序列长度 */

     for ( D=Sedgewick[Si]; D>0; D=Sedgewick[++Si] )
         for ( P=D; P<N; P++ ) { /* 插入排序*/
             Tmp = A[P];
             for ( i=P; i>=D && A[i-D]>Tmp; i-=D )
                 A[i] = A[i-D];
             A[i] = Tmp;
         }
}

2. 交换排序

算法思想:将待排序记录的关键码进行两两比较,发现两个记录次序相反时就进行交换,知道没有相反记录为止

2.1 冒泡排序

算法思想:对所有相邻记录的关键码值进行比较,如果是逆序,则交换,重复这个过程直至整个序列有序

void BubSort(int s[], int len)
{
	bool tmp = false; //记录是否交换
	for (int i = 0; i < len - 1; i++)
	{
		for (int j = 0; j < len - 1; j++)
		{
			if (s[j] > s[j + 1])
			{
				swap(s[j], s[j + 1]);
				tmp = true;
			}
		}
		if (tmp)
			tmp = false;
		else break;
	}
}

2.2 快速排序

算法思想:首先将待排序记录序列中所有记录作为当前待排序区域,选取第一个记录的关键码值为基准(轴值),从待排序记录序列左右两端向中间靠拢,交替与轴值比较,若左侧记录大于轴值,则将该纪录移到基准记录右侧,若右侧记录小于轴值,则将该记录移到基准记录左侧,至此,基准记录将待排序记录分为左右两块,左侧的所有记录小于基准记录,右侧的所有记录大于基准记录,这就是一趟快速排序,然后再堆左右两个区域进行快速排序,重复这个过程直至每个区域只含有一个记录,这时整个序列有序

int qSort(int s[], int L, int R)
{
	int piv = L;
	int p = s[piv];
	for (int i = L + 1; i <= R; i++)
	{
		if (s[i] < s[piv])
		{
			piv++;
			if (i != piv)
				swap(s[i], s[piv]);
		}
	}
	s[L] = s[piv];
	s[piv] = p;
	return piv;
}
void QSort(int s[], int L,int R)
{
	if (L < R)
	{
		int piv = qSort(s, L, R);
		QSort(s, L, piv - 1);
		QSort(s, piv + 1, R);
	}
}

void QuickSort(int s[], int len)
{
	QSort(s, 0, len - 1);
}

3. 选择排序

算法思想:每一次从待排序的记录中选出最小的。放在已排序的子序列后面,直至序列有序

3.1 线性选择排序

算法思想:新建一个空间,从未排序的序列中找到最小的,放在新的空间内,重复这个过程直至未排序的序列为空

3.2 交换线性选择排序

算法思想:将序列分为有序区域和无序区域,初始时有序区域为空,将无序序列中最小与无序区域后第一个元素交换,重复这个过程直至无序序列为空

void SelectSort(int s[], int len)
{
	for (int i = 0; i < len - 1; i++)
	{
		int min = s[i];
		for (int j = i+1; j < len; j++)
		{
			if (s[min] > s[j])
				min = j;
		}
		swap(s[min], s[i]);
	}
}

3.3 堆排序

算法思想:将所有元素建堆,建好以后不断弹出堆顶元素,放入序列末尾(初始序列为空),直至堆为空,此时序列有序

void HeapSort(vector<int>& s, int len)
{
	priority_queue<int> heap;
	for (int i = 0; i < len; i++)
		heap.push(s[i]);
	for (int i = len - 1; i >= 0; i--)
	{
		s[i] = heap.top();
		heap.pop();
	}
}

4. 归并排序

算法思想:利用“归并”进行排序,将n个待排序的序列看作n个长度为1的有序序列,两两归并得到【n/2】个有序序列。重复这个过程直至有序序列个数为1.

void MergeTwo(int s[], int L, int midR, int R,int n[]) 	//合并两部分
{
	for (int i = L, j = midR + 1,l=L; l<=R;l++)
	{
		if (i<=midR&&s[i] < s[j])
		{
			n[l] = s[i];
			i++;
		}
		else {
			n[l] = s[j];
			j++;
		}
	}
	for (int i = L; i <= R; i++)
		s[i] = n[i];
}
void MSort(int s[],int L,int R,int n[])
{
	if (L < R)
	{
		MSort(s, L, (L + R) / 2,n);		//对左半部分排序
		MSort(s, (L + R) / 2+1,R ,n);	//对右半部分排序
		MergeTwo(s, L, (L + R) / 2, R,n); 	//合并两部分
	}
}
void MergeSort(int s[],int len)
{
	if (len > 1)
	{
		int* n = new int[len] {};
		MSort(s, 0, len - 1,n);
		
		delete[] n;
	}
}

5. 基数排序

算法思想:基于关键词的性质进行排序

5.1 多键排序

有多个关键词进行排序

  1. 最高位优先 MSD
    先对主关键码进行排序,将序列分为若干个子序列,在子序列中对次一级的关键码排序,重复这个过程到没有关键码用完。然后从优先级最低L级的关键字开始排序,把所有L+1级关键码相同的子序列排序,重复这个过程直至所有子序列连接在一起。
  2. 最低位优先 LSD
    与上面的的优先级顺序相反

5.2 桶排序

算法思想:设置若干个桶,依次扫描待排序序列,将键值相等的记录放在同一个桶里,然后依次连接各个桶。

5.3 链式基数排序

算法思想:最主要的是拆键,将一个键拆成多个键,比如512这个数拆分为5 , 1 , 2 三个键,然后用低位优先的多键排序,顺序是 2 -->1 -->5 如此如此即可

6. 其他排序

6.1 二叉树排序法

  1. 建立二叉树
  2. 中序遍历二叉树

6.2 计数排序法

和冒泡排序很像,但不需要交换,需要额外的空间存储计数数组

void CSort(int s[], int len)	//计数排序
{
	int* num = new int[len] {};//建立计数数组
	for (int i = 0; i < len-1; i++)		//循环与后面的数比较
	{
		for (int j = i + 1; j < len;j++)
		{
			if (s[i] < s[j])	//较大的数计数器+1
				num[j]++;
			else num[i]++;
		}
	}
}

7.各种内排序比较

在这里插入图片描述

8. 外排序

8.1 自然归并排序法

  1. 扫描一遍原始数据
  2. 将初始有序的子序列归并得到有序序列

8.2 k路归并法

将k个归并段归并为一个大的归并段(零头除外)

8.3 多段归并法

每次将有序段最小的磁带与其他磁带中有相同数目的有序段作k路归并,然后将结果写入空白磁带上,重复直至归并为一个有序序列为止

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值