常用的各种排序算法

//常用的排序算法
#include <iostream>
using namespace std;

typedef int ElemType;

/*
1、插入排序
(1)直接插入排序算法
算法思想:将等排序列划分为有序与无序两部分,然后再依次将无序部分插入到已经有序的部分,最后

就可以形成有序序列。
操作步骤如下:
1)查找出元素L(i)在表中的插入位置K;
2)将表中的第K个元素之前的元素依次后移一个位置;
3)将L(i)复制到L(K)。

时间复杂度为:O(n^2)
*/
void InsertSort(ElemType arr[], int length)
{
	int i, j;
	ElemType guard; // 哨兵

	for (i = 1; i < length; ++i)
	{
		if (arr[i] < arr[i-1]) // 在无序部分寻找一个元素,使之插入到有序部分后仍然有序
		{
			guard = arr[i];// 复制到“哨兵”

            // 将第i个元素之前的元素依次后移一个位置
			for (j = i - 1; arr[j] > guard; j--)
			{
				arr[j + 1] = arr[j];
			}

			arr[j + 1] = guard; // 复制到插入位置
		}
	}
}

/*
  2、折半插入排序
  使用于排序表为顺序存储的线性表
  在查找插入位置时,采用折半查找
  算法思想是:
  1)设置折半查找范围;
  2)折半查找
  3)移动元素
  4)插入元素
  5)继续操作1)、2)、3)、4)步,直到表成有序。
*/
void BinaryInsertSort(ElemType arr[], int length)
{
	int i, j, low, high, mid;
    ElemType tmp;

	for ( i = 1; i < length; ++i )
	{
		tmp = arr[i]; // 复制到哨兵

		// 设置折半查找范围
		low = 0;
		high = i;

        while (low <= high) // 折半查找
        {
			mid = (low + high) / 2;

			if (arr[mid] > tmp) // 在左半部分查找
			{
				high = mid - 1;
			}
			else
			{
				low = mid + 1; // 在右半部分查找
			}
        }

		// 移动元素
		for ( j = i - 1; j >= high + 1; --j )
		{
			arr[j + 1] = arr[j];
		}

		arr[j + 1] = tmp;
	}
}

/*
3、希尔(Shell)排序
   基本思想:
   先将待排序的表分割成若干个形若L[i, i+d, i+2d, ..., i+kd]的“特殊”子表,分别进行直接插入排序,
   当整个表已呈“基本有序”时,再对全体记录进行一次直接插入排序。
   算法过程:
   1)先取一个小于n的步长d1,把表中全部记录分成d1个组,所有距离为d1的倍数的记录放在同一组中,在各
      组中进行直接插入排序;
   2)然后取第二个步长d2 < d1, 重复步骤1
   3)直到dk = 1,再进行最后一次直接插入排序
*/

void ShellSort(ElemType arr[], int length)
{
	int i, j, dk = length / 2;
	ElemType tmp;

	while (dk >= 1)// 控制步长
	{
		for (i = dk; i < length; ++i)
		{
            if (arr[i] < arr[i - dk])
            {
                tmp = arr[i]; // 暂存

				// 后移
				for (j = i - dk; j >= 0 && tmp < arr[j]; j -= dk)
				{
					arr[j + dk] = arr[j];
				}

				arr[j + dk] = tmp;
            }
		}

		dk /= 2;
	}
}

/*
4、冒泡排序算法
   基本思想:
   假设待排序的表长为n, 从后向前或从前向后两两比较相邻元素的值,若为逆序,则交换之,直到序列比较完。
   这样一回就称为一趟冒泡。这样值较大的元素往下“沉”,而值较小的元素入上“浮”。
   时间复杂度为O(n^2)
*/
void BubbleSort(ElemType arr[], int length)
{
	int i, j;
	ElemType tmp;

	for (i = 0; i < length - 1; ++i)// 趟次
	{
		for (j = i + 1; j < length; ++j)
		{
			if (arr[i] > arr[j])
			{
				tmp = arr[i];
				arr[i] = arr[j];
				arr[j] = tmp;
			}
		}
	}
}

/*
5、快速排序算法
   基本思想:基于分治法,在待排序的n个元素中任取一个元素pivot作为基准,通过一趟排序将待排序表划分为独立的
   两部分L[1..k-1]和L[k+1 .. n],使得第一部分中的所有元素值都小于pivot,而第二部分中的所有元素值都大于pivot,
   则基准元素放在了其最终位置L(K)上,这个过程为一趟快速排序。而后分别递归地对两个子表重复上述过程,直到每
   部分内只有一个元素或为空为止,即所有元素都放在了其最终位置上。
*/

