Java - 排序大全

本帖子包含的排序有:
1、库函数的qsort()排序
2、冒泡排序
3、直接插入排序
4、折半插入排序
5、2-路·插入排序
6、希尔排序
7、快速排序
8、选择排序
9、堆排序
10、归并排序
11、基数排序
12、基于链表的冒泡排序

下面将一一贴出排序的代码:
1、库函数的qsort()排序

/*
*	qsort库函数排序:
*		使用qsort函数进行排序,
*		需要注意的一点就是,qsort函数的两个参数
*		相减,>= 0 的时候,数组按升序排列,< 0
*		的时候,数组按降序排列
*/

int mysort(const void* elem1, const void* elem2)
{
	return *(int*)elem1 - *(int*)elem2;
}

2、冒泡排序

/*
*	冒泡排序:每一趟都将数组的第一个元素与第二个元素进行比较,
*			若为逆序,则交换两个元素的值,以此类推,每一趟
*			都把一个大的数放入到数组的后面,从而实现排序
*	时间复杂度:O(n^2)
*	稳定性:稳定
*/
void bubbleSort(int* array, int length)
{
	for (int i = 0; i < length; ++i)
	{
		for (int j = 0; j < length - i - 1; ++j)
		{
			if (array[j] > array[j + 1])
			{
				array[j]		^=		array[j + 1];
				array[j + 1]	^=		array[j];
				array[j]		^=		array[j + 1];
			}
		}
	}
}

3、直接插入排序

/*
*	直接插入排序:是一种简单的排序方法,基本操作是将一个记录
*				插入到已排序好的有序表中,从而得到一个新的、
*				记录数增1的有序表
*	时间复杂度:O(n^2)
*	稳定性:稳定
*/
void InsertSort(int* array, int length)
{
	int sentry = 0;
	for (int i = 1; i < length; ++i)
	{
		if (array[i] < array[i - 1])
		{
			sentry = array[i];						//设置岗哨
			array[i] = array[i - 1];
			int j = 0;
			for (j = i - 1; sentry < array[j]; --j)	//将比岗哨小的元素往后移
				array[j + 1] = array[j];
			array[j + 1] = sentry;					//插入到正确位置
		}
	}
}

4、折半插入排序

/*
*	折半插入排序:由于插入排序的基本操作是在一个有序表中进行查找和插入,这个“查找”操作可以利用“折半查找”
*				来实现,由此而来的折半插入排序
*	时间复杂度:O(n^2)
*	稳定性:稳定
*/
void BininsertSort(int* array, int length)
{
	int sentry = 0, low, high, mid;
	int j = 0;
	for (int i = 1; i < length; ++i)
	{
		sentry = array[i];				//将array[i]暂存在sentry
		low = 0;
		high = i - 1;
		while (low <= high)
		{
			mid = (low + high) / 2;
			if (sentry > array[mid])
				low = mid + 1;
			else
				high = mid - 1;
		}
		for (j = i - 1; j > high; --j)	//将数据往后移动
			array[j + 1] = array[j];
		array[j + 1] = sentry;			//插入到正确位置
	}
}

5、2-路·插入排序

/*
*	2-路插入排序:该排序是在折半插入排序的基础上改进的,目的是减少排序过程中移动记录的次数,
*				但为此需要 n 个记录的辅助空间
*	时间复杂度:O(n^2)
*	稳定性:稳定
*/
void InsertSort_2(int* array, int length)
{
	int first = 0, final = 0;							//分别表示在辅助空间的开始和最后的位置
	int* array_temp = new int[length] {0};				//创建辅助数组
	int k, i;
	array_temp[0] = array[0];
	for (i = 1; i < length; ++i)
	{
		if (array[i] < array_temp[first])				//小于最小元素
		{
			first = (first - 1 + length) % length;
			array_temp[first] = array[i];
		}
		else if (array[i] > array_temp[final])			//大于最大元素
		{
			final = (final + 1 + length) % length;
			array_temp[final] = array[i];
		}
		else											//折半查找
		{
			k = (final + 1 + length) % length;
			while (array_temp[((k - 1) + length) % length] > array[i])
			{
				array_temp[(k + length) % length] = array_temp[(k - 1 + length) % length];
				k = (k - 1 + length) % length;
			}
			array_temp[(k + length) % length] = array[i];
			final = (final + 1 + length) % length;
		}
	}
	for (k = 0; k < length; ++k)						//拷贝数组
		array[k] = array_temp[(first + k) % length];
	
	delete[] array_temp;								//释放辅助空间
}

6、希尔排序

/*
*	希尔(Shell)排序:又称“缩小增量排序”,基本思想是:先将整个待排记录序列分割成若干子序列,
*					分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录
*					进行一次直接插入排序
*	时间复杂度:O(nlog2n)
*	稳定性:不稳定
*/
void ShellSort(int* array, int length)
{
	int interval = 1;					//初始化一个间隔
	while (interval < length / 3)		//设置最大间隔
		interval = interval * 3 + 1;
	while (interval > 0)				//进行插入排序
	{
		long tmp = 0;
		for (int i = interval; i < length; ++i)
		{
			tmp = array[i];
			int j = i;
			while (j > interval - 1 && array[j - interval] >= tmp)
			{
				array[j] = array[j - interval];
				j -= interval;
			}
			array[j] = tmp;
		}
		interval = (interval - 1) / 3;	//缩小间隔
	}
}

