【上机代码】交换排序——冒泡排序,快速排序

冒泡排序

思路

从后往前两两比较相邻元素的值,若为逆序(A[i-1]>A[i]),则交换两元素,直到序列比较完毕。每趟排序都将未排序列中最小元素放在已排序列的最终位置。
最多执行n-1次,若某一趟排序中没有进行任何交换,说明序列已经有序,则停止排序。
排序过程中,若两元素相同,则不交换,保证稳定性。

代码

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void print(int A[], int length)
{
	for (int i = 0; i < length; ++i)
	{
		printf("%d ", A[i]);
	}
}
void swap(int &a,int &b)
{
	int temp = a;
	a = b;
	b = temp;
}

//冒泡排序
void BubbleSort(int A[], int n) {
	for (int i = 0; i < n-1; ++i) {
		int flag = 1;
		for (int j = n - 1; j > i; --j) {
			if (A[j - 1] > A[j])
			{
				swap(A[j - 1], A[j]);
				flag = 0;
			}
		}
		if (flag == 1)
		{
			return;
		}
	}
}

void test()
{
	int A[10];
	int length = sizeof(A) / sizeof(A[0]);
	srand(time(0));
	for (int i = 0; i < length; ++i)
	{
		A[i] = rand() % 100;//取0-99的随机数  0-99,都为原值,100-199为0-99,以此类推

	}
	printf("原始序列为:\n");
	print(A, length);
	BubbleSort(A, length);
	printf("\n排序后为:\n");
	print(A, length);
}


int main()
{
	test();
}

链表实现

思路

数组是从后往前冒泡,而链表特别是单链表不方便从后向前查找,因此可以从前向后把较大的值冒到后面去。

链表排序最好还是要交换节点,而不只是交换值。

交换节点后p指针等于后移了一位
1,交换节点后
指针p与q(p的后一元素指针)交换了位置,实际相当于p已经后移一位,
2,不交换节点
当前元素小于下一元素,p需要手动后移,指向下一个元素(更大的)
3,pre位置不变
无论是否交换,pre指针位置不变,因此通过pre执行后移。

代码

#include<stdio.h>
#include "malloc.h"
#include<stdlib.h>
#include<time.h>
//定义链表结构体
typedef struct Linklist
{
	int data;
	struct Linklist* next;
}Linklist;

//交换链表中两个节点
void swap(Linklist* pre,Linklist* p, Linklist* q)
{
	pre->next = q;
	p->next = q->next;
	q->next = p;

};

//输出链表节点
void print(Linklist* L)
{
	Linklist* p = L;
	for (int i = 0; i < L->data; ++i)//L为头结点不能动 否则每次遍历就会改变条件
	{
		printf("%d ", p->next->data);
		p = p->next;
	}
	printf("\n");
}
void Bubblesort(Linklist* head)//简单选择排序(升序)
{
	for (int i = head->data - 1; i > 0; --i)
	{
		int flag = 1;
		Linklist* pre = head;
		Linklist* p = pre->next;
		for (int j = 0; j < i; ++j)//从第一个元素开始遍历到n-1个元素
		{
			if (p->data > p->next->data) {//将大的元素冒泡上去
				swap(pre, p, p->next);//元素交换后,p指针就相当于前移了一次(数组中只交换值,不改变下标)
				flag = 0;
			}
			pre = pre->next;//不管交换与否,pre位置不变,因此通过pre指针指行后移
			p = pre->next;
		}
		if (flag == 1)
			return;
	}
}

void test()
{
	//建立链表,头结点
	Linklist* L = (Linklist*)malloc(sizeof(Linklist));
	if (L == NULL) {
		printf("内存分配不成功!\n");
	}
	else
	{
		L->data = 10;
		Linklist* p = L;
		srand(time(0));
		for (int i = 0; i < L->data; ++i)
		{
			p->next = (Linklist*)malloc(sizeof(Linklist));
			if (p->next) {
				p = p->next;
				p->data = rand() % 100;//取0-99的随机数  0-99,都为原值,100-199为0-99,以此类推
			}
		}
		p->next = NULL;
		printf("原始序列为:\n");
		print(L);
		Bubblesort(L);
		printf("\n排序后为:\n");
		print(L);
	}
}

int main()
{
	test();
	return 0;
}

快速排序

思路

快速排序是基于分治法进行的。在待排序列L[1…n]中建立一个元素pivot作为枢轴(常为首元素)。通过一趟排序将序列分为独立的两个部分L[1…K-1]和L[K+1…n]。使L[1…K-1]中所有元素小于pivot,L[K+1…n]中所有元素大于等于pivot,pivot放在其最终位置L[K]上。然后递归地进行多次快速排序,直到所有子表只有一个元素或者为空,则所有元素都放在最终位置。

具体的一趟排序:
low和high指针分别指向首尾元素,pivot取首元素。
从high向左,找到第一个小于pivot的元素,将其替换到low处。
从low向右,找到第一个大于等于pivot的元素,将其替换到high处。
high和low交替向中间搜索元素,直到low==high,此处就是pivot的最终位置

若序列只有一个元素,显然已经有序,该元素就在最终位置处。
具体的递归机制可以看我的这篇帖子:【上机代码】函数调用栈,快速排序与归并排序.

代码

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void print(int A[], int length)
{
	for (int i = 0; i < length; ++i)
	{
		printf("%d ", A[i]);
	}
}
//partition实现从low和high向中间扫描序列,以low指向的元素为基准,将序列分为两个部分,基准在中间,左边所有元素小于基准,右边所有元素大于等于基准。
//返回基准值,和排序好的序列
int partition(int A[], int low, int high)
{
	int pivot = A[low];
	while (low < high) {
		while (low < high && A[high] >= pivot)
			--high;
		A[low] = A[high];
		while (low < high && A[low] <= pivot)
			++low;
		A[high] = A[low];
	}
	A[low]= pivot;
	return low;
}
//基于递归实现,先按基准排序,然后分别递归处理基准左右的子表,子表长度>1时就继续划分,直到所有子表被处理完毕。
void QuickSort(int A[], int low, int high) {
	if (low < high) {
		int pivotpos = partition(A, low, high);
		QuickSort(A, low, pivotpos - 1);
		QuickSort(A, pivotpos + 1, high);
	}
}

void test()
{
	int A[10];
	int length = sizeof(A) / sizeof(A[0]);
	for (int i = 0; i < length; ++i)
	{
		A[i]= rand() % 100;//取0-99的随机数  0-99,都为原值,100-199为0-99,以此类推

	}
	printf("原始序列为:\n");
	print(A, length);
	QuickSort(A, 0, length-1);
	printf("\n排序后为:\n");
	print(A, length);
}


int main()
{
	test();
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

燕南路GISer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值