int Partition(ElemType arr[], int left, int right)
{
	ElemType pivot = arr[left]; // 以当前表中第一个元素为枢轴值

	while (left < right)
	{
		// 从右向左找一个比枢轴值小的元素的位置
		while (left < right && arr[right] >= pivot)
		{
			--right;
		}

		arr[left] = arr[right]; // 将比枢轴值小的元素移动到左端

		// 从左向右查找比枢轴值大的元素的位置
		while (left < right && arr[left] <= pivot)
		{
			++left;
		}

		arr[right] = arr[left];// 将比枢轴值大的元素移动到右端
	}

	arr[left] = pivot; // 将枢轴元素放在最终位置

	return left;
}

void QuickSort(ElemType arr[], int left, int right)
{
	if (left < right)
	{
		int pivotPos = Partition(arr, left, right); // 划分
		QuickSort(arr, left, pivotPos - 1); // 快速排序左半部分
		QuickSort(arr, pivotPos + 1, right); // 快速排序右半部分
	}
}

/*
6、简单选择排序算法
   基本思想:
   假设排序表为L[1...n],第i趟排序从表中选择关键字最小的元素与Li交换,第一趟排序可以确定一个元素的
   最终位置,这样经过n-1趟排序就可以使得整个排序表有序。
*/

void SelectSort(ElemType arr[], int length)
{
	int i, j, min;
    ElemType tmp;

	for (i = 0; i < length - 1; ++i) // 需要n-1趟
	{
		min = i;

		for (j = i + 1; j < length; ++j)
		{
			if (arr[j] < arr[min]) // 每一趟选择元素值最小的下标
			{
				min = j;
			}
		}

		if (min != i) // 如果第i趟的Li元素值该趟找到的最小元素值,则交换,以使Li值最小
		{
			tmp = arr[i];
			arr[i] = arr[min];
			arr[min] = tmp;
		}
	}
}

/*
7、堆排序算法
    堆的定义如下:n个关键字序列号L[1..n]称为堆,仅当该序列满足:
	1)L(i) <= L(2i)且L(i) <= L(2i+1) 或 2)L(i) >= L(2i)且L(i) >= L(2i+1)
	满足第一种情况的堆,称为小根堆(小顶堆);
	满足第二种情况的堆,称为大根堆(大顶堆)。
*/
void HeapAdjust(ElemType *a,int i,int size)  //调整堆
{
	int lchild = 2 * i;       //i的左孩子节点序号
	int rchild = 2 * i + 1;     //i的右孩子节点序号
	int max = i;            //临时变量 

	if(i <= size / 2)          //如果i是叶节点就不用进行调整
	{
		if (lchild <= size && a[lchild] > a[max])
		{
			max = lchild; // 左孩子比双亲值还大,需要调整
		}  

		if (rchild <= size && a[rchild] > a[max])
		{
			max = rchild;// 右孩子比双亲值还大,需要调整
		}

		if (max != i) // 需要调整
		{
			ElemType tmp = a[max];
			a[max] = a[i];
			a[i] = tmp;

			HeapAdjust(a, max, size);    //避免调整之后以max为父节点的子树不是堆
		}
	}
}

void BuildHeap(ElemType *a,int size)    //建立堆
{
	for (int i = size / 2; i >= 0; i--)    //非叶节点最大序号值为size/2
	{
		HeapAdjust(a, i, size);
	}
} 

void HeapSort(ElemType *a, int size)    //堆排序
{
	BuildHeap(a,size);

	for(int i = size - 1; i >= 0; i--)
	{
		swap(a[0], a[i]);           //交换堆顶和最后一个元素,即每次将剩余元素中的最大者放到最后面
		BuildHeap(a, i-1);        //将余下元素重新建立为大顶堆
		HeapAdjust(a,1,i-1);      //重新调整堆顶节点成为大顶堆
	}
} 

void Display(ElemType arr[], int length)
{
	for ( int i = 0; i < length; ++i )
	{
		cout << arr[i] << " ";
	}

	cout << endl;
}
int main()
{
	ElemType arr[] = {2, 1, 5, 3, 4, 0, 6, 9, -1, 4, 12};

	//InsertSort(arr, sizeof(arr) / sizeof(ElemType));
	//BinaryInsertSort(arr, sizeof(arr) / sizeof(ElemType));
	//ShellSort(arr, sizeof(arr) / sizeof(ElemType));
	//BubbleSort(arr, sizeof(arr) / sizeof(ElemType));
    //QuickSort(arr, 0,  sizeof(arr) / sizeof(ElemType) - 1);
	HeapSort(arr, sizeof(arr) / sizeof(ElemType));
	Display(arr, sizeof(arr) / sizeof(ElemType));

	return 0;
}
时间: 2024-08-03 11:26:47

常用的各种排序算法的相关文章

图解程序员必须掌握的Java常用8大排序算法_java