7、快速排序

/*
*	快速排序(快排):是对冒泡排序的一种改进,它的基本思想是:通过一趟排序将待排序的记录
*				分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小
*				,则可以分别对这两部分记录继续进行排序,以达到整个序列有序
*	时间复杂度:O(nlog2n)--->当数组基本有序时,退化接近冒泡排序,时间复杂度为O(n^2)
*	稳定性:不稳定
*/
int Partition(int* arr, int low, int high)//首先需要一个函数返回轴驱的位置 这是每一排序的基础 
{
	/*交换数组当中的值 使轴驱记录到自己该指定的位置 并返回其所在的位置 此时 轴驱前(后)的数值均不
	大(小)于轴驱位置上的数值*/

	int pivotkey = arr[low];
	while (low < high)
	{
		while (low < high && arr[high] >= pivotkey)
			--high;
		arr[low] = arr[high];
		while (low < high && arr[low] <= pivotkey)
			++low;
		arr[high] = arr[low];
	}
	arr[low] = pivotkey;
	return low;
}
void QuickSort(int* arr, int low, int high)	//注意,high应为数组最大个数减一
{
	/*利用上面函数返回值进行数组排序 快速排序*/
	if (low < high)
	{
		int value = Partition(arr, low, high);
		QuickSort(arr, low, value - 1);
		QuickSort(arr, value + 1, high);
	}
}

8、选择排序

/*
*	选择排序:每次选择最小的数值,并且把最小数值赋给排序数组的前端,依次进行,直到数组有序
*	时间复杂度:O(n^2)
*	稳定性:不稳定
*/
void SelectSort(int* array, int length)
{
	int i, j, min = 0, temp = 0;
	for (i = 0; i < length - 1; ++i)
	{
		min = i;			//查找最小值
		for (j = i + 1; j < length; ++j)
		{
			if (array[min] > array[j])
				min = j;
		}
		if (min != i)
		{
			//交换数值
			array[min] ^= array[i];
			array[i] ^= array[min];
			array[min] ^= array[i];
		}
	}
}

9、堆排序

/*
*	堆排序:堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,堆是
*		具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;
*		或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆
*	时间复杂度:O(nlog2n)
*	稳定性:不稳定
*/
void max_heapify(int* arr, int start, int end) {
	//建立父节点指标和子节点指标
	int dad = start;
	int son = dad * 2 + 1;
	while (son <= end)
	{ //若子节点指标在范围内才做比较
		if (son + 1 <= end && arr[son] < arr[son + 1]) //先比较两个子节点大小,选择最大的
			son++;
		if (arr[dad] > arr[son]) //如果父节点大於子节点代表调整完毕,直接跳出函数
			return;
		else
		{ //否则交换父子内容再继续子节点和孙节点比较
			arr[dad] ^= arr[son];
			arr[son] ^= arr[dad];
			arr[dad] ^= arr[son];

			dad = son;
			son = dad * 2 + 1;
		}
	}
}
void heapsort(int* arr, int len) 
{
	//初始化,i从最後一个父节点开始调整
	for (int i = len / 2 - 1; i >= 0; i--)
		max_heapify(arr, i, len - 1);
	//先将第一个元素和已经排好的元素前一位做交换,再从新调整(刚调整的元素之前的元素),直到排序完毕
	for (int i = len - 1; i > 0; i--) 
	{
		arr[0] ^= arr[i];
		arr[i] ^= arr[0];
		arr[0] ^= arr[i];
		max_heapify(arr, 0, i - 1);
	}
}

10、归并排序

/*
*	归并排序:(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)
*			的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序
*	时间复杂度:O(nlog2n) 
*	稳定性:稳定
*/
void _merge_inArray(int* array, int left, int mid, int right)		//用来合并分开的数组
{
	int length = right - left + 1;	//定义一个辅助空间的长度
	int* ptemp = new int[length] {0};//分配一个辅助数组

	//合并操作
	int low = left;//左边区间起始下标
	int high = mid + 1;//右边区间起始下标
	int index = 0;//辅助数组的下标
	while (high <= right)	//右区间没有合并完
	{
		while (low <= mid && array[low] <= array[high])//证明左区间没有合并完,且左区间的值小于右区间的值
			ptemp[index++] = array[low++];	//把左边的值放进辅助数组 low++表示左边往高位移,
											//下一次需要判断左边的新下标,index++表示下一次放进辅助数组的新下标
		if (low > mid)//证明左区间已经放完
			break;

		while (high <= right && array[low] > array[high])
			ptemp[index++] = array[high++];
	}

	//到这一步证明有一个区间已经合并完成
	if (high <= right)//证明右边没有完成
		memmove(&ptemp[index], &array[high], sizeof(int) * (right - high + 1));

	if (low <= mid)//证明左边没有完成
		memmove(&ptemp[index], &array[low], sizeof(int) * (mid - low + 1));

	//把所有区间都合并到辅助区间
	memmove(&array[left], ptemp, sizeof(int) * length);

	delete[] ptemp;
}
void _merge(int* array, int left, int right)//将数组拆分成两个左右区间
{
	if (left >= right)			//递归终止操作,左右相等说明就只有一个元素,就不需要分了
		return;
	int mid = ((right - left) >> 1) + left;	//求中点
	_merge(array, left, mid);//拆分左
	_merge(array, mid + 1, right);//拆分右

	//并操作
	_merge_inArray(array, left, mid, right);
}
void MergeSort(int* array, int length)
{
	_merge(array, 0, length - 1);
}

