CJW deeplearning , machine learning

各类排序算法比较

2015-10-23

1. 冒泡排序

冒泡排序,依序比较相邻的两个,顺序不对则交换
时间复杂度 O(n^2)

	void bsort(int a[], n){
		for(int i=0; i<n; i++){
			for(int j=0; j<n-i-1; j++){
				if(a[j]>a[j+1]){
					temp = a[j+1];
					a[j+1] = a[j];
					a[j] = temp;
				}
			}
		}
	}

2. 选择排序,selection sort

选择排序,从第一个元素开始往后遍历,每轮从后面选择最小的元素排到最前面。
时间复杂度 O(n^2),排序速度先慢后快,因为要查找的元素的元素逐个减少。大量查找,少量移动。

	void selectsort(int a[], n ){
		for(int i=0; i<n; i++){
			min = a[i];
			for(int j = i+1; j<n; j++){
				if(a[j]<min){
					int temp;
					temp = min;
					min = a[j];
					a[j] = temp;

				}
			}
			a[i] = min;
		}
	}

3. 插入排序 insertion sort

将序列分为已排序和未排序两个部分,对未排序部分依序遍历插入前面已排序部分。
先快后慢。后几轮插入时要比较的更多。

  1. 可以假设认为第一个元素是已排序的
  2. 依序对后面的n-1个元素遍历,
    for i in 1 - n:
    将第i个元素插入前面i-1个已排序元素中

     void insertionsort(int a[], int n ){
         for(int i=1; i<n; i++){
             int temp = a[i];
             for(int j=i-1;j>=0;j--){
                 if(a[j]>temp)                                                                                      
                     a[j+1] = a[j];
                 else{
                     a[j+1] = temp;
                     break;
                 }
             }
         }
     }
    

4. 归并排序

归并排序要调用递归的方法,步骤:

  1. 排序好左边,MergeSort(left),对左边序列递归调用这三个步骤
  2. 排序好右边,Mergesort(right),对右边序列递归调用这三个步骤
  3. 合并两个有序序列, Merge(v, left, right)

时间复杂度 O(nlogn),空间上需要额外的 n 个空间,不利于基本有序的序列。

	void merge(int a[], int low, int mid, int high, int temp[]){
		int i =low;
		int j = mid+1;

		int k =0;
		while(i <=mid && j<=high){
			if(a[i]<a[j]){
				temp[k++]=a[i];
				i++;
			}
			else{
				temp[k++]=a[j];
				j++;
			}
		}
		while(i<=mid){
			temp[k++] = a[i];
			i++;
		}
		while(j<=high)  {
			temp[k++] = a[j];
			j++;
		}
		for(int i=0; i<k; i++){
			a[i+low] = temp[i];
		}
	}
	void mergesort(int a[], int low, int high, int temp[] ){

		if(low<high){
			int mid = (high+low)/2;
			mergesort(a, low, mid,temp);
			mergesort(a, mid+1, high,temp);
			merge(a, low, mid, high,temp);
		}
	}

5. 快速排序

也是要用到递归

  1. 选择某个位置的元素 p
  2. 将大于该元素的放到 p 的右边, 小于 p 的放到左边。
  3. 递归调用这三步分别对p左边和p右边的元素进行排序

时间复杂度 O(nlogn),相对归并排序不需要额外的空间,p 的选择对排序影响比较大,序列基本有序时会相对快。

	int partition(int a[], int low, int high){
		int midvalue = a[low];
		int i = low; 
		int j = high;

		while(i<j){
			while(a[j]>midvalue && i<j)
				j--;
			if(i<j)
				a[i++] = a[j];
			while(a[i]<midvalue && i<j)
				i++;
			if(i<j)
				a[j--] = a[i];
		}
		a[i]=midvalue;
		return i;
	}
	void quicksort(int a[], int low, int high){
		if(low<high){
			int pivot = partition(a, low, high);
			quicksort(a, low, pivot-1);
			quicksort(a, pivot+1, high);
		}
	}

5. 堆排序

大根堆: 父节点比两个子节点都大,小根堆反之。

	//调整以第i个节点为父节点的树,使之成为大根堆
	int adjust_heap(vector<int> &v, int length, int i){
			int left = 2 * i;
			int right = 2 * i + 1;
			int largest = i;
			int temp;

			while(left < length || right < length){
					if (left < length && v[largest] < v[left]){
							largest = left;
					}
					if (right < length && v[largest] < v[right]){
							largest = right;
					}

					if (i != largest){
							temp = v[largest];
							v[largest] = v[i];
							v[i] = temp;
							i = largest;
							left = 2 * i;
							right = 2 * i + 1;
					}
					else{
							break;
					}
			}
	}
	//建立堆,使首节点最大。从最后一个非叶子节点开始,逐个向前,调整为大根堆
	int build_heap(vector<int> &v, int length){
			int i;
			int begin = length/2 - 1; //get the last parent node
			for (i = begin; i>=0; i--){
					adjust_heap(v,length,i);
			}
	}

	int heap_sort(vector<int> &v){
			int length = v.size();
			int temp;
			build_heap(v,length);
			for(int i=n-1;i>=0;i--)
			//交换v[0]和v[i]
					temp = v[i];
					v[i] = v[0];
					v[0] = temp;
					i--;
			//调正前 i-1 个元素是大根堆来获取前i-1的最大值
					adjust_heap(v,i,0);
			}
	}

6. 希尔排序

其实就是分段的插入排序


Comments