数据结构-排序

排序

1、插入排序

基本思想:每一趟将一个待排序的纪录,按其关键字的大小插入到已经排序好的记录的适当的位置上,直到所有的待排序记录全部插入为止。

1.1 直接插入排序

算法步骤
  1. 设所有记录存储在 r [ 1.. n ] r[1..n] r[1..n]中, r [ 1 ] r[1] r[1]是一个已排好的有序序列。
  2. 循环n-1次,每次使用顺序查找法查找 r [ i ] ( i ∈ [ 2 , n ] ) r[ i ](i ∈[2, n]) r[i]i[2,n]在已排好的序列中的插入位置,插入,直到插完。
实现查找
  • 从前往后的顺序查找
  • 从后向前的顺序查找

为了避免查找插入位置时,数组下标出界,在r[0]设置监视哨。

算法分析
  • 时间复杂度
    O( n 2 n^2 n2)
  • 空间复杂度
    O(1)
  • 排序稳定,也适用于链式结构,更适合初始基本有序的情况
void InsertSort(SqList &L){
	int i,j;
	//从小到大直接插入排序
	for(i=2; i<L.length; i++){
		if(L.r[i].key < L.r[i-1].key){					//判断r[i]是插入有序表中还是不动(放在有序表的尾部)
			L.r[0] = L.r[i];							    //将待插入的r[i]放到监视哨r[0]中
			L.r[i] = L.r[i-1];							//将r[i-1]后移,此时r[i-1]相当于空位
			for(j=i-2; L.r[0].key<L.r[j].key; --j){		//从后往前比较,大的往后移
				L.r[j+1] = L.r[j];
			}
			L.r[j+1] = L.r[0];							//将监视哨中元素放下
		}
	}
}

1.2 折半插入排序

相较于直接插入排序不同的是,将其中的查找插入位置的部分,由原来的顺序查找,换成了折半查找

void BInsertSort(SqList &L){
	int i,j,m,low,high;
	//从小到大折半插入排序
	for(i=2; i<L.length; i++){
		if(L.r[i].key < L.r[i-1].key){					//判断r[i]是插入有序表中还是不动(放在有序表的尾部)
			L.r[0] = L.r[i];					    		//将待插入的r[i]放到监视哨r[0]中
			low = 0;									//初始化low
			high = i-1;									//初始化high

			while(low <= high){							//进行折半查找
				m = (low + high)/2;
				if(L.r[i].key > L.r[m].key)
					low = m+1;
				else
					high = m-1;
			}

			for(j=i-1; j>=low; j--)						//折半查找的最后落在low位置
				L.r[j+1] = L.r[j];						//每个后移

			L.r[low] = L.r[0];							//将监视哨中元素放下
		}
	}
}

1.3 希尔排序

基本思想:跳着排

算法步骤
  1. 第一趟每 d d d个数选一个放在一组,每个组进行直接插入排序。
  2. 第二趟每 d − 1 d-1 d1个数选一个放在一组,每个组也是进行排序。
  3. 直到间隔为 1 1 1,即连续时,再次进行排序,得到顺序序列。

2、交换排序

2.1 冒泡排序

基本思想:从底部一个一个像冒气泡一样,大的排到队尾。

算法步骤

设待排序数组$r[1…n]

  1. 第一趟排序: r [ 1 ] r[1] r[1] r [ 2 ] r[2] r[2]比较,若为逆序则交换位置。接下来 r [ 2 ] r[2] r[2] r [ 3 ] r[3] r[3]比较,若为逆序则交换位置……直到 r [ n − 1 ] r[n-1] r[n1] r [ n ] r[n] r[n]比较,若为逆序则交换位置。至此已从待排序列中将最大的数“冒泡”到最后 r [ n ] r[n] r[n]
  2. 第二趟排序,同上,但是由于r[n]已经是排完的有序序列,故只要到 r [ n − 1 ] r[n-1] r[n1]。此趟完成后,待排的数中最大的数“冒泡”到 r [ n − 1 ] r[n-1] r[n1]
  3. 重复上述比较和交换过程,直到在某一趟排序中未发生交换,说明排序完成。
void BubbleSort(SqList &L){
	int m,flag,j;
	num t;
	//对顺序表L做冒泡排序
	m = L.length - 1;
	flag = 1;											//flag用来标记某一趟是否需要交换
	while((m>0) && (flag==1)){
		flag=0;											//flag置为0,如果本趟排序未发生交换,则不会执行下一趟
		for(j=1; j<=m; j++){
			if(L.r[j].key > L.r[j+1].key){
				flag = 1;								//本趟发生交换
				t = L.r[j];
				L.r[j] = L.r[j+1];
				L.r[j+1] = t;
			}
		}
		--m;
	}
}

2.2 快速排序

int Partition(SqList &L, int low, int high){
	int pivotkey;
	//对顺序表L中的子表r[low..high]进行排序,并返回枢纽位置
	L.r[0] = L.r[low];
	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];
	return low;
}

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

void QucikSort(SqList &L){
	QSort(L, 1, L.length-1);
}

3、选择排序

3.1 简单选择排序

void SelectSort(SqList &L){
	int i,j,k;
	num t;
	//对顺序表L做简单选择排序
	for(i=1; i<L.length; i++){
		k = i;
		for(j=i+1; j<L.length; j++){
			if(L.r[j].key < L.r[k].key)
				k = j;
			if(k!=i){
				t = L.r[i];
				L.r[i] = L.r[k];
				L.r[k] = t;
			}
		}
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值