排序问题C++

虽临近期末考试,但仍要总结一下各种排序算法。

以下默认全部为升序排序(从小到大)
如果一种排序算法能够保证同值元素之间的相对次序不变则称为稳定排序

选择排序(selection sort)

选择排序的方法十分简单。第i次搜索,搜索从第i个元素到第n个元素中的最小值,将其放到第i的位置上。(将原来第i位置的元素与后面的最小值进行交换即可)
依次循环,循环到最后一个元素,即可终止算法。

算法思路的核心就是每次选择最小的,放到前面对应的位置。这样整个序列就分为前面排好序的序列和后面待排序的序列。
很明显复杂度在 O ( n 2 ) O(n^2) O(n2)级别上。
实现代码

void select_sort(int * element,int n){
	for(int i=0;i<n;i++){
		int min=i;   //give the first search index to min
		for(int j=i;j<n;j++){
			if(element[min]>element[j]){
				min=j;
			}
		}
		swap(element[min],element[i]);  //let the minnest value to ith
	}
}

插入排序(insertion sort)

插入排序的思路与选择排序类似。需要从头到尾扫描一次,每到一个元素,就搜索它前面已经有序的序列中寻找它应当在的位置,继续保证前边序列有序。

选择排序是搜索后方最小的元素直接放到前面的某个位置,此时这个值就在这个位置,在后续搜索过程中也不会变化。
而插入排序,是在遍历序列的过程中,始终保证到搜索点前端序列是有序的。这样直到最后一个元素,插入前n-1个序列中,就保证了前n个元素序列是有序的。

实现代码

void insert_sort(int * element,int n){
	for(int i=0;i<n;i++){
		int index=i;  //search from index
		while(index>0&&element[index-1]>element[index]){
			swap(element[index-1],element[index]);
			index--;  //find the previous node
		}
	}
}

冒泡排序(bubble sort)

冒泡排序每次从头开始遍历整个序列,每一次遍历,从开始的元素依次向后比较,两两进行比较,将大的元素放到后边。这样每一次循环都会将一个最大元素放到后面(第一次将最大的元素放到第n位置,第二次将次大的元素放到n-1的位置,依次进行),这就就保证后面的序列是有序的,当执行n次循环时,那倒数n个的序列都有序,即整个序列有序

这个算法相当于插入排序的一个倒序过程。
插入排序保证前面是有序的
冒泡排序保证后面是有序的。而且还保证了每一次放到第i位置的元素就是第i大,之后的循环不会影响它的位置了。(这就与选择排序部分相似)

实现代码

void bubble_sort(int * element,int n){
	for(int i=0;i<n;i++){//this is the times
		for(int j=0;j<n-1-i;j++){
			if(element[j]>element[j+1]) swap(element[j],element[j+1]);
		}
	}
}

基数排序(radix sort)

基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。

首先确定需要比较的位数(通过最大值确定),然后依次从低位进行比较。每个位数的比较通过计数排序获得。

计数排序中最巧妙地部分在于

	//very important
	for(int i=1;i<10;i++){
		record[i]+=record[i-1];
	}

通过累计求和可以很方便的确定第i个元素应当在有序数组的中的位置。

实现代码

void count_sort1(int * element,int n,int exp){
	int * result=new int [n];
	int record[10];  //record the count
	for(int i=0;i<10;i++) record[i]=0;

	//get the record
	for(int i=0;i<n;i++){
		record[(element[i]/exp)%10]++;
	}

	//very important
	for(int i=1;i<10;i++){
		record[i]+=record[i-1];
	}

	//cause the result list
	for(int i=n-1;i>=0;i--){
		result[record[(element[i]/exp)%10]-1]=element[i];
		record[(element[i]/exp)%10]--;

	}
	//make the result to element
	for(int i=0;i<n;i++){
		element[i]=result[i];
	}
}

void  radix_sort(int * element,int n){
	int exp;   //record the point
	//get the max number
	int maxx=element[0];
	for(int i=1;i<n;i++){
		if(maxx<element[i]) maxx=element[i];
	}
	//count sorting according to each order
	for(exp=1;maxx/exp>0;exp=exp*10){
		count_sort1(element,n,exp);
	}
	return;
}

桶排序(bucket sort)

堆排序(heap sort)

堆排序主要用最小堆的性质,每次取出最小元素放到有序数组中。
当然也可以直接在element元素中手动实现最大堆(先进行初始化,再依次取出最大元素放到(数组末尾 − i -i i)的位置,直到最后整个数组就是从小到大的有序数组。)

void stack_sort(int* element,int n){
	priority_queue<int,vector<int>,greater<int>> que;
	for(int i=0;i<n;i++)
		que.push(element[i]);

	int index=0;
	while(!que.empty()){
		element[index++]=que.top();
		que.pop();
	}
	return;
}

计数排序(count sort)

将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。

void count_sort(int * element,int n,int maxx){
		
	int* record=new int [maxx+1];
	//inital
	for(int i=0;i<=maxx;i++){
		record[i]=0; 
	}

	//counting
	for(int i=0;i<n;i++){
		record[element[i]]++;
	}
	//cause new list
	int index=0;
	for(int i=0;i<=maxx;i++){
		while(record[i]!=0){
			element[index++]=i;
			record[i]--;
		}
	}
	
	delete [] record;
}

快速排序(quick sort)

快速排序的主要思想就是每次将待排序的序列分成两部分,前一部分的序号都小于后一部分,之后分别对着两部分进行排序。

详细图解:快速排序

首先需要挑出一个作为基准,重新排序序列,把所有比基准小的数放到基准的前面,把所有比基准大的数放到基准的后边。
完成操作后,即将排序分成了两部分。然后递归进行即可。

template<typename T>
void Quick_sort <T> ::quicksort(int left,int right){
    if(left>right) return;
    int i,j;
    i=left;j=right;
    T temp=element[left];  //start
    while(i!=j){
        while(element[j]>=temp&&i<j){j--;}  //find the element smaller than temp at right series
        while(element[i]<=temp&&i<j){i++;}  //find the element bigger than temp at left series

        if(i<j){
            T record=element[i];
            element[i]=element[j];
            element[j]=record;
        }

    }
    //change the middle and the start element
    element[left]=element[i];
    element[i]=temp;
    
    quicksort(left,i-1);
    quicksort(i+1,right);

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值