这篇文章主要介绍了Java如何实现八个常用的排序算法:插入排序.冒泡排序.选择排序.希尔排序 .快速排序.归并排序.堆排序和LST基数排序,分享给大家一起学习. 分类1)插入排序(直接插入排序.希尔排序) 2)交换排序(冒泡排序.快速排序) 3)选择排序(直接选择排序.堆排序) 4)归并排序 5)分配排序(基数排序) 所需辅助空间最多:归并排序 所需辅助空间最少:堆排序 平均速度最快:快速排序 不稳定:快速排序,希尔排序,堆排序. 先来看看8种排序之间的关系: 1.直接插入排序 (1)基本思想:

java常用的7大排序算法汇总

这段时间闲了下来,就抽了点时间总结了下java中常用的七大排序算法,希望以后可以回顾! 1.插入排序算法 插入排序的基本思想是在遍历数组的过程中,假设在序号 i 之前的元素即 [0..i-1] 都已经排好序,本趟需要找到 i 对应的元素 x 的正确位置 k ,并且在寻找这个位置 k 的过程中逐个将比较过的元素往后移一位,为元素 x "腾位置",最后将 k 对应的元素值赋为 x ,一般情况下,插入排序的时间复杂度和空间复杂度分别为 O(n2 ) 和 O(1). /**  * @param

排序算法笔记说明

         排序算法相关内容(Java实现)是个人理解并代码实现的常用的内部排序算法,目前包括如下七大算法(暂不包括基数排序):          直接插入排序.希尔排序.简单选择.堆排.冒泡.快排.归并排序.          相关内容最初写在自己的云笔记上,现发表于博客,希望和大家多多交流.由于多数内容是直接从云笔记上copy过来的,编辑器不同使得个别文字格式或许有些不美观,但这不影响阅读.如有需要,将尽可能优化使其更美观.          在写这些内容之时,也借鉴了一些前辈的文章,

Java 实现的各种经典的排序算法小Demo

由于有上机作业,所以就对数据结构中常用的各种排序算法都写了个Demo,有如下几个: 直接插入排序 折半插入排序 希尔排序 冒泡排序 快速排序 选择排序 桶排序 Demo下载地址 下面谈一谈我对这几个排序算法的理解: 插入类算法 对于直接插入排序:(按从小到大的顺序) 核心原理: 若数组中只有一个元素,那么这就已经是有序的了:若数组中元素个数为两个,我们只需要对他们进行比较一次,要么交换顺序,要么不交换顺序就可以实现数组的内容的有序化:但是当数组内的元素的个数为N个呢?又该如何?这就催化了这个直接

C#几种常用的排序算法

排序|算法 C#几种常用的排序算法:1 冒泡排序法 1冒泡排序法#region 冒泡排序法 2public void Sort(int[] list) 3{ 4    long begintime = System.DateTime.Now.Second*1000+System.DateTime.Now.Millisecond; 5    WriteLine(begintime); 6    int j,temp; 7    j= 1; 8    while((j<list.Length)) 9

搜索引擎常用的三种网站排序算法

搜索引擎如何对互联网上那么多的网站进行合适的排名?想必做站长的都想知道这一点,这是通过一套非常繁琐复杂的算法计算出来的,具体的算法想必没有几个人知道,但是最常用的三种算法还是需要大家去了解一下的. 1.词频位置加权排序算法:顾名思义是说从整个网站上的文字的位置上与出现的次数进行排序,先来说一下位置,不同的网站关键词在内容里出现与在标题里面出现时差别非常大的,搜索引擎认为标题能表现出一个网站是干什么的,如果标题里面出现了关键词要远比文章里面出现关键词重要的多的多.这就是现在大家都知道一个网站的标题

常用内部排序算法之五:希尔排序

前言 在前面介绍常用内部排序算法的文章中,我们知道在简单排序算法中,直接插入排序算法的时间复杂度是要优于冒泡排序和简单选择排序的.而这里要讲的希尔排序则是优于直接插入排序的.而且希尔排序打破了原来简单排序中时间复杂度不能超过O(n2)的神话.这也是希尔排序伟大的地方,而且希尔排序不同于之前三种简单排序,希尔排序是以一个科学家的名字进行命名的. 希尔排序的原理 由于希尔排序是在直接插入排序的基础上进行改进的,所以为了更好理解希尔排序,需要再次将直接插入排序请出来.我们知道直接插入排序的基本思想是将

视觉直观感受7种常用的排序算法

1 快速排序 介绍: 快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较.在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见.事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来,且在大部分真实世界的数据,可以决定设计的选择,减少所需时间的二次方项之可能性. 步骤: ▲从数列中挑出一个元素,称为 "基准"(Pivot), ▲重新排序数列,所有

视觉直观感受 7 种常用排序算法

10月14日发布<统计世界的十大算法>后,很多朋友在后台询问,哪里有"视觉直观感受 7 种常用排序算法",今天分享给大家,感谢todayx.org. 1. 快速排序 介绍: 快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较.在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见.事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来,