排序算法

在这里插入图片描述
需要手写的:冒泡排序 快速排序
理解内容的:堆排序 归并排序
在这里插入图片描述
一.普通排序

//简单排序
void ChooseSort(int k[], int n)
{
	int i, j, temp;
	for(i = 0; i < n - 1; i++)
	{
		for(j = i + 1; j < n; j++)
		{
			if(k[i] > k[j])
			{
				temp = k[i];
				k[i] = k[j];
				k[j] = temp;
			}
		}
	}
} 

二.冒泡排序
在这里插入图片描述
C
若出现只比较没有移动,则表明后面的数字已经排好的顺序,即可以退出循环,因而可以改进冒泡排序,加一个标志变量flag去判断是否有移位

//冒泡排序(改进后加一个flag) 
void BubbleSort(int k[], int n)
{
	int i, j, temp, flag = 1;
	for(i = 0; i < n - 1 && flag; i++)
	{
		for(j = n - 1; j > i; j--)
		{
			flag = 0;
			if(k[j - 1] > k[j])
			{
				temp = k[j];
				k[j] = k[j - 1];
				k[j - 1] = temp;
				flag = 1;
			}
		}
	}
} 

Java

//冒泡排序
        for(int i = 0 ; i < arr.length - 1; i++){
            for(int j = 0; j < arr.length - 1 - i; j++){
                if(arr[j] > arr[j + 1]){
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }

三.选择排序
在这里插入图片描述
先比较,找出min,再交换

//选择排序
void SelectSort(int k[], int n)
{
	int i, j, temp, min;
	for(i = 0; i < n; i++)
	{
		min = i;
		for(j = i + 1; j < n; j++)
		{
			if(k[j] < k[min])
			{
				min = j;
			}
		}
		if(min != i)
		{
			temp = k[i];
			k[i] = k[min];
			k[min] = temp;
		}
	}
}

四.插入排序
基本方法:每步将一个待排序的元素,按其排序码大小插入到前面已经排好序的一组元素的适当位置上去,直到元素全部插入为止。

分类
可以选择不同的方法在已经排好序的有序数据表中寻找插入位置,依据查找方法的不同,分为常用的三种
①直接插入排序
②折半插入排序
希尔排序

1.直接插入排序
(在基本有序或者小规模数据的情况下效率很高)
待排序序列的第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
在这里插入图片描述

//直接插入排序
void InsertSort(int k[], int n)
{
	int i, j, temp;
	for(i = 1; i < n; i++)
	{
		if(k[i] < k[i - 1])
		{
			temp = k[i];
			for(j = i - 1; k[j] > temp; j--)
			{
				k[j + 1] = k[j]; //往后移 
			}
			k[j + 1] = temp;
		}
	}
} 

2.折半插入排序
比较和移动操作分离开来,即先折半查找出元素的待插入位置,然后再同意地移动待插入位置之后的所有元素。

//折半插入排序
void BinaryInsertSort(int k[], int n)
{
	int i, j, temp, low, high, mid;
	for(i = 1; i < n; i++)
	{
		temp = k[i];
		low = 0;
		high = i - 1;
		while(low <= high)
		{
			mid = (low + high) / 2;
			if(k[mid] > temp)
			{
				high = mid - 1;
			}
			else
			{
				low = mid + 1;
			}
		}
		for(j = i - 1; j >= high + 1; j--)
		{
			k[j + 1] = k[j];
		}
		k[j + 1] = temp;
	}
	
} 

3.希尔排序
思想是使用一个不断缩小的增量gap将数组元素分组,在每个分组内部先进行插入排序,当gap减少到1时整个数组元素分在一组,最后进行一次插入排序,整个排序过程结束。(但是算法不稳定

do……while控制gap每次的缩小,其内部便是直接插入排序算法的使用,与直接插入排序算法稍有不同的一点是:每次的变化量是gap而不是1。
gap = gap / 3 + 1;

//希尔排序 
void ShellSort(int k[], int n)
{
	int i, j, temp;
	int gap = n;
	do{
		gap = gap / 3 + 1;
		for(i = gap; i < n; i++)
		{
			if(k[i] < k[i - gap])
			{
				temp = k[i];
				for(j = i - gap; k[j] > temp; j -= gap)
				{
					k[j + gap] = k[j];
				}
				k[j + gap] = temp;
			}
		}
	}while(gap > 1);	
} 

五 .堆排序
从小到大构造大顶堆,从大到小构造小顶堆
在这里插入图片描述
将待排序的序列构造成一个大顶堆。此时,整个序列的最大值就是堆顶的根节点。将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次最大值。如此反复执行,就能得到一个有序序列了。这个过程其实就是先构建一个最大/最小二叉堆,然后不停的取出最大/最小元素插入到新的队列中,以此达到排序的目的。

例如

int main()
    {
    	int i;
    	int a[10] = {-1, 5, 2, 6, 0, 3, 9, 1, 7, 4}; //从1开始 
    	HeapSort(a, 9);
    	printf("排序后的结果是:");
		for(i = 1; i < 10; i++)
		{
			printf("%2d", a[i]);
		} 
		return 0;
	}

在这里插入图片描述

void HeapSort(int k[], int n)
{
	int i;
	for(i = n / 2; i > 0; i--) //从左到右 从下到上 
	{
		HeapAdjust(k, i, n);
	}
	for(i = n; i > 1; i--)
	{
		swap(k, 1, i); //将第一个元素和最后一个互换 
		HeapAdjust(k, 1, i - 1); //重新调整堆的序列(相当于最大的那个数固定在后面) 
	}
}

2.交换函数

void swap(int k[], int i, int j)
{
	int temp;
	temp = k[i];
	k[i] = k[j];
	k[j] = temp;
} 

3.构造堆
这个循环要确保每个结点都符合大顶堆的特点

void HeapAdjust(int k[], int s, int n)
{
	int i, temp;
	temp = k[s]; //当前需要调整的双亲结点 
	for(i = 2 * s; i <= n; i *= 2) // 2 * i是双亲的左孩子, 2 * i + 1是双亲的右孩子 
	{
		if(k[i] < k[i + 1] && i < n) //i = n就没有i + 1 
		{
			i++; //i指向最大元素孩子的下标 
		}
		if(temp >= k[i])
		{
			break;
		}
		k[s] = k[i]; //大元素放在双亲的位置 
		s = i;
	}
	k[s] = temp;
}

六.归并排序
在这里插入图片描述
在这里插入图片描述
1.递归思想
总的拆成两部分,再拆成两部分,直到不能拆为止

void MergeSort(int k[], int n)
{
	if(n > 1)
	{
		int *list1 = k;
		int list1_size = n / 2;
		int *list2 = k + n / 2;
		int list2_size = n - n / 2;
		
		MergeSort(list1, list1_size);
		MergeSort(list2, list2_size);
		Merging(list1, list1_size, list2, list2_size);
	}
}

归并:把两个部分放在一个临时变量里,最后再覆盖

//实现归并,并把最后的结果存放到list1里 
void Merging(int *list1, int list1_size, int *list2, int list2_size)
{
	int temp[Maxsize];
	int i = 0, j = 0, k = 0, m;
	while(i < list1_size && j < list2_size)
	{
		if(list1[i] < list2[j])
		{
			temp[k++] = list1[i++];
		}
		else
		{
			temp[k++] = list2[j++];
		}
	}
	while(i < list1_size)
	{
		temp[k++] = list1[i++];
	}
	while(j < list2_size)
	{
		temp[k++] = list2[j++];
	}
	for(m = 0; m < list1_size + list2_size; m++)
	{
		list1[m] = temp[m]; 
	}
}

2.迭代思想
递归调用自己,效率不高

// 归并排序(迭代)
void MergeSort(int k[], int n)
{
	int i, left_min, left_max, right_min, right_max, next = 0;
	int *temp = (int *)malloc(n * sizeof(int));
	
	for(i = 1; i < n; i *= 2)
	{
		for(left_min = 0; left_min < n - i; left_min = right_max)
		{
			right_min = left_max = left_min + i;
			right_max = left_max + i;
			
			if(right_max > n)
			{
				right_max = n;
			} 
			while(left_min < left_max && right_min < right_max)
			{
				if(k[left_min] < k[right_min])
				{
					temp[next++] = k[left_min++];
				}
				else
				{
					temp[next++] = k[right_min++];
				}
			}
			while(left_min < left_max)
			{
				k[--right_min] = k[--left_max];
			}
			while(next > 0)
			{
				k[--right_min] = temp[--next];
			}
		}
	} 
}

七.快速排序
基本内容是选择一个数作为准基数,然后利用这个准基数将遗传数据分为两个部分,第一部分比这个准基数小,都放在准基数的左边,第二部分都比这个准基数大,放在准基数的右边.
(用递归的思想)
在这里插入图片描述

快速排序的优化
1.优化选取基准点
确保基准点是处于数据中的中间位置
先找出三个关键字(可以前中后选择一个,进行比较)选择中间的数作为基准点
在这里插入图片描述
2.优化不必要的交换
交换直接改换成赋值即可

//优化后的快速排序
void swap(int k[], int low, int high)
{
	int temp;
	temp = k[low];
	k[low] = k[high];
	k[high] = temp;
}
int Partition(int k[], int low, int high)
{
	int point;
	int mid = low + (high - low) / 2;
	//整个交换就是在确保low是中间值 
	if(k[low] > k[high])
	{
		swap(k, low, high);
	}
	if(k[mid] > k[high])
	{
		swap(k, mid, high);
	} 
	if(k[mid] > k[low])
	{
		swap(k, mid, low);
	}  
	
	point = k[low];  
	while(low < high)
	{
		while(low < high && k[high] >= point)
		{
			high--; //大的部分依然在右边 
		}
		k[low] = k[high];
		while(low < high && k[low] <= point)
		{
			low++; //小的部分依然在左边 
		}
		k[high] = k[low];
	}
	k[low] = point; //最后依然要还原 
	return low; //返回相遇的下标 
}

3.优化小数组的排序方案
就快速排序对于大数据而言,效率很高。但如果是一些小数据就完全没有必要,对于小数组,直接插入排序效率很高。一般分界点是high - low > 7为大数据,则在代码区加上一个判断即可。

4.优化递归操作
在这里插入图片描述

void QSort(int k[], int low, int high) 
{
	int point;
	if(low < high)
	{
		while(low < high)
		{
			point = Partition(k, low, high);
			if(point - low < high - point)
			{
				QSort(k, low, point - 1);
				low = point + 1;
			} 
			else
			{
				QSort(k, point + 1, high);
				high = point - 1;
			}
		}
	}
}

八.总结
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值