八大排序算法总结

在这里插入图片描述
在这里插入图片描述

选择排序算法准则:

每种排序算法都各有优缺点。

影响排序的因素有很多,平均时间复杂度低的算法并不一定就是最优的。相反,有时平均时间复杂度高的算法可能更适合某些特殊情况。同时,选择算法时还得考虑它的可读性,以利于软件的维护。一般而言,需要考虑的因素有以下四点:

1.待排序的记录数目n的大小;

2.记录本身数据量的大小,也就是记录中除关键字外的其他信息量的大小;

3.关键字的结构及其分布情况;

4.对排序稳定性的要求。

设待排序元素的个数为n.
1)当n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序、堆排序或归并排序序。

   **快速排序**:是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;
   **堆排序** :  如果内存空间允许且要求稳定性的,
   **归并排序**:它有一定数量的数据移动,所以我们可能过与插入排序组合,先获得一定长度的序列,然后再合并,在效率上将有所提高。

2)当n较大,内存空间允许,且要求稳定性 ——归并排序
3)当n较小,可采用直接插入或直接选择排序。

	**直接插入排序**:当元素分布有序,直接插入排序将大大减少比较次数和移动记录的次数。
	**直接选择排序** :元素分布有序,如果不要求稳定性,选择直接选择排序

4)一般不使用或不直接使用传统的冒泡排序。

5)基数排序
它是一种稳定的排序算法,但有一定的局限性:
  1、关键字可分解。
  2、记录的关键字位数较少,如果密集更好
  3、如果是数字时,最好是无符号的,否则将增加相应的映射复杂度,可先将其正负分开排序

插入排序:

直接插入排序

思想:将数组中的所有元素依次和前面的已经排好序的元素相比较(依次),如果选择的元素比已排序的元素小,则交换,直到全部元素都比较过。在这里插入图片描述

#include <stdio.h>
#include<iostream>
using namespace std;
void display(int array[], int size) {
	for (int i = 0; i < size; i++) {
		printf("%d ", array[i]);
	}
	printf("\n");
}

void InsertSort(int array[], int size) {
	for (int i = 1; i < size; i++) {        // 第 1 个数肯定是有序的,从第 2 个数开始遍历,依次插入有序序列
		int temp = array[i];                // 取出第 i 个数,和前 i-1 个数比较后,插入合适位置
		int j = i - 1;                   // 因为前 i-1 个数都是从小到大的有序序列,所以只要当前比较的数 (array[j]) 比 temp 大,就把这个数后移一位
		while (j >= 0 && array[j] > temp) { // 当 j < 0 或 array[j] < temp(array[i]) 时终止
			array[j + 1] = array[j];        // 将大于 temp(array[i]) 的数据后移
			j--;                            // 向前比较
		}                                   // 结束循环
		array[j + 1] = temp;                // array[i]插入到正确的位置上

		//打印每次排序结果
		display(array, size);
	}
}

int main() {
	int array[] = { 49, 38, 65, 97, 76, 13, 27, 49, 10 };
	int size = sizeof(array) / sizeof(int);

	//打印原始数据
	printf("%d \n", size);
	display(array, size);
	InsertSort(array, size);
	system("pause");
	return 0;
}

最好的情况:数组本身就是有序的,只是进行比较,时间复杂度是O(n)
最坏的情况:数组是逆序的,时间复杂度O(n²)
平均情况:O(n²)

希尔排序

思想:希尔排序也称缩小增量排序;希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序,随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时(用gap = gap/3+1 控制),保证了最后一次进行直接插入排序,算法终止。(其中直接插入排序是希尔排序gap=1的特例)另外,gap越大,值越大的容易到最后面,但是不太接近有序。—— 一般gap不要超过数组大小的一半
在这里插入图片描述

https://www.bilibili.com/video/BV1rE411g7rW?from=search&seid=8131314960769167697

void print(int a[], int n ,int i){  
    cout<<i <<":";  
    for(int j= 0; j<8; j++){  
        cout<<a[j] <<" ";  
    }  
    cout<<endl;  
}  
/** 
 * 直接插入排序的一般形式 
 * 
 * @param int dk 缩小增量,如果是直接插入排序,dk=1 
 * 
 */  
  
void ShellInsertSort(int a[], int n, int dk)  
{  
    for(int i= dk; i<n; ++i){  
        if(a[i] < a[i-dk]){          //若第i个元素大于i-1元素,直接插入。小于的话,移动有序表后插入  
            int j = i-dk;     
            int x = a[i];           //复制为哨兵,即存储待排序元素  
            a[i] = a[i-dk];         //首先后移一个元素  
            while(x < a[j]){     //查找在有序表的插入位置  
                a[j+dk] = a[j];  
                j -= dk;             //元素后移  
            }  
            a[j+dk] = x;            //插入到正确位置  
        }  
        print(a, n,i );  
    }  
      
}  
  
