数据结构与算法-- 排序

在这里插入图片描述
重点记忆:插入排序 堆排序 归并排序 快速排序
稳定排序:相同元素的前后顺序并没有改变
不稳定的排序算法有:快、希、选、堆。
https://baijiahao.baidu.com/s?id=1602011058247698952&wfr=spider&for=pc

插入排序:样本小且基本有序的时候效率比较高 优于冒泡和选择
希尔排序:插入排序升级 间隔大时移动的次数少 间隔小时移动的距离短 (不稳定 )

口诀:
选泡插,
快归堆希统计基,
恩方恩老恩一三,
对恩加k/恩乘K,
不稳稳稳不稳稳,
不稳不稳稳稳稳!

代码详细说明看注释

排序算法检验函数
下面的算法使用该函数验证

void Random(int* a, int n, int l, int r)//生成范围在l~r的随机数 
{
	srand(time(0));  //设置时间种子 取系统时间
	for (int i = 0; i < n; i++) {
		a[i] = rand() % (r - l + 1) + l;//生成区间r~l的随机数 
	}
}

void check()
{
	int n = 1000;
	int* arr1= new int[n];
    Random(arr1, n, 0, 1000);

	vector<int> check_num(arr1, arr1 + n);
	sort(check_num.begin(), check_num.end());
;
	quick_sort(arr1, 0, n - 1);//检验快排算法
	
	bool same = true;
	for (int i = 0; i < n; i++)
	{
		if (arr1[i] != check_num[i]) same = false;
	}


	same == true ? cout << "right" << endl : cout << "false" << endl;
	

}

1.快速排序
核心思想:
参考链接
https://developer.51cto.com/art/201403/430986.htm
/*1.先从数列中取出一个数作为基准数。
1.1 直接取第一个元素

2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
2.1 两个指针i,j分别指向头尾,相向而行。先移动j,直到j找到一个小于等于基准数的,i找到一个大于基准数的,交换他们。
2.2 继续2.2 直到i=j ,交换这个位置和首元素

3.再对左右区间重复第二步,直到各区间只有一个数
3.1 递归

//手写快排
int quick_sort_partition(int nums[],int left,int right)
{
	int axis = left;
	int i = left+1;
	int j = right;

	int n = right-left + 1;
	//printf_array(nums, n);
	while (i <=j)//比轴小得都放到轴得左边,比轴大的都放在右边
	{
		while (i<=j && nums[i] <= nums[axis]) i++;
		while (i<=j && nums[j] > nums[axis]) j--;

		if (i < j)
		{
			swap(nums[i], nums[j]);
		}
		//printf_array(nums, n);
		//cout << "----" << endl;
	}


	swap(nums[i-1], nums[left]);
	//printf_array(nums,n);
	return i - 1;
	 
}
void quick_sort(int nums[], int left, int right)
{
	if (left >= right) return;
	int mid = quick_sort_partition(nums, left, right);
	quick_sort(nums, left, mid - 1);
	quick_sort(nums, mid + 1, right);
}

int main()
{
	vector<int> nums{ 6,1,2,7,9,3,4,5,10,8,2 };
	
	int n = sizeof(nums2) / sizeof(nums2[0]);

	
quick_sort(nums2, 0, n-1);
	
	return 0;

}

2.归并排序
递归注意结束条件、递归公式
先递归,再合并
1.完成数组拆分,直到拆成单个元素
2.完成两个分别有序子序列合并得功能函数

int printf_array(int nums[],int n)
{

	for (int i = 0; i < n; i++)
	{
		cout << nums[i] << endl;
	}
	return 0;
}
//合并函数
//1.先解决子问题 两个有序数组如何合并成一个新的有序数组
//2.再修改边界条件 这里将left mid right_bound 均为数组下标 左闭右闭写法
//3.再写拆得过程 也就是递归得过程
void merge(int nums[], int left,int mid,int right_bound) 
{
	int i = left;
	int j = mid+1;
	int* temp = new int[right_bound-left+1];
	int k = 0;

	while (i <= mid && j <= right_bound)
	{
		temp[k++] = nums[i] >= nums[j] ? nums[j++] : nums[i++];
		
	}
	while (i <= mid)           temp[k++] = nums[i++];
	while (j <= right_bound)   temp[k++] = nums[j++];

	for (int i = 0; i < right_bound - left + 1; i++)
	{
		nums[left + i] = temp[i];
	}
	                                                                    
	//printf_array(temp, right_bound - left + 1);

}
//拆分
//这里要注意边界条件一定要统一,这里全部采用左闭右闭得区间
void merge_sort(int nums[], int left, int right)
{
	if (left < right)//边界条件 
	{
	int mid = (left + right) / 2;
	merge_sort(nums,left,mid);
	merge_sort(nums,mid+1,right);
	merge(nums, left, mid, right);
	}

	/*int num[] = { 1,3,4,2,5,6 };
	merge(num, 1,2,4);*/
	
}
int main()
{
	vector<int> nums{ 6,1,2,7,9,3,4,5,10,8,2 };
	int nums2[] = { 6,1,2,7,9,3,4,5,10,8,2 };
	int n = sizeof(nums2) / sizeof(nums2[0]);
	//selection_sort(nums);
	//insertion_sort(nums, nums.size());
	//shell_sort(nums, nums.size());
	//shell_sort2(nums, nums.size());
	//bubble_sort(nums, nums.size());

	merge_sort(nums2, 0,n-1);

	printf_array(nums2,n);
	//cout << nums.size() << endl;
	
	//system("pause");
	return 0;

}

