【数据结构严蔚敏】第十章-内部排序【期末复习】

基本概念

1.排序:使元素按关键字有序排列
2.内部排序:待排记录都在内存当中
3.稳定与不稳定:待排序元素中的两个元素a,b,a在b之前且a的关键字与b的关键字相同,排序后二者的相对位置不变,则称排序方法为稳定的,否则称为不稳定的。
存储结构:

typedef struct {
	KeyType key;
	//... other infomation
}RedType;	//记录类型 Record Type
typedef struct{
	RedType r[MAXSIZE + 1]; // 0 号作哨兵
	int lenght;
}SqList;

插入排序

  • 直接插入排序 O ( n 2 ) O(n^2) O(n2),稳定
void InsertSort(SqList &L){
	int i,j;
	for(i = 2; i < n; i++){
		if(L.r[i].key < L.r[i-1].key){
			L.r[0] = L.r[i];	//哨兵
			L.r[i] = L.r[i-1];	//i-1后移
			for(j = i - 2; L.r[j].key > L.r[0].key; j--)
				L.r[j+1] = L.r[j];	//后移
			L.r[j+1] = L.r[0];	//插入到正确位置
		}
	}
}
  • 折半插入排序
    折半寻找插入位置。比较次数为 O ( n l o g n ) O(nlogn) O(nlogn),移动次数没有减少,时间复杂度仍为 O ( n 2 ) O(n^2) O(n2)
void BinInsertSort(SqList &L){
	for(int i = 2; i <= L.length; i ++){
		int low = 1,high = i - 1;
		L.r[0] = L.r[i];	//哨兵
		while(low <= high){
			int mid = (low + high)/2;
			if(L.r[mid].key < L.r[0].key) low = mid + 1;
			else high = mid - 1;
			//不考虑key相等是稳定的
		}
		//退出循环时,low > high, low 是要插入的位置
		for(int j = i - 1; j >= low; j--)L.r[j+1] = L.r[j];
		L.r[low] = L.r[0];
	}
}
  • 希尔排序
    将待排序列按除d同余划分为若干等价类,在类内排序,d逐渐减小,保证最后d = 1。
    原理:对于有序序列,插入排序的时间复杂度为O(n);
    希尔排序的时间复杂度 O ( n 1.5 ) O(n^{1.5}) O(n1.5)左右,不稳定
void ShellInsert(SqList &L,int dk){
	int  i,j;
	for(i = dk + 1; i <= L.length; i++){	//前dk个元素分组
		L.r[0] = L.r[i];
		for(j = i - dk;j > 0&&L.r[j].key > L.r[0].key; j-=dk)	//j > 0,考虑当前元素最小
			L.r[j+dk] = L.r[j];
		L.r[j+dk] = L.r[0];
	}
}
void ShellSort(SqList &L,int d[],int t){
	for(int i = 0; i < t; i++)
		ShellInsert(L,d[t]);	//保证增量序列互质,且d[t-1] = 1
}

交换排序

  • 冒泡排序(气泡排序),稳定
void BubbleSort(SqList &L){
	for(int i = 1; i < L.length; i++){	//n - 1 趟 , L.r[L.lenth]有元素
		for(int j = 2; j <= L.length - i + 1; j ++){
			if(L.r[j-1].key > L.r[j].key)
				swap(L.r[j-1],L.r[j]);
		}
	}

}
  • 快速排序
    不稳定,A(n) = O(nlogn);
    最坏情况,序列有序,枢轴总是取low, O ( n 2 ) O(n^2) O(n2);
int Partition(SqList &L,int low,int high){	//返回枢轴的位置
	L.r[0] = L.r[low];
	int pivotkey = L.r[low].key;
	while(low < high){
		while(low < high&&L.r[high].key >= pivotkey)high--;
		L.r[low] = L.r[high];
		while(low < high&&L.r[low].key <= pivotkey)low++;
		L.r[high] = L.r[low];
	}
	L.r[low] = L.r[0];	//low == high
	return low;
}
void QuickSort(SqList &L,int low ,int high){
	if(low < high){
		int m = Partition(L,low,high);
		QuickSort(L,low,m-1);
		QuickSort(L,m+1,high);
	}
}