/** 
 * 先按增量d(n/2,n为要排序数的个数进行希尔排序 
 * 
 */  
void shellSort(int a[], int n){  
  
    int dk = n/2;  
    while( dk >= 1  ){  
        ShellInsertSort(a, n, dk);  
        dk = dk/2;  
    }  
}  
int main(){  
    int a[8] = {3,1,5,7,2,4,9,6};  
    //ShellInsertSort(a,8,1); //直接插入排序  
    shellSort(a,8);           //希尔插入排序  
    print(a,8,8);  
}  

选择排序

选择排序

思想:在一个无序数组中选择出每一轮中最值元素,然后把这一轮中最前面的元素和min交换,最后面的元素和max交换;然后缩小范围(开始位置(begin++)++,最后位置(end - -)- -),重复上面步骤,最终得到有序序列(升序)。在这里插入图片描述

void SelectSort(int* a,size_t n)
{
	assert(a);
	int begin = 0;
	int end = n-1;
	while ( begin < end )
	{
		int min = begin,max = begin;
		for(int i = begin; i <= end; ++i)
		{
			if( a[min] > a[i] )
				min = i;
			if( a[max] < a[i] )
				max = i;
		}
		swap( a[min],a[begin] );
		if( max == begin )//如果首元素是最大的,则需要先把min 和 max的位置一换,再交换,否则经过两次交换,又回到原来的位置
			max = min;
		swap( a[max],a[end] );
		begin++;
		end--;
	}
}


堆排序

思想:
堆排序利用了大堆(或小堆)堆顶记录的关键字最大(或最小)这一特征,使得当前无序的序列中选择关键最大(或最小)的记录变得简单。(升序—建大堆,降序—建小堆)

#include<iostream>
#include<vector>
using namespace std;

// 递归方式构建大根堆(len是arr的长度,index是第一个非叶子节点的下标)
void adjust(vector<int> &arr, int len, int index)
{
	int left = 2 * index + 1; // index的左子节点
	int right = 2 * index + 2;// index的右子节点

	int maxIdx = index;
	if (left<len && arr[left] > arr[maxIdx])     maxIdx = left;
	if (right<len && arr[right] > arr[maxIdx])     maxIdx = right;//找到树里的最大值的下标

	if (maxIdx != index)//最大值的下标不是树顶
	{
		swap(arr[maxIdx], arr[index]);
		adjust(arr, len, maxIdx);
	}

}

// 堆排序
void heapSort(vector<int> &arr, int size)
{
	// 构建大根堆(从最后一个非叶子节点向上)
	for (int i = size / 2 - 1; i >= 0; i--)
	{
		adjust(arr, size, i);
	}

	// 调整大根堆
	for (int i = size - 1; i >= 1; i--)
	{
		swap(arr[0], arr[i]);           // 将当前最大的放置到数组末尾
		adjust(arr, i, 0);              // 将未完成排序的部分继续进行堆排序
	}
}

int main()
{
	vector<int> arr = { 8, 1, 14, 3, 21, 5, 7, 10 };
	heapSort(arr, arr.size());
	for (int i = 0; i<arr.size(); i++)
	{
		cout << arr[i] << endl;
	}
	system("pause");
	return 0;
}


交换排序

冒泡排序

基本思想就是:从无序序列头部开始,进行两两比较,根据大小交换位置,直到最后将最大(小)的数据元素交换到了无序队列的队尾,从而成为有序序列的一部分;下一次继续这个过程,直到所有数据元素都排好序。

算法的核心在于每次通过两两比较交换位置,选出剩余无序序列里最大(小)的数据元素放到队尾。
在这里插入图片描述

#include<iostream>
#include<vector>
using namespace std;

vector<int> sort(vector<int> &ivec);
int main()
{
	cout << "请输入想要排序的数字:" << endl;
	int i = 0;
	vector<int> ivec;

	while (cin >> i)
	{
		ivec.push_back(i);
	}

	cout << "为排序前的序列:" << endl;

	for (vector<int>::iterator iter = ivec.begin();
		iter != ivec.end(); ++iter)
	{
		cout << *iter << " ";
	}
	cout << endl;

	cout << "排序后的序列如下:" << endl;
	//排序
	vector<int> i_vec = sort(ivec);
	//输出
	for (vector<int>::iterator i_iter = i_vec.begin();
		i_iter != i_vec.end(); ++i_iter)
	{
		cout << *i_iter << " ";
	}
	cout << endl;
	system("pause");
	return 0;
}


vector<int> sort(vector<int> &ivec)
{
	const int  COUNT = ivec.size();
	for (int i = 1; i<COUNT; i++)//这一行只是为了排除最后已经沉到最底下的元素
	{
		for (int j = 0; j<COUNT - i; ++j)
		{
			if (ivec[j]>ivec[j + 1])
			{
				int temp = 0;
				temp = ivec[j];
				ivec[j] = ivec[j + 1];
				ivec[j + 1] = temp;
			}
			for (vector<int>::iterator i_iter = ivec.begin();
				i_iter != ivec.end(); ++i_iter)
			{
				cout << *i_iter << " ";
			}
			cout << endl;
			
		}
	}
	return ivec;
}



