排序算法

冒泡排序和选择排序
  • 冒泡排序的本质就是交换,选择排序的本质就是求最大最小,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <bits/stdc++.h>
using namespace std;
int main(){
	int g;
	void bubblesort(int a[],int g);
	void selectsort(int a[],int g) ;
	while(1){
		if((cin>>g)==0)break;
		int a[g];
		for(int i=0;i<g;i++) cin>>a[i];
	    //selectsort(a,g);
	    bubblesort(a,g);
		for(int i=0;i<g;i++){
			if(i==g-1) cout<<a[i]<<endl;
			else cout<<a[i]<<" ";
		}
	}
}
//冒泡排序 
void bubblesort(int a[],int n) {
	//把最大的冒到最后一个,倒数第二个,依次进行 
	int temp;
	for(int i=0;i<=n-1;i++)  		//n-1是小一位数 ,因为外循环要比n-1次,如三次比两次就好了 
		for(int j=0;j<=n-i-1;j++)   //不能j=i+1
		/*也可以这样写 
		for(int i=1;i<n;i++)
		for(int j=0;j<n-i;j++)    //1  n  0  n-i 
		*/
			if(a[j]>a[j+1]){
				temp=a[j];
				a[j]=a[j+1];
				a[j+1]=temp;
			//a[j+1]=temp;这行是a[j+1]而不是 a[j] 
			//或者  swap(a[j],a[j+1]);
			}
	}
    //选择排序
void selectsort(int a[],int n) {
	//if(a[j]<a[index]) index=j;  index存放最小值(最大值)的下标
	//就是把最小的换到第一个位置 ,第二小的换到第二位置,依次排列 
	int temp,index;
	    for(int i=0;i<n-1;i++){    //比较n-1次就行了   0  n-1  i+1  n
		index=i; 				  //假设i=0为最小值(最大值)的下标 
		for(int j=i+1;j<n;j++)    //是j<n而不是n-1 
			if(a[j]<a[index]) index=j;  
		temp=a[index];    //最小值(最大值)与下标为i的换 
		a[index]=a[i];
		a[i]=temp;
		}
	}
插入排序(挪动数组)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//插入排序实现从小到大排列(若果想从大到小排列,那么改为if(a[k-1)<x) a[k]=a[k-1],这样的话就是当前位置的数比x小就往后移。
#include<iostream>
    #include<cstdio>
    using namespace std;
    #define N 5
    int a[N];//有序数组
    int main ( ) {
    	int i, k, x;
    	printf("Please input %d numbers:\n",N);   
    	for (i=0; i<N; i++) {
    		scanf ("%d", &x);
    		for ( k=i; k>0; k-- ) {	        /* 从后向前比较 */
    			if ( a[k-1] > x )    //x前面的数比它大
    				a[k]=a[k-1];         /* 将大数向后移动*/
    			else      break; /* 找到插入的位置,退出 */
    		}
    		a[k] = x;  /* 完成插入操作 */
    	}
    
    	for (i=0; i<N; i++)
    		printf("%d ", a[i]);
    	return 0;
    }
快速排序(分治法的一个体现)

upload successful

  • 快排之单向扫描分区法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include<bits/stdc++.h>
using namespace std;
//快速排序单向扫描分区法 
void swap(int A[],int p,int r){
	//交换数组A下标为p和r的值 
	int tmp=A[p];
	A[p]=A[r];
	A[r]=tmp;
	
}
int partition(int A[],int p,int r){
	int pivot=A[p];//初始化pivot(主元)指向A[p],就是最靠左的位置 
	int sp=p+1;  //扫描指针 
	int bigger=r; //右侧指针 
	while(sp<=bigger){  //bigger指向的 
		if(A[sp]<=pivot) //扫描元素小于主元,右指针向右移 
			sp++;
		else{
			swap(A,sp,bigger);//扫描元素大于主元,二指针的元素互换,右指针左移 
			bigger--;
		} 
	}
	swap(A,p,bigger);
	return bigger;
}
void quickSort(int A[],int p,int r){
	if(p<r){
		int q=partition(A,p,r);
		quickSort(A,p,q-1);
		quickSort(A,q+1,r);
	}
}

