数据结构-6种内部排序算法

排序算法

  • 本文将列举常用的线性表的排序算法的c++ 实现 供读者参考。涉及到的排序算法有:插入排序(3种)、交换排序(2种)、归并排序
    (假设小于为正序)
  • 详细介绍:
  1. 直接插入排序:
    该算法采用朴素的比较方式,在有序序列中寻找待插入元素的位置,为节省运算采用从后往前的方式进行查找(每次将正序序列元素后移一位) .
    这种方式是稳定的。
//straight insert
void StraightInsertSort(int * n,int start,int end){
	for(int i = start+1;i<=end;i++){
		int k = n[i],j;//记录
		for(j = i-1;j>=start;j--){
			if(n[j]>k){
				n[j+1] = n[j];
			}else{
				n[j+1] = k;
				break;
			}
		}
		if(j<start)n[start]=k;
	}
}
  1. 折半插入排序:
    该算法的思路是基于直接插入排序的,采用二分的方法在有序序列中查找到待插入的元素的位置,进行插入,优化了比较次数。 这种方式是也稳定的。
//binaryinsert
void BinaryInsertSort(int * n,int start,int end){
	for(int i = start+1;i<=end;i++){
		int k = n[i];//记录
		///binary find first index that below index==k
		int left = start,right = i-1;
		while(left<=right){
			int mid = left+(right-left)/2;
			if(n[mid]>k)right = mid-1;
			else left = mid+1;
		}
		for(int j = i-1;j>=left;j--)n[j+1] = n[j];
		n[left] = k;
	}

}
  1. 希尔排序:
    希尔排序本质上也是直接排序,只不过将序列按照一定间隔(n/2)划分然后对每一部分进行直接插入排序,之后减小间隔(一直到间隔为1为止)重复以上过程。 这种方式是不稳定的。
//sheel
void ShellSort(int * num,int start,int end){
	int n = end-start+1;
	int d = n/2;
	while(d>=1){
		for(int k = 0;k<d;k++){// the Kth group
			for(int i = start+k+d;i<=end;i+=d){
				int index = num[i];
				for(int j = i-d;j>=start;j-=d){
					if(num[j]>index)num[j+d] = num[j];
					else {
						num[j+d] = index;
						break;
					}
				}
			
			}
			
		}
		d /=2;
	}
}
  1. 快速排序:
    c++ stl 库自带的sort 函数则采用的是本算法。它采用简单的递归实现排序,将序列划分为比轴大,比轴小的两部分,然后对这两部分进行类似划分,直到无法划分为止(片段元素个数为1).其核心算法是划分算法,具体有两种。

第一种划分方式:

//Partiton way 1
int Partition1(int * n,int start,int end){
	int l = start;int r = end;
	int axis = n[start];//轴
	while(l<r){
		while(l<r&&n[r]>axis)r--;
		n[l] = n[r]; // l 位置其实已经记录过了所以它相当于是空的,所以可以存放元素
		while(l<r&&n[l]<=axis)l++;
		n[r] = n[l]; //在移动 r 的过程中 r 位置的元素已经换走 r 位置相当于是空 所以可以用来存放元素 
	}
	//end in l == r;  结束时候 l == r
	n[l] = axis;
	return l;
}

第二种划分方式

//Partition way 2
int Partition2(int * d,int start,int end){
	int left = start;int right = end;
	int axis = d[start];
	while(left<=right){
		while(left<=right&&d[left]<= axis)left++;
		while(left<=right&&d[right]>axis)right--;
		if(left<right){
			int temp = d[left];
			d[left] = d[right];
			d[right] = temp;
			left++;right--;
		} 
	}
	//end in right = left -1; 结束条件是 r == l -1
	int temp = d[start];
	d[start] = d[right];
	d[right] = temp;
	return right;
}

在有了划分函数之后快速排序就十分简单了(但是人就可能会出现爆栈等问题/这是由于机器决定的,毕竟是递归?)。同时这种方式是不稳定的。

void qsort(int * n ,int start,int end,int ch = 0){
	if(start>=end)return;
	int axis;
	if(ch == 0)axis = Partition1(n,start,end);
	else axis = Partition2(n,start,end);
	
	qsort(n,start,axis-1,ch);
	qsort(n,axis+1,end,ch);
}
  1. 冒泡排序:
    作为最朴素的交换排序方式,冒泡经常被人调侃,原理十分简单,乱序则交换。这种方式是稳定的。
//Bubble sort
void BubbleSort(int * d,int start,int end){
	bool flag = true;//优化冒泡
	for(int i = end;i>start&&flag;i--){
		flag = false;
		for(int j = start;j<i;j++){
			if(d[j]>d[j+1]){
				int temp = d[j];
				d[j] = d[j+1];
				d[j+1] = temp;
				flag = true;
			}
		}	
	}
}
  1. 归并排序:
    归并排序采用合并有序序列的思路,原理也是十分简单的,它同样是采用递归实现的。这种方式是稳定的。
    合并函数
//mergesort
void Merge(int * d,int start,int mid,int end){
	int len1 = mid-start+1;
	int len2 = end-mid;
	int * left = new int[len1];
	int * right = new int[len2];
	for(int i = 0;i<len1;i++)left[i] = d[start+i]; 
	for(int i = 0;i<len2;i++)right[i] = d[mid+1+i]; 
	int i =0, j = 0;
	int k = start;
	while(i<len1&&j<len2){
		if(left[i]<right[j]){
			d[k] = left[i];
			i++;
		}else{	
			d[k] = right[j];
			j++;
		}
		k++;
	}
	while(i<len1)d[k++] = left[i++];
	while(j<len2)d[k++] = right[j++];
	delete []left;
	delete []right;
}

在有了合并函数之后,归并排序实现如下:

void Mergesort(int * n,int start,int end){
	if(start>=end)return;
	int mid = (start+end)/2;
	Mergesort(n,start,mid);//左半部分有序
	Mergesort(n,mid+1,end);//右半部分有序
	Merge(n,start,mid,end);//合并两部分
}
  • 当然除此之外还有别的排序方式,如:堆排序,基数排序等。这些排序方式在这里就不再叙述了
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值