快速排序

基本思想:

1)选择一个基准元素,通常选择第一个元素或者最后一个元素,

2)通过一趟排序讲待排序的记录分割成独立的两部分,其中一部分记录的元素值均比基准元素值小。另一部分记录的元素值比基准值大。

3)此时基准元素在其排好序后的正确位置

4)然后分别对这两部分记录用同样的方法继续进行排序,直到整个序列有序。

void quickSort(int *array, int left, int right)
{
	if(left < right)
	{
		int pivot = array[left];
		int low = left, high = right;
		while(low < high)
		{
			while(array[high] >= pivot && low < high)
				high--;
			array[low] = array[high];
			
			while(array[low] <= pivot && low < high)
				low++;
			array[high] = array[low];
		}
		array[low] = pivot;
		
		quickSort(array, left, low - 1);
		quickSort(array, low + 1, right);
	}
}

归并排序

在这里插入图片描述

#include <iostream>
#include <algorithm>
#define MAXSIZE 1000
using namespace std;
void swap(int array[], int i, int j)
{
	int temp = array[i];
	array[i] = array[j];
	array[j] = temp;
}
void Merge(int src[], int des[], int low, int mid, int high)
//归并的过程
//src是数组,des是目的地
{
	int i = low;
	int j = mid + 1;
	int k = low;
	while ((i <= mid) && (j <= high))//将小的放到目的地中
		//这个如果没有等于号就不是稳定排序
	{
		if (src[i] < src[j]) des[k++] = src[i++];
		else des[k++] = src[j++];
	}
	while (i <= mid)//若还剩几个尾部元素
		des[k++] = src[i++];
	while (j <= high)//若还剩几个尾部元素
		des[k++] = src[j++];

}

//每次兵分两路,当只剩下一个元素时,就不需要再划分
void Msort(int src[], int des[], int low, int high, int max)
//划分的过程
{
	if (low == high)//只有一个元素,不用归并,结果赋给des[low]
		des[low] = src[low];
	else  //如果两个元素,进行二路划分
	{
		int mid = (low + high) / 2;
		int TR2[MAXSIZE+1];//辅助数组

		//递归进行两路两路的划分
		//当剩下一个元素的时候,递归划分结束,然后开始merge归并操作
			Msort(src, TR2, low, mid, max);
			Msort(src, TR2, mid + 1, high, max);
			Merge(TR2, des, low, mid, high);//调用归并函数进行归并
	}
}
void MergeSort(int array[], int len)
{
	Msort(array, array, 0, len - 1, len);
	//Msort(原数组,目标数组,原数组中的最低位和最高位,长度)
}
int main()
{
	int array[] = { 12, 5, 433, 7, 98, 32, 11, 8, 2, 56 };
	int len = sizeof(array) / sizeof(*array);
	cout << "before sorting:" << endl;
	for (int i = 0; i <len; ++i)
	{
		cout << array[i] << " ";
	}
	cout << endl;

	MergeSort(array, len);

	cout << "after sorting:" << endl;
	for (int i = 0; i <len; ++i)
	{
		cout << array[i] << " ";
	}
	cout << endl;

	system("pause");
	return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数据结构中的八大排序算法,是指常见的八种用于对数据进行排序的算法。这八种算法分别是冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序、计数排序和基数排序。 冒泡排序是一种简单的排序算法,通过不断比较和交换相邻元素的位置,使得最大(或最小)的元素逐渐往后(或往前)移动。 选择排序是一种简单直观的排序算法,每次选择未排序序列中最小(或最大)的元素,放到已排序序列的末尾。 插入排序是一种简单直观的排序算法,将一个待排序的元素插入到已部分排序的数列中的合适位置。 希尔排序是一种改进的插入排序算法,通过将待排序数列分组,并对每个分组进行插入排序,然后逐渐减小分组规模,最后进行一次插入排序。 归并排序是一种分治思想的排序算法,将待排序数列不断分割成较小的数列,然后再将这些较小的数列按照顺序进行合并。 快速排序是一种分治思想的排序算法,通过选择一个中间的基准元素,将数列分割成两部分,然后分别对这两部分进行排序。 堆排序是一种利用堆这种数据结构的排序算法,通过将待排序数列构建成一个大(或小)顶堆,然后逐步将堆顶元素与最后一个元素交换,并调整堆结构。 计数排序是一种非比较型的排序算法,通过统计待排序数列中每个元素出现的次数,然后依次输出即可。 基数排序是一种非比较型的排序算法,通过对待排序数列的每个位进行排序,依次从低位到高位进行。 这里简单介绍了八大排序算法的基本思想和实现方法。在实际应用中,不同的排序算法适用于不同的场景和要求,我们需要根据具体情况选择合适的算法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值