int main(){
	int a[]={11,9,2,9,4,6};
	quickSort(a,0,5);//因为从0开始存的,所以此时的右侧指针为下标5
	for(int i=0;i<6;i++)
	cout<<a[i]<<" ";
}
  • 双向扫描法
    upload successful
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include<bits/stdc++.h>
using namespace std;
//快速排序双向扫描分区法 
//void swap(int A[],int p,int r){
//	//交换数组A下标为p和r的值 
//	int tmp=A[p];
//	A[p]=A[r];
//	A[r]=tmp;
//	可以用stl中的swap函数来交换两个数或数组的值 
//}
int partition2(int A[],int p,int r){
	int pivot=A[p];//初始化pivot(主元)指向A[p],就是最靠左的位置 
	int left=p+1;  //左侧指针 
	int right=r; //右侧指针 
	while(left<=right){  
	//left不停的往右走,直到遇到大于主元的元素 
		while(left<=right&&A[left]<=pivot)left++;
		//上面这个循环退出时,left一定是指向第一个大于主元的位置 
		while(left<=right&&A[right]>pivot)right--;
		//上面这个循环退出时,right一定是指向最后一个小于或等于主元的位置 
		if(left<right)
			swap(A[left],A[right]);
	}
	//while退出时,两者相错,且right指向的是最后一个小于等于主元的位置,也就是主元应该待的位置 
	swap(A[p],A[right]);
	return right;
}
void quickSort(int A[],int p,int r){
	if(p<r){
		int q=partition2(A,p,r);
		quickSort(A,p,q-1);
		quickSort(A,q+1,r);
	}
}

int main(){
	int a[]={11,9,2,9,4,6};
	quickSort(a,0,5);
	for(int i=0;i<6;i++)
	cout<<a[i]<<" ";
}
  • 三指针分区法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44


void quickSort(int a[], int low, int high)

{

    if (low <= high)

        return;

    int i = low;

    int j = high;

    int key = a[i];


    while (i < j)

    {

        while (i < j && a[j] >= key)

            --j;

        a[i] = a[j];

        while (i < j && a[i] <= key)

            ++i;

        a[j] = a[i];

    }


    a[i] = key;


    quickSort(a, low, i - 1);

    quickSort(a, i + 1, high);

}
  • 3.6 快排在工程实践中的优化

希尔排序 

upload successful

  • 希尔排序的过程

    • 希尔排序在排序前:将一个序列分成了好几个序列
    • 在第一趟排序时:将这几个序列做插入排序。
    • 在第二趟排序时:将这个序列又分了好几个序列做插入排序。
    • …………….
    • 在第n趟排序时:将原序列进行插入排序,从宏观上看,此序列就基本是有序的了。这时就用简单插入排序将数列直至已序

    从直观上看希尔排序:
    就是把数列进行分组(不停使用插入排序),直至从宏观上看起来有序,最后插入排序起来就容易了(无须多次移位或交换)。就是increase后面的第一个分组中的元素和数列的第一个分组比较,然后后面第二个分组和数列的第二个分组比较....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//希尔排序的java实现数组从小到大排列
public static void shellSort(int[] nums){
    for(int increase = nums.length/2;increase > 0;increase/=2){//increase为希尔排序增量
        //对每一个增量序列进行插入排序
        for(int i = increase;i<nums.length;i++){
            int target = nums[i];
            int j = i - increase;
            while(j>=0 && target<nums[j]){
                nums[j+increase] = nums[j];
                j = j - increase;  //进行下一组的排序
            }
            nums[j+increase] = target;
        }
    }
}

c++的实现


#include<bits/stdc++.h>
using namespace std;
template <typename T> void ShellSort(T *array, const int length)
{
    int gap = length/2;
    do{//第一次因为length不为0,所以肯定能执行一次while语句 
        T tmp;
        for(int i=gap; i<length; ++i){
            tmp = array[i];
            int j = i;
            while(j>=gap && tmp<array[j-gap]){
                array[j] = array[j-gap];
                j-=gap;
            }
            array[j] = tmp;
        }
        gap/=2;
    }while(gap);
}
int main(){
	int a[5]={12,1,6,3,2};
	ShellSort(a,5);
	for(int i=0;i<5;i++)cout<<a[i]<<" ";
}

