排序算法总结

原创 2015年07月06日 17:07:48

一、直接插入排序

1、基本思想:对于数组a[1...n],初始时,a[1]为一个有序区间,a[2...n]为无序区间,然后依次将a[2],a[3].....a[n]插入到有序区间内。

2、代码

/*直接插入排序*/
void InsertSort(int arr[], int length)
{
	for (int i = 1; i < length; i++)
	{
		int temp = arr[i];
		int j;
		for (j = i - 1; j >=0 && temp<arr[j] ; j--)//从后往前进行比较
		{
			arr[j+1] = arr[j];
		}
		arr[j + 1] = temp;
	}
}
3、稳定、时间复杂度O(n^2)  空间复杂度o(1)

二、希尔(shell)排序

1、基本思想:改进的的插入排序,首先将待排序列按照某个增量d分成几个组,每个组中记录下标相差d对每个组中的元素进行排序,然后减小d重新排序,直至d为1,整个序列变成一个组,排序完成。

2、代码

/*希尔排序(d开始为序列的一半,每次减半)*/
void ShellSort(int arr[], int length)
{
	
	for (int d = length / 2; d > 0; d = d / 2)
	{
		for (int i = 1; i < length; i++)
		{
			int temp = arr[i];
			int j;
			for (j = i - d; j >= 0 && arr[j]>temp; j-=d)
			{
				arr[j + d] = arr[j];
			}
			arr[j + d] = temp;
		}
	}
}
3、 不稳定 时间复杂度O(nlog2n) 空间复杂度o(1)

三、冒泡排序

1、基本思想:对于待排序列a,从头到尾扫描,将较大的数交换至最后的位置,直到整个序列有序

2、代码:

void Swap(int &a, int &b)//“或”实现两个数的交换
{
	a = a^b;
	b = b^a;
	a = a^b;
}
/*直接插入排序*/
void BubberSort(int arr[], int length)
{
	for (int i = 0; i < length-1; i++)
	{
		int exchange = 0; //添加变量记录本次遍历有无交换,若无已经有序,跳出循环
		for (int j = i + 1; j < length; j++)
		{
			if (arr[i]>arr[j])
			{
				swap(arr[j], arr[i]);
				exchange = 1;
			}
		}
		if (exchange != 1)
			return;
	}
}
3、稳定 时间复杂度O(n^2) 空间复杂度o(1)

四、快速排序

1、基本思想:采用分治法,将原问题分解为若干与原问题结构相似的子问题,递归解决。首先,选取关键字pivot将待排序列分为两个部分,一部分元素全部大于pivot,另一部分全部小于pivot,pivot的位置得到确定。然后再递归的对小于和大于pivot的序列进行快排。

2、代码

/*快速排序*/
void QuickSort(int arr[],int first,int last)
{
	int low = first;
	int high = last;
	int pivot = arr[low];
	if (low < high)
	{
		while (low < high)
		{
			while (low < high && arr[high] >= pivot)//注意先从高位开始比较
			{
				high--;
			}
			if (low < high)
				arr[low++] = arr[high];
			
			while (low < high && arr[low] <= pivot)
			{
				low++;
			}
			if (low < high)
				arr[high--] = arr[low];		
		}
		arr[low] = pivot;
		QuickSort(arr, first, low - 1);
		QuickSort(arr, low + 1, last);
	}
}

3、不稳定 时间复杂度o(nlog2n)  由于采用了递归空间复杂度o(logn) 


五、选择排序

1、基本思想:在待排序列的无序区间的a[i+1.....n]中,选择一个最小的数跟a[i] 交换

2、代码:

/*选择排序*/
void SelectSort(int arr[], int length)
{
	for (int i = 0; i < length-1; i++)
	{
		int min = arr[i];
		int index = i;

		for (int j = i+1; j < length; j++)
		{
			if (arr[j] < min)
			{
				min = arr[j];
				index = j;
			}
		}
		arr[index] = arr[i];
        arr[i] = min;		
	}
}

3、不稳定 时间复杂度 O(n^2) 空间复杂度O(1)


六、堆排序

1、基本思想:堆排序有两种大根堆(所有子节点都小于其父节点,即Ai<=A2i且Ai<=A2i+1),小根堆(所有子节点都小于其父节点,即Ai>=A2i且Ai>=A2i+1)。

2、代码