3.插入排序

/插入排序
//***********************************
//一个指针遍历未排序的序列,待比较数字过来后,从后往前遍历,若比较数字小于该数字,则交换这两个数字,一直到大于或到数组头
//外层循环遍历未排序的序列并插入

int insertion_sort(vector<int>& nums, int n)
{
	for (int i = 0; i < n; i++)
	{
		
		for (int j = i ; j > 0 && nums[j-1]>nums[j]; j--)
		{
			swap(nums[j], nums[j - 1]);
		}
	}
	return 0;
}


//****************************************

int main()
{
	vector<int> nums{ 6,1,2,7,9,3,4,5,10,8,2 };

	insertion_sort(nums, nums.size());

	printf_array(nums);
	

	return 0;

}

4.希尔排序

//希尔排序
//插排的升级   数组后面比较小的元素会移动更少的次数到前面   
//将数组按照gap间隔分成若干组,对每组分别进行插入排序,然后缩小间隔再进行排序,直到间隔为1,最后进行一次插入排序
void shell_sort(vector<int> & nums,int n)
{
	for (int gap = nums.size(); gap > 0; gap /= 2)
	{
		for (int i = gap; i < n; i++)//是几组同步进行
		{
			for (int j = i; j >gap-1 && nums[j] < nums[j - gap]; j -= gap) //新元素与有序序列的元素比较
			{
				swap(nums[j], nums[j - gap]);
			}
		}
	}
			
}

int main()
{
	vector<int> nums{ 6,1,2,7,9,3,4,5,10,8,2 };
	//selection_sort(nums);
	//insertion_sort(nums, nums.size());
	shell_sort(nums, nums.size());
	//bubble_sort(nums, nums.size());
	printf_array(nums);
	

	return 0;

}

5.冒泡排序


//****************************************
//冒泡排序
/*
1.原理:比较两个相邻的元素,将值大的元素交换到右边

2.思路:依次比较相邻的两个数,将比较小的数放在前面,比较大的数放在后面。

(1)第一次比较:首先比较第一和第二个数,将小数放在前面,将大数放在后面。

(2)比较第2和第3个数,将小数 放在前面,大数放在后面。

......

(3)如此继续,知道比较到最后的两个数,将小数放在前面,大数放在后面,重复步骤,直至全部排序完成

(4)在上面一趟比较完成后,最后一个数一定是数组中最大的一个数,所以在比较第二趟的时候,最后一个数是不参加比较的。

(5)在第二趟比较完成后,倒数第二个数也一定是数组中倒数第二大数,所以在第三趟的比较中,最后两个数是不参与比较的。

(6)依次类推,每一趟比较次数减少依次

内层遍历完一趟后,最后一个数就是最大的了,所以下一次只需要遍历到n-i+1,外层循环相当于就是记个数

*/


//****************************************

void bubble_sort(vector<int> &nums,int n)
{
	bool swaped;//如果发现没有需要交换的 提前结束
	for (int i = 0; i <n ; i++)
	{
		swaped = false;
		for (int j = 1; j < n - i ; j++)
		{
			if (nums[j] < nums[j - 1])
			{
				swap(nums[j], nums[j - 1]);
				swaped = true;
			}
		}
	}
}



int main()
{
	vector<int> nums{ 6,1,2,7,9,3,4,5,10,8,2 };

	//insertion_sort(nums, nums.size());
	bubble_sort(nums, nums.size());
	printf_array(nums);
	

	return 0;

}

5.选择排序

//选择排序
//*****************************************
/*
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。

再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。

重复第二步,直到所有元素均排序完毕。
*/


//*****************************************
void selection_sort(vector<int>& nums)
{
	int n = nums.size();
	for (int i = 0; i < n; i++)
	{
		int j = i;
		int min= nums[j];
		int min_index = 0;
		int flag=false;
		for (; j < n; j++)
		{
			
			if (nums[j] < min)
			{
				min = nums[j];
				min_index = j;
				flag = true;
			}
		}
		if(flag)
		{ 
			swap(nums[min_index], nums[i]);
		}

	}
}



int main()
{
	vector<int> nums{ 6,1,2,7,9,3,4,5,10,8,2 };
	selection_sort(nums);
	//insertion_sort(nums, nums.size());
	//bubble_sort(nums, nums.size());
	printf_array(nums);
	

	return 0;

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值