选择排序

  • 简单选择排序 O ( n 2 ) O(n^2) O(n2),稳定
    每趟挑出第i小的元素,放在i的位置。
void SelectSort(SqList &L){
	for(int i = 1; i <= L.length; ++ i){	//第i小的元素
		int min = i;
		for(int j = i+1; j <=L.length; ++j){
			if(L.r[j].key < L.r[min].key)
				min = j;
		}
		swap(L.r[i],L.r[min]);
	}
}
  • 堆排序:
    最坏最后都是 O ( n l o g n ) O(nlogn) O(nlogn),不稳定,n较大时使用
    堆:完全二叉树
    大根堆:
    a i ⩾ a 2 i , a i ⩾ a 2 i + 1 , a_i \geqslant a_{2i},a_i \geqslant a_{2i+1}, aia2i,aia2i+1,
    小根堆:
    a i ⩽ a 2 i , a i ⩽ a 2 i + 1 , a_i \leqslant a_{2i},a_i \leqslant a_{2i+1}, aia2i,aia2i+1,
    存储结构:
    因为是完全二叉树,可用顺序表存储
    R[MAXSIZE];
    调整操作
void HeapAdjust(int R[],int i,int n){//大根堆调整
	//调整操作的前提是,除去调整结点,调整结点的左右树都是堆
	//R[i+1...n]都满足堆定义,R[i]是要调整的结点。
	int rc = R[i];
	for(int j = 2*i; j<=n; j*=2){	//*2跳到下一层
		if(j < n && R[j+1] > R[j] )j++;
		if(rc>=R[j])break;
		R[i] = R[j]; i = j;
	}
	R[i] = rc;
}
void HeapSort(int R[],int n){	//大根堆得升序数组
	for(int i = n/2; i >=1 ; --i)
		HeapAdjust(R,i,n);
	for(int i = 0; i < n; i++){	//n-1次排序
		swap(R[1],R[n-i]);
		HeapAdjust(R,1,n-i-1);	//排完序输出数组即可
	}
}

归并排序

void MSort(RcdType s[],int l,int r){
	if(l < r){
		int m = (l+r)/2;
		MSort(s,l,m);
		MSort(s,m+1,r);
		Merge(s,l,m,r);
	}
}
void Merge(RcdType s[],int l,int m,int r){
	RcdType t[MAXSIZE] = {0};	//临时数组
	int i,j,k = 0;
	for( i = l,j = m + 1; i <= m && j <=r;){	//合并两个升序数组
		if(s[i].key < s[j].key)
			t[k++] = s[i++];
		else
			t[k++] = s[j++];
	}
	while(i<=m)t[k++] = s[i++];
	while(j<=r)t[k++] = s[j++];
	for(i = l,k = 0;i <= r; i ++,k++)	//拷贝回s;
		s[i] = t[k];
}
void MergeSort(SqList &L){
	MSort(L.r,1,L.length);
}

基数排序

桶排序,桶可以用队列实现。
不通过比较,而是分配收集的方法实现排序,稳定
O(k*(n+m)); k 维,每维分配n次,收集m次
典例:按年月日排序,极快。
扑克排序:花色桶*4,序号桶1-13。
如果想一次解决,就设max个桶,耗空间。

void RadixSort(int a[],int max,int n){
	vector<queue<int> >  v(10);
	int d = 1;
	while(max/d){
		d*=10;
		for(int i = 0; i < n; i++)	//分配 
			v[a[i]%d].push(a[i]);
		int k = 0;
		for(int i = 0 ; i < 10; i++){	//收集 
			while(v[i].size()){
				a[k++] = v[i].front();
				v[i].pop();
			}
		}
	}
}

总结

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值