以大根堆为例,首先将待排数列建成一个堆

void Built_Maxheap(int arr[], int length)//建立堆
{
	heapSize = length-1;
	for (int  i = (length >> 1-1); i >= 0 ; i--) //n/2-1之前都是父节点,之后的节点都是子节点,只需要对父节点进行maxHeapify
	{
		maxHeapify(arr, i);
	}
}

然后再将最大关键字堆顶元素与无序区的最后一个元素交换

void MaxHeapSort(int arr[], int length)//堆排序
{
	Built_Maxheap(arr, length);

	for (int i = length - 1; i >= 1; i--)
	{
		swap(arr[0], arr[i]);
		heapSize--;
		maxHeapify(arr, 0);
	}

}

交换过后可能会导致新的根违反大根堆的定义,所以要进行调整

void maxHeapify(int arr[], int index)//堆的调整
{
	int max = index;
	int left = Left(index);
	int right = Right(index);

	if (left <= heapSize && arr[left] > arr[index])
		max = left;

	if (right <= heapSize && arr[right] > arr[max])
		max = right;

	if (max != index)//如果堆顶不是最大者,则交换,并递归调整堆
	{
		Swap(arr[index], arr[max]);
		maxHeapify(arr, max);
	}
}

其中,根节点的左右子树计算方法如下

void Swap(int &a, int &b)//用“^”完成交换操作
{
	a = a^b;
	b = b^a;
	a = a^b;
}

int Left(int i){ return ((i << 1) + 1); } //leftchild=2*i+1;返回左子节点索引
int Right(int i){ return ((i << 1) + 2); }//rightchild=2*i+2返回右子节点索引
int heapSize = 0;

3、不稳定 时间复杂度建堆O(n),堆调整O(nlogn),所以为O(nlogn) 空间复杂度O(1)


七、归并排序

1、基本思想:假设有两个有序的子文件,放在A[low......m],A[m+1......n]上,先将他们合并到一个Temp中,待排序完毕后在复制到原数组中。

2、代码(自顶向下)

//将两个子序列按照大小顺序填入临时数组temp中
void Merge(int arr[], int temp[], int start1, int end1, int end2)
{
	int start2 = end1 + 1;
	int tempindex = start1;
	int number = end2 - start1 + 1;
	while (start1<=end1 && start2<=end2)
	{
		if (arr[start1] <= arr[start2])
		{
			temp[tempindex++] = arr[start1];
			start1++;
		}
		else{
			temp[tempindex++] = arr[start2];
			start2++;
		}
	}

	while (start1 <= end1)
	{
		temp[tempindex++] = arr[start1];
		start1++;
	}

	while (start2<=end2)
	{
		temp[tempindex++] = arr[start2];
		start2++;
	}

	for (int i = 0; i < number; i++, end2--)
		arr[end2] = temp[end2];
}


void merge_sort(int arr[], int temp[], int start, int end)
{
	if (start >= end)
		return;

	int middle = (start + end) / 2;//分裂节点
	merge_sort(arr, temp, start, middle);//分别递归排序
	merge_sort(arr, temp, middle + 1, end);
	Merge(arr, temp, start, middle, end);//合并
}

/*归并排序*/
void MergeSort(int arr[], int length)
{
	int *temp = NULL;
	temp = new int[length];
	if (temp != NULL)
	{
		merge_sort(arr, temp, 0, length - 1);
		delete[] temp;
	}
}

3、稳定,时间复杂度O(nlogn) 空间复杂度O(n)


八、基数排序

1、基本思想:从低位到高位依次对数据进行排序,第d趟排序就是对第d位进行排序,所需箱子数就是技术rd。

2、代码

int find_max(int arr[], int length)//找到最大的一个数
{
	int max = arr[0];
	for (int i = 1; i < length; ++i)
	{
		if (arr[i]>max)
			max = arr[i];
	}
	return max;
}

int digitnumber(int number)//求数字的位数
{
	int num = 0;
	while (number > 0)
	{
		number = number / 10;
		num++;
	}
	return num;
}

int kdigitnumber(int number,int k)//求第k位的元素,从个位数开始计数
{
	number = number / pow(10, k);
	return number % 10;
}