归并排序

upload successful

upload successful

#include<bits/stdc++.h>
using namespace std;

//归并过程
void merge(int arr[], int l, int mid, int r){
    int help[r-l+1];//辅助数组
    int i = 0;
    int lIndex = l;
    int rIndex = mid+1;
    while(lIndex <= mid && rIndex <= r){
        help[i++] = arr[lIndex] < arr[rIndex] ? arr[lIndex++]:arr[rIndex++];    
    }
    //左边和右边肯定有一边到头了,不可能同时,因为每次只移动一边
    while(lIndex <= mid){
        help[i++] = arr[lIndex++];
    } 
    while(rIndex <= r){
        help[i++] = arr[rIndex++];
    }
    //将排好序的辅助数组赋值给原始数组,不需要返回值
    for(i = 0; i < r-l+1; i++){
        arr[l+i] = help[i];
    }
}

//递归
static void mergeSort(int arr[], int l, int r){
    if(l == r){
        return;
    }
    int mid = (l + r) / 2;
    //左半部分归并排序
    mergeSort(arr, l, mid);
    //右半部分归并排序
    mergeSort(arr, mid+1, r);
    //左右部分归并
    merge(arr, l, mid, r);
}

//归并排序整个数组
void mergeSort(int arr[], int n){
    //如果数组为空或只有一个元素,不需要排序
    if(arr == NULL || n < 2){
        return;
    }
    mergeSort(arr,0,n-1);
}


int main(){
    int n; 
    while(cin >> n){
        int arr[n];
        for(int i = 0; i < n; i++) cin >> arr[i];

        mergeSort(arr, n);

        for(int i = 0; i < n; i++){
            cout << arr[i] << " ";
        } 
        cout << endl;
    }
    return 0;
} 
堆排序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/*
堆排序
最差时间复杂度:O(nlogn)
最优时间复杂度:O(nlogn)
平均时间复杂度:O(nlogn)
稳定性:不稳定
堆排序,利用堆这种数据结构设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足性质:即子节点的键值或索引总是小于(或者大于)它的父节点。
通常堆是通过一维数组来实现的,在起始数组为0的情形中,对于节点i:
其左子节点的下标为 (2*i+1);
其右子节点的下标为 (2*i+2);
其父节点的下标为 floor((i-1)/2)。
在堆的数据结构中,堆中的最大值总是位于根节点。堆中定义一下三个操作:
1.最大堆调整(Max Heapify):在假定节点i的左右子节点为根的两棵二叉树都是最大堆的前提下,确保父节点大于子节点,否则下降原父节点,最终使以i为根的子树成为最大堆。
2.创建最大堆(Build Max Heap):将堆所有数据重新排序,对所有非叶子节点调用一次Max Heapify。
3.堆排序(Heap Sort):首先创建最大堆,然后依次将堆的根节点与末节点交换、剔除末节点、对根节点进行最大堆调整,直到堆中的节点数为1,排序结束。
*/
template <typename T> void MaxHeapify(T *array, int i, int heapSize)
{
    int l = 2*i+1;
    int r = 2*i+2;
    int tmp = i;
    if(l<=heapSize && array[l]>array[i]){
        tmp = l;
    }else{
        tmp = i;
    }

    if(r<=heapSize && array[r]>array[tmp]){
        tmp = r;
    }

    if(tmp != i){
        swap(array[i], array[tmp]);
        MaxHeapify(array, tmp, heapSize);
    }

}
template <typename T> void HeapSort(T *array, const int length)
{
    if(array == NULL){ 
        throw invalid_argument("Array must not be empty");
    }   
    if(length<=0) 
        return;
    for(auto i = length/2; i>=0; --i){ //构建最大堆
        MaxHeapify(array, i, length-1);
    }
    for(auto i = length-1; i>=0; --i){
        swap(array[0], array[i]);
        MaxHeapify(array, 0, i-1);
    }
}

sort函数的时间复杂度为 O(N log(N))

这篇将排序将的很好
https://www.imooc.com/article/9429

upload successful

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值