常见的排序算法详解

01 冒泡排序

//冒泡排序1:直接排序法
void bubble_sort(ElementType arr[], int N) {
	int i, j;
	for (i = 0;i < N - 1;i++) {	//用i来代表这是第几趟
		bool flag = false;
		for (j = 0;j < N - 1 - i;j++) {	//用N-i-j来代表这一趟要比较的最后一个元素的位置
			if (arr[j] > arr[j + 1]) {	//比较的是相邻元素
				flag = true;
				swap(arr[j], arr[j + 1]);
			}
		}
		if (!flag)break;	//数组已经有序了,不需要进行交换操作了
	}
}

①直接排序法:

        设置一个flag=false,如果在for(j=...)里面一次交换顺序的操作也没有执行就表明后面的数据已经是有序的了,就不用再进行排序了,可以直接通过break来退出循环。

 for (int i = 0;i < N - 1;i++) 
        for (int j = 0;j < N - 1-i;j++) 

使用i来代表需要排序多少趟,使用j来指示当前的位置,使用N-1-i来代表需要比较多少次,这种算法是先把最后面的元素排好序,然后再排前面的元素。

//冒泡排序2:间接排序法
void bubble_sorted_02(ElementType arr[], int N) {
    int i,j,k;
    for (i = 0;i < N - 1;i++) {  //确定从前往后第i个位置应该放谁
        k = i;
        for (j = i+1;j < N;j++) {  //从下一个元素一直到结尾,找一个当前最小的元素
            if (arr[k] > arr[j]) {
                k = j;
            }
        }
        if (k != i) swap(arr[i], arr[k]);    //判断是否需要交换位置
    }
}

②间接排序法:

 for (i = 0;i < N - 1;i++) 
        for (j = i+1;j < N;j++)

这种算法是从前往后把顺序排好,使用i来代表当前需要排序的位置(寻找应当存放在第i个位置的元素),j代表的是第i个位置后面的元素,从第i个位置后面一个元素开始,一直到最后一个元素,寻找到当前最小的元素放置在第i个位置上。

间接排序的好处是如果第i个元素本身就是第i个位置的最小元素就不需要进行交换操作了。

间接排序可以上来就定义好i,j,k以便后面进行使用。

02 插入排序

//插入排序
void insertion_sort(ElementType arr[], int N) {
    int i, j;
    for (i = 1;i < N;i++) {
        ElementType tmp = arr[i];
        for (j = i;j >=1 && tmp < arr[j - 1];j--)
            arr[j] = arr[j - 1];
        arr[j] = tmp;
    }
}

插入排序:

先把最后一个位置的元素保存起来,然后将这个tmp值依次和前面的元素进行比较,如果还是当前位置前面的元素较大的话,就使用前面的元素来覆盖当前位置的元素,本例中使用i来代表最后一个元素的位置,使用j来代表当前的位置,如果tmp已经比当前位置的前一个元素还要大了,就可以直接使用tmp来覆盖当前第j个位置的值,在这里你不用担心第j个位置的值会丢失,因为在此之前第j个位置的值已经备份好了一份放在了第j+1位置处。

03 原始希尔排序

//原始希尔排序
void shell_sort(ElementType A[], int N) {
    int D, p, k;  //D为步长,p用来表示每一组的最后一个元素的位置,k用来表示当前比较元素的位置,k-D表示前一个元素的位置
    for (int D = N / 2;D >=1;D /= 2) {    //增量从2/N开始递减至1
        for (int p = D;p < N;p++) {     //从第一个增量的位置开始,每++一次相当于换另外一组
            ElementType tmp = A[p];
            //对每一组进行插入排序
            for (;k >= D && tmp < A[k - D];k -= D) // k要大于边界值,而k>=D 在前,因为也许 A[k-D]已经越界 
                A[k] = A[k - D];
            A[k] = tmp;
        }
    }
}

两种改进后的希尔排序:

01 Hibbard增量序列哈希排序