11、基数排序

/*
*	基数排序:(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)
*			或bin sort,顾名思义,它是透过键值的部份资讯
*			,将要排序的元素分配至某些“桶”中,藉以达
*			到排序的作用
*	时间复杂度:O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。
*	稳定性:稳定
*/
int maxbit(int* data, int n) //辅助函数,求数据的最大位数
{
	int d = 1; //保存最大的位数
	int p = 10;
	for (int i = 0; i < n; ++i)
	{
		while (data[i] >= p)
		{
			p *= 10;
			++d;
		}
	}
	return d;
}
void radixsort(int* array, int length) //基数排序
{
	int d = maxbit(array, length);
	int* tmp = new int[length];
	int* count = new int[10]; //计数器
	int i, j, k;
	int radix = 1;
	for (i = 1; i <= d; i++) //进行d次排序
	{
		for (j = 0; j < 10; j++)
			count[j] = 0; //每次分配前清空计数器
		for (j = 0; j < length; j++)
		{
			k = (array[j] / radix) % 10; //统计每个桶中的记录数
			count[k]++;
		}
		for (j = 1; j < 10; j++)
			count[j] = count[j - 1] + count[j]; //将tmp中的位置依次分配给每个桶
		for (j = length - 1; j >= 0; j--) //将所有桶中记录依次收集到tmp中
		{
			k = (array[j] / radix) % 10;
			tmp[count[k] - 1] = array[j];
			count[k]--;
		}
		for (j = 0; j < length; j++) //将临时数组的内容复制到data中
			array[j] = tmp[j];
		radix = radix * 10;
	}
	delete[]tmp;
	delete[]count;
}

12、基于链表的冒泡排序

/*
*	使用冒泡排序思想对链表进行排序操作
*/

struct arr			//链表的节点数据
{
	int data;
	arr* next;
};

arr* moveto(const arr node, int n)	//将链表指针移动到指定位置,并返回
{
	arr* p = node.next;
	if (p)
	{
		for (int i = 0; i < n; ++i)
		{
			p = p->next;
		}
	}
	return p;
}

int count_list(arr node)		//获得链表长度
{
	int count = 0;
	arr* p = node.next;
	while (p)
	{
		count++;
		p = p->next;
	}
	return count;
}

void create_list(arr* node, int length)		//创建一个链表
{
	arr* p = node;
	arr* temp = NULL;
	for (int i = 0; i < length; ++i)
	{
		temp = new arr;
		temp->data = rand() % length;
		temp->next = NULL;

		p->next = temp;
		p = p->next;
	}

}

void show_list(const arr node) 		//显示链表数据
{
	arr* p = node.next;
	while (p)
	{
		std::cout << p->data << " ";
		p = p->next;
	}
	std::cout << std::endl;
}

void destroy_list(arr* node)	//销毁链表
{
	arr* p = node;
	arr* temp = nullptr;
	while (p->next)
	{
		temp = p->next;
		p->next = temp->next;
		free(temp);
	}
}

void list_sort(arr* node)			//链表排序
{
	int count = count_list(*node);
	arr* p = nullptr;
	for (int i = 0; i < count - 1; ++i)
	{
		for (int j = 0; j < count - 1 - i; ++j)
		{
			p = moveto(*node, j);
			if (p)
			{
				if (p->data > p->next->data)
				{
					p->data			^=	p->next->data;
					p->next->data	^=	p->data;
					p->data			^=	p->next->data;
				}
			}
		}
	}
}

使用的main函数

int main()
{
	int array[13] = { 56, 95, 45, 21, 48, 75, 23, 11, 99, 33, 22, 44, 88 };


	//qsort(array,10,sizeof(int),mysort);

	//InsertSort(array, 13);

	//BininsertSort(array, 13);

	//InsertSort_2(array, 13);

	//ShellSort(array, 13);

	//QuickSort(array, 0, 12);

	//SelectSort(array, 13);
	
	//MergeSort(array, 13);

	//heapsort(array, 13);

	//radixsort(array, 13);

	arr head;										//建立链表头节点
	create_list(&head, 13);							//创建链表
	list_sort(&head);								//排序链表
	show_list(head);								//显示链表

	for (int i = 0; i < 13; ++i)
		std::cout << array[i] << " ";
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值