/*基数排序*/
void RadixSort(int arr[], int length)
{
	int *temp[10];//指针数组,指向10个桶
	int max = find_max(arr,length);
	int maxDigit = digitnumber(max);
	int count[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };//每个桶元素的个数

	for (int i = 0; i < 10; ++i)//给桶分配空间,并初始化
	{
		temp[i] = new int[length];
		memset(temp[i], 0, sizeof(int)*length);
	}

	for (int i = 0; i < maxDigit; i++)
	{
		memset(count, 0, sizeof(int)* 10);
		for (int j = 0; j < length; j++)
		{
			int x = kdigitnumber(arr[j], i);
			temp[x][count[x]] = arr[j];
			count[x]++;
		}

		int index = 0;//对桶中的元素进行收集操作
		for (int k = 0; k < 10; k++)
		{
			for (int m = 0; m < count[k]; m++)
			{
				arr[index++] = temp[k][m];
			}
		}
	}
}

3、不稳定 时间复杂度O(kn)   空间复杂度O(n)(其中k为数字的最大位数)


版权声明:本文为博主原创文章,未经博主允许不得转载。

几种常见排序算法总结(java版)

代码如下: /*************几种常见的排序算法总结***************************/ package paixu; public class PaiXu {...
  • zgrjkflmkyc
  • zgrjkflmkyc
  • 2013年09月13日 12:50
  • 13470

[数据结构]七种排序算法小结

冒泡排序 选择排序 插入排序 归并排序 快速排序 堆排序 希尔排序眼看着就要实习,为了巩固基础,回顾并总结排序算法。参考自:http://www.nowcoder.com/courses/1/1/1冒...
  • u010536377
  • u010536377
  • 2016年02月20日 12:21
  • 1512

C++常用排序算法总结

排序算法是一种基本并且常用的算法。由于实际工作中处理的数量巨大,所以排序算法对算法本身的速度要求很高。而一般我们所谓的算法的性能主要是指算法的复杂度,一般用O方法来表示。在后面我将给出详细的说明。  ...
  • fanyun_01
  • fanyun_01
  • 2016年05月31日 15:51
  • 2620

十种常见的排序算法总结(java版)

排序是程序开发中非常常见的操作,对一组任意的数据元素经过排序操作后,就可以把他们变成一组一定规则排序的有序序列。排序算法属于算法中的一种,而且是覆盖范围极小的一种,但彻底掌握排序算法对程序开发是有很大...
  • canot
  • canot
  • 2016年03月06日 23:03
  • 2727

排序算法总结与C代码

最近参加笔试,感觉排序算法需要好好的整理一下,感觉部分排序算法理解得不是很清楚;通过这段时间的整理与总结来对排序算法的一个复习吧。         主要参考了《大话数据结构》: 1. 冒泡排序的基本思...
  • yyme411
  • yyme411
  • 2013年10月09日 21:23
  • 7182

七大常见排序算法总结

插入类排序 直接插入排序 希尔排序 选择类排序 简单选择排序 堆排序 交换类排序 冒泡排序 快速排序 归并类排序 归并排序...
  • lutianfeiml
  • lutianfeiml
  • 2016年07月19日 19:56
  • 5105

Java数据结构与算法之常见排序算法总结

目录: 1.概述 2.常用排序方法总结 3.冒泡排序 4.选择排序 5.插入排序 6.归并排序 7.快速排序 8.shell排序 1.概述 学过排序算法的朋友可能都知道排序算法...
  • qq_28057577
  • qq_28057577
  • 2016年10月08日 15:54
  • 609

排序算法大汇总

排序算法大汇总        排序算法是最基本最常用的算法,也是各大上市公司经常会被问道的面试知识点之一,不同的排序算法在不同的场景或应用中会有不同的表现,我们需要对各种排序算法熟练才能将它应用到实...
  • u014536527
  • u014536527
  • 2016年03月30日 01:23
  • 1949

十大经典排序算法总结——Java实现

引 这段时间博主逐步替换为Java的实现 //博主留 2017.9.15 //2017.10.10完成冒泡排序的修改 //2017.10.11完成选择排序、插入排序和希尔排序的修改 //2017.1...
  • WangQYoho
  • WangQYoho
  • 2016年09月19日 12:12
  • 2239

【算法】-8大排序算法总结-Python

8大排序算法总结-Python
  • aliceyangxi1987
  • aliceyangxi1987
  • 2016年03月16日 14:52
  • 1122
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:排序算法总结
举报原因:
原因补充:

(最多只允许输入30个字)