// Hibbard增量序列希尔排序 (希伯德)
void Hibbard_shell_sort(ElementType A[], int N) {
	int add[] = { 32767,16383,8191,4095,2047,1023,511,255,127,63,31,15,7,3,1,0 };
	int i = 0;
	for (int D = add[i];D > 0;D = add[++i]) {
		for (int p = D;p < N;p++) {
			long tmp = A[p];
			int k = p;
			for (;k >= D && tmp < A[k - D];k -= D) // j>=D 在前,因为也许 A[j-D]已经越界 
				A[k] = A[k - D];
			A[k] = tmp;
		}
	}
}

02 Sedgewick增量序列哈希排序

// Sedgewick增量序列哈希排序 (塞奇威克)
void Sedgewick_shell_sort(ElementType arr[], int N) {
	int add[] = { 2161,929,505,209,109,41,19,5,1,0 };
	int i, j, k;
	int p = 0;
	ElementType tmp;
	for (i = add[p];i >= 1;i = add[++p]) {	//使用i来代表增量/步长
		for (j = i;j < N;j++) {		//使用j来代表每一组的最后一个元素的位置
			tmp = arr[j];	//先把最后一个位置的元素存一个备份,方便让前面的元素进行覆盖
			for (k = j;k >= i && arr[k - i] > tmp;k -= i)	//一定要注意tmp是和arr[k-i]进行比较,以此来决定tmp是不是可以放在第k个位置
				arr[k] = arr[k - i];	//从前往后赋值
			arr[k] = tmp;
		}
	}
}

04 快速排序 

//选取中位数作为主元
ElementType getPivot(ElementType arr[], int left, int right) {
	int center = (left+right) / 2;
	if (arr[left] > arr[center])
		swap(arr[left], arr[center]);
	if (arr[left] > arr[right])
		swap(arr[left], arr[right]);
	if (arr[right] < arr[center])
		swap(arr[right], arr[center]);
	swap(arr[center], arr[right - 1]);
	return arr[right - 1];//主元存放在right-1这个位置
}

void quickSort(ElementType arr[], int left, int right) {
	int cutoff = 6;//设置阈值
	if (right - left > cutoff) {
		int pivot = getPivot(arr, left, right);
		int i = left;
		int j = right-1;
		for (;;) {
			while (arr[++i] < pivot) {};
			while (arr[--j] > pivot) {};
			if (i >= j)break;
			else swap(arr[i], arr[j]);
		}
		//将主元放在合适的位置
		swap(arr[i], arr[right - 1]);
		quickSort(arr, left, i - 1);//向左递归
		quickSort(arr, i + 1, right);//向右递归
	}
	else
		shell_sort(arr + left, right - left + 1);	//否则使用希尔排序
}

void quick_sort(ElementType arr[], int N) {
	quickSort(arr, 0, N - 1);
}

05 堆排序

// 调整成最大堆 
void PrecDown(int arr[], int i, int N) {
	int parent, child;
	long tmp = arr[i];
	// 从 0 开始存,所以关系有变化 
	for (parent = i;parent * 2 + 1 < N;parent = child) {
		child = parent * 2 + 1;
		if ((child != N - 1) && (arr[child] < arr[child + 1]))
			child++;
		if (arr[child] <= tmp)
			break;
		else
			arr[parent] = arr[child];
	}
	arr[parent] = tmp;
}


// 堆排序 
void heap_sort(int arr[], int N) {
	// 先调整成最大堆 
	for (int i = N / 2;i >= 0;i--)
		PrecDown(arr, i, N);
	for (int i = N - 1;i > 0;i--) {
		swap(arr[0], arr[i]); // 每次把当前最大堆根元素选择出来 
		PrecDown(arr, 0, i);  // 再次调整最大堆 
	}
}

补充:利用STL实现最大堆

priority_queue<int, vector<int>, less<int> > q; // 定义一个最大堆 

void STL_Heap_sort(int A[], int N) {
	// 数据读入最大堆 
	for (int i = 0;i < N;i++)
		q.push(A[i]);
	// 依次出队 
	for (int i = N - 1;i >= 0;i--) {
		A[i] = q.top();
		q.pop();
	}
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值