八大排序

 

一.冒泡排序(交换排序)

  1. 思想:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。(从头扫描待排序序列,第一趟排序,对n个记录进行排列,在扫描过程中顺次比较相邻的两个元素。若按升序排列,则把较小的数往前移动。接着进行第二趟排列,对n-1个记录进行排列,如此反复,直到排好序为止。)
  2. 时间复杂度:最好情况O(n)  最坏情况O(n^2)   平均情况O(n^2)
  3. 空间复杂度:O(1)
  4. 稳定性:稳定
  5. 代码及优化:
//冒泡法代码
void Bubble(int *arr, int len)
{
	int tmp = 0;
	for (int i = 0; i < len - 1; i++)
	{
		for (int j = 0; j < len - 1; j++)
		{
			if (arr[j]>arr[j + 1])
			{
				tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
//冒泡法代码优化
void BubbleSort(int *arr, int len)
{
	bool swap = false;
	int tmp = 0;
	for (int i = 0; i < len-1; i++)
	{
		swap = false;
		for (int j = 0; j < len-i-1; j++)
		{
			if (arr[j]>arr[j+1])
			{
				tmp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = tmp;
				swap = true;
			}
		}
		if (!swap)
		{
			return;
		}
	}	
}

 

6.

  • 冒泡:若为升序,每一趟排序中,则有都选出无序中一个最大的放在最后。即每一趟在无序中冒出一个最大的数在其最后面,执行len-1趟

二.直接选择排序(选择排序)

  1. 思想:通过n-i次关键字间的比较,从n-1+1个记录中选出关键字最小的记录,并和第i(1<=i<=n)个记录交换之。(从头扫描待排序序列,第一趟排序,对n个记录进行排序,用第一个和后面所有的依次进行比较。以升序排列为例,把较小的值换到第一个。第二趟排序,从第二个开始,对n-1个记录进行排序。进行n-1趟。)
  2. 时间复杂度:O(n^2)
  3. 空间复杂度:O(1)
  4. 稳定性:不稳定
  5. 代码及优化
void Choice(int *arr, int len)
{
	for (int i = 0; i < len-1; i++)
	{
		for (int j = i+1; j < len; j++)
		{
			if (arr[i]>arr[j])
			{
				int tmp = arr[i];
				arr[i] = arr[j];
				arr[j] = tmp;
			}
		}
	}
}
  • 直接选择法:每一趟选出一个最小的数放在当前排序队列的第一位,进行n-1趟。

三. 直接插入排序(插入排序)

  1. 思想:将一个记录插入到已经排序的有序表中,从而得到一个新的,记录数增1的有序表。(以升序排列为例,若一个数字比他后面数字大,则则把大数后移,小数插入。以此类推,我们在移动的时候,比较一个数字,移动一个数字。)
  2. 时间复杂度:最好情况O(n)  最坏情况O(n^2)   平均情况O(n^2)
  3. 空间复杂度:O(1)
  4. 稳定性:稳定
  5. 代码及优化
代码
void Insert_Sort(int*arr, int len)
{
	int tmp = 0;
	int i, j;
	for (i = 1; i < len; i++)
	{
		tmp = arr[i];
		for (j = i - 1; j >= 0; j--)
		{
			if (tmp < arr[j])
			{
				arr[j + 1] = arr[i];
			}
			else break;
		}
		arr[j + 1] = tmp;
	}
}

优化见下个排序(希尔排序)

6.

四.希尔(shell)排序(直接插入排序的优化

  1. 思想:将待排序序列分为5组,然后让其各组分别排序(用直接插入排序)。由此得到的整个排序序列基本有序。再分为3组,让其各组排序。再分为1组,让其排序。最后就得到一个顺序的数组。
  2. 时间复杂度:最好情况O(n)  最坏情况O(n^2)   平均情况O(n^1.3)
  3. 空间复杂度:O(1)
  4. 稳定性:不稳定
  5. 代码及优化:
    代码
    void Shell(int *arr, int len,int gap)
    {
    	int tmp=0;
    	int i, j;
    	for (i = gap; i < len; i++)
    	{
    		tmp = arr[i];
    		for (j = i - gap; j >= 0; j=j-gap)
    		{
    			if (arr[j]>tmp)
    			{
    				arr[j + gap] = arr[j];
    			}
    			else break;
    		}
    		arr[j + gap] = tmp;
    	}
    }
     void ShellSort(int *arr, int len)
    {
    	int brr[] = { 5, 3, 1 };
    	int lenn = sizeof(brr) / sizeof(brr[0]);
    	for (int i = 0; i < lenn; i++)
    	{
    		Shell(arr, len, brr[i]);
    	}
    }

     

  • 首先分为5组,用直接插入排序先将各组进行排序。然后将整体分为3组,同样对各组进行排序。最后将整体进行排序。目的是为了减少排序的次数

五.堆排序(选择排序)

  1. 思想:将待排序序列构造成一个大根堆,此时,整个序列的最大值就是堆顶的根节点。将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次小值。如此反复执行,便能得到一个有序序列了。
  2. 时间复杂度:O(nlog2 n)
  3. 空间复杂度:O(1)
  4. 稳定性:不稳定
  5. 代码及优化
    void Adjust(int *arr, int start, int end)//调整树的根结点
    {
    	int tmp = arr[start];
    	for (int i = 2*start+1; i <= end; i = 2 * i + 1)
    	{
    		if (i < end&&arr[i] < arr[i + 1])
    		{
    			i++;
    		}
    		if (tmp < arr[i])
    		{
    			arr[start] = arr[i];
    			start = i;
    		}
    		if (tmp>arr[i])
    		{
    			break;
    		}
    	}
    	arr[start] = tmp;
    }
    void HeapSort(int *arr, int len)
    {
    	for (int i = (len - 1 - 1) / 2; i >= 0; i--)//第一次建立大根堆
    	{
    		Adjust(arr, i, len - 1);
    	}
    	//交换,并建立大根堆
    	int tmp = 0;
    	for (int i = 0; i < len - 1; i++)
    	{
    		tmp = arr[0];
    		arr[0] = arr[len - 1 - i];
    		arr[len - 1 - i] = tmp;
    		Adjust(arr, 0, len - 1-i-1);
    	}
    }

     

  6. 建立大根堆。-----首先将未排序序列建立大根堆,然后将根结点的数和未排列的最后一位数交换,并在未排序序列重新建立大根堆。依次循环。

六.归并排序

  1. 思想:先使每个子序列有序,再使子序列段间有序。
  2. 时间复杂度:O(nlog2 n)
  3. 空间复杂度:O(n)
  4. 稳定性:稳定
  5. 代码及优化:
//归并
void Merge(int *arr, int len, int gap)
{
	int *brr = (int*)malloc(sizeof(int));
	int start1 = 0;
	int end1 = start1 + gap - 1;
	int start2 = end1 + 1;
	int end2 = start2 + gap - 1;
	int i = 0;
	while (start2 < len)
	{
		while (start1 <= end1&&start2 <= end2)//两段都有数据
		{
			if (arr[start1] <= arr[start2])
			{
				brr[i++] = arr[start1++];
			}
			else
			{
				brr[i++] = arr[start2++];
			}
		}
		while (start1 <= end1)
		{
			brr[i++] = arr[start1++];
		}
		while (start2 <= end2)
		{
			brr[i++] = arr[start2++];
		}
		start1 = end2++;
		end1 = start1 + gap - 1;
		start2 = end1++;
		end2 = start2 + gap - 1;
	}
	while (start1 < len)
	{
		brr[i++] = arr[start1++];
	}
	for (i = 0; i < len; i++)
	{
		arr[i] = brr[i];
	}
	free(brr);
	brr = NULL;
}
void MergeSort(int *arr, int len)
{
	for (int i = 1; i < len; i*=2)
	{
		Merge(arr, len, i);
	}
}

七.基数排序

  1. 思想:按最低位的值进行记录进行初步排序,在此基础上按照次低位的值进行进一步排序。
  2. 时间复杂度:最好情况O(d(r+n))  最坏情况O(d(r+n))   平均情况O(d(r+n))
  3. 空间复杂度:O(rd+n)
  4. 稳定性:稳定
  5. 代码及优化:
    //删除第一个节点DelFirst()
    bool DelFirst(List plist,int *rtv)
    {
    	Node *pDel = plist->next;
    	if(pDel == NULL)
    	{
    		return false;
    	}
    	plist->next = pDel->next;
    	*rtv = pDel->data;
    	free(pDel);
    	pDel = NULL;
    	return true;
    }
    int GetMaxBit(int *arr,int len)
    {
    	//1、找出数组当中最大的数字
    	int max = arr[0];
    	for(int i = 1;i < len;i++)
    	{
    		if(arr[i] > max)
    		{
    			max = arr[i];
    		}
    	}
    	//2、求最大的数字的位数
    	int count = 0;
    	while(max != 0)
    	{
    		count++;
    		max/=10;
    	}
    	return count;
    }
    
    int GetNum(int num,int figure)
    {//123%10      123/10 = 12  12%10 = 2  
    	for(int i = 0;i < figure;i++)
    	{
    		num/=10;
    	}
    	return num%10;
    }
    
    void Base(int *arr,int len,int figure)
    {
    	Node head[10];
    	int i;
    	for(i = 0;i < 10;i++)
    	{
    		InitList(&head[i]);
    	}
    	int tmp;
    	//得到数组当中的每一个数字,得到当前数字的figure为
    	for(i = 0;i < len;i++)
    	{
    		//1、figure位
    		tmp = GetNum(arr[i],figure);//123   3
    		//2、入桶:figure桶
    		InsertTail(&head[tmp],arr[i]);
    	}
    	//出桶
    	i = 0;
    	for(int j = 0;j < 10;  )
    	{
    		if(DelFirst(&head[j],&arr[i]))
    		{
    			i++;
    		}
    		else
    		{
    			j++;
    		}
    	}
    }
    void BaseSort(int *arr,int len)
    {
    	//1、入桶的次数(数组当中最大的数字的位数)
    	int count = GetMaxBit(arr,len);
    	//2、得到入桶次数后进行如同
    	for(int i = 0;i < count;i++)//d代表的是:入桶的次数
    	{
    		Base(arr,len,i);//i:代表位数  0代表右数第一位  个位
    	}
    }
    
    
    
    

     

八.快速排序(交换排序)

  1. 思想:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。
  2. 时间复杂度:平均情况【O(nlog2 n)】最好情况【O(nlog2 n)】最坏情况【O(n^2)】
  3. 空间复杂度:O(log2 n)
  4. 稳定性:不稳定
  5. 代码及优化
    int Partion(int*arr, int low, int high)
    {
    	int tmp = arr[low];
    	while (low < high)
    	{
    		while (low < high&&arr[high] >= tmp)
    		{
    			high--;
    		}
    		if (low >= high)
    		{
    			break;
    		}
    		else
    		{
    			arr[low] = arr[high];
    		}
    		while (low < high&&arr[low] <= tmp)
    		{
    			low++;
    		}
    		if (low >= high)
    		{
    			break;
    		}
    		else
    		{
    			arr[high] = arr[low];
    		}
    	}
    	arr[low] = tmp;
    	return low;
    }
    
    void swap(int *arr, int low, int high)
    {
    	int tmp = arr[low];
    	arr[low] = arr[high];
    	arr[high] = tmp;
    }       
    //优化二   三分取基准
    void SelectPivotMedianOfThree(int *arr, int low, int mid, int high)//4  1  8
    {
    	if (arr[low] < arr[mid])
    	{
    		swap(arr, low, mid);
    	}
    	if (arr[high] < arr[mid])
    	{
    		swap(arr, low, mid);
    	}
    	if (arr[low] > arr[high])
    	{
    		swap(arr, low, high);
    	}
    }
      //优化4  相同元素聚集法
    void Focus_Same_Num(int *arr, int low, int par, int high, int *left, int *right) 
    {
    	if(low < high)
    	{
    		int ParLeftIndex = par-1;
    		int ParRightIndex = par+1;
    		for(int i = par-1;i >= low;i--)
    		{
    			if(arr[i] == arr[par] )//如果两个值相等,那么交换,如果不是紧挨着的
    			{
    				if(i != ParLeftIndex)
    				{
    				      Swap(arr,i,ParLeftIndex);//把相等的拉过来,聚集在一起
    				      ParLeftIndex--;
    				}
    				else
    				{
    			        	ParLeftIndex--;
    				}
    				
    			}
    		}
    		*left = ParLeftIndex;
    
    		for(int i = par+1;i <= high;i++)
    		{
    			if(arr[i] == arr[par])
    			{
    				if(i != ParRightIndex)
    				{
    					Swap(arr,i,ParRightIndex);
    					ParRightIndex++;
    				}
    				else
    				{
    					ParRightIndex++;
    				}
    			}
    		}
    		*right = ParRightIndex;
    	}
    }
    void Quick(int*arr, int start, int end)
    {
    	int par = Partion(arr, start, end);
    	int left = par - 1;
    	int right = par + 1;
    	if (par < end - 1)
    	{
    		Quick(arr, right, end);
    	}
    	if (par>start + 1)
    	{
    		Quick(arr, start, left);
    	}
    }
    void Quick_sort(int* arr, int len)
    {
    	Quick(arr, 0, len - 1);
    }
    

     

  6. (1)一趟快排,返回基准。序列基本有序(基准左边都比他小,右边都比他大)

(2)基准两边继续寻找进行排序,直到right==end且left==start。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值