std中稳定排序算法_八大经典排序算法

本文详细介绍了四种基本排序算法:直接插入排序、希尔排序、简单选择排序以及堆排序。直接插入排序是将元素逐个插入已排序部分;希尔排序通过分组进行插入排序;简单选择排序是找到最小值并交换到前面;堆排序利用堆的性质进行排序。每种算法都给出了具体的实现代码,并分析了它们的时间复杂度和工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ca2cead736c48c42b380d986f3149470.png

一、插入排序-直接插入排序(Straight Insertion Sort)

直接插入排序(Straight Insertion Sort)的基本思想是:把n个待排序的元素看成为一个有序表和一个无序表。开始时有序表中只包含1个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,将它插入到有序表中的适当位置,使之成为新的有序表,重复n-1次可完成排序过程。

#include

using namespacestd;void InsertSort(int *a,intn)

{for(int i=1;i

{if(a[i]

{int j=i-1;int x=a[i];

a[i]=a[i-1];while(x

a[j]=x;

}

}

}intmain()

{int a[8]={-3,-1,-5,-7,-2,-4,-9,-6};

InsertSort(a,8);for(int i=0;i<8;i++)

printf("%d%c",a[i],i==7?'\n':' ');return 0;

}

二、插入排序-希尔排序(Shell's Sort)

希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

如-3,-1,-5,-7,-2,-4,-9,-6

第一次分组k=8/2=4,分为四组(-3,-2)(-1,-4)(-5,-9)(-7,-6)排序后为-3,-4,-9,-7,-2,-1,-5,-6;第二次k=4/2=2

分为两组(隔二取一)(-3,-9,-2,-5)(-4,-7,-1,-6)

-9,-7,-5,-6,-3,-4,-2,-1

第二次 k=1,整体为一组,直接插序。

#include

using namespacestd;void ShellSort(int *a,intn)

{for(int k=n/2;k;k/=2)

{for(int i=k;i

{for(int j=i-k;j>=0;j-=k)if(a[j]>a[j+k]) swap(a[j],a[j+k]);

}

}

}intmain()

{int a[8]={-3,-1,-5,-7,-2,-4,-9,-6};

ShellSort(a,8);for(int i=0;i<8;i++)

printf("%d%c",a[i],i==7?'\n':' ');return 0;

}

三、选择排序-简单选择排序(Simple Selection Sort)

选则排序,和插入排序不同的是,每次从数组中选择一个最小的数,放到前面,因此就是n次循环O(n^2)

void SelectionSort(int *a,intn)

{for(int i=0;i

{int k=i;for(int j=i+1;j

}

}intmain()

{int a[8]={-3,-1,-5,-7,-2,-4,-9,-6};

SelectionSort(a,8);for(int i=0;i<8;i++)

printf("%d%c",a[i],i==7?'\n':' ');return 0;

}

上面的选择排序,每次确定一个最小值,循环n次,也可以二元选择,每次确定一个最大值,一个最小值,因此可以减少循环。

//二元选择排序

#include

using namespacestd;void SelectionSort_TwoPoint(int *a,intn)

{for(int i=0;i

{int mink=i,maxk=n-i-1;for(int j=i;j

{if(a[j]

}if(mink==n-i-1 && maxk==i) swap(a[i],a[n-i-1]);//避免二次交换

else if(maxk==i) swap(a[n-i-1],a[i]),swap(a[i],a[mink]);else swap(a[i],a[mink]),swap(a[maxk],a[n-i-1]);

}

}intmain()

{int a[8]={0,-1,-5,-7,-2,-4,-9,-3};

SelectionSort_TwoPoint(a,8);for(int i=0;i<8;i++)

printf("%d%c",a[i],i==7?'\n':' ');return 0;

}

四、选择排序-堆排序(Heap Sort)

什么是堆(Heap):

(1)堆中某个节点的值总是不大于或不小于其父节点的值;

(2)堆总是一颗完全二叉树(Complete Binary Tree)

完全二叉树是由满二叉树(Full Binary Tree)而引出来的。除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树称为满二叉树。

如果除最后一层外,每一层上的节点数均达到最大值;在最后一层上只缺少右边的若干结点,这样的二叉树被称为完全二叉树。

680d080f5a98719d9a5420c6344f167f.png

一棵完全二叉树,如果某个节点的值总是不小于其父节点的值,则根节点的关键字是所有节点关键字中最小的,称为小根堆(小顶堆);如果某个节点的值总是不大于其父节点的值,则根节点的关键字是所有节点关键字中最大的,称为大根堆(大顶堆)。

若一个数列满足

baa261ed38baad3a1e0136054ad0ec19.png时可称之为堆(即任何一个子树的根节点所对应的元素一定是这颗子树所代表的所有元素中最小或最大的元素)

堆排序的核心是建树,任何一个树的父节点的个数为n/2,设父节点的标号为u,则左儿子的标号为2*u,右儿子的标号为2*u+1;

建树的核心为从父节点所在的最底层开始建树,每次比较父节点,左儿子和右儿子的元素大小,把最大最小的元素放到父节点的位置上(左儿子和右儿子的相对大小不做要求),若父节点的元素已经为最大(或最小),则继续向上建树,否则,交换元素后向下回溯。(建树从下往上,回溯从上往下)

以0,-1,-5,-7,-2,-4,-9,-3为例:

元素的个数为8,所以有4个父节点。

ac569d82ab150a3e065b055df6cf279a.png

建树完成后,1节点为最大值,交换到数组最后,之后维护前面的数,调整二叉树,直到排序完成。

代码实现:

#include

using namespacestd;void HeapAdjust(int *a,int u,intn)

{int lson=2*u,rson=2*u+1,maxelement=u;if(u<=n/2)

{if(lson<=n && a[maxelement]

### C++ 中八大排序算法的实现 #### 1. 插入排序 插入排序是一种简单直观的排序算法,它的工作原理类似于人们整理手中的扑克牌。每次从未排序部分取出一个元素,在已排序部分找到合适的位置将其插入。 ```cpp void insertionSort(std::vector<int>& arr) { for (size_t i = 1; i < arr.size(); ++i) { int key = arr[i]; int j = i - 1; while (j >= 0 && arr[j] > key) { arr[j + 1] = arr[j]; --j; } arr[j + 1] = key; } } ``` #### 2. 冒泡排序 冒泡排序通过重复遍历要排序的列表来工作,依次比较相邻项,并按需交换位置直到整个数组变得有序为止[^1]。 ```cpp void bubbleSort(std::vector<int>& arr) { bool swapped; for (size_t i = 0; i < arr.size() - 1; ++i) { swapped = false; for (size_t j = 0; j < arr.size() - i - 1; ++j) { if (arr[j] > arr[j + 1]) { std::swap(arr[j], arr[j + 1]); swapped = true; } } // 如果没有发生任何交换,则说明已经完成排序 if (!swapped) break; } } ``` #### 3. 简单选择排序 该方法首先找出最小(或最大)元素并与第一个元素互换;接着在剩下的未处理区域继续寻找次小值并移动到第二个位置...以此类推直至全部记录都有序[^3]。 ```cpp void selectionSort(std::vector<int>& arr) { for (size_t i = 0; i < arr.size() - 1; ++i) { size_t minIndex = i; for (size_t j = i + 1; j < arr.size(); ++j) { if (arr[j] < arr[minIndex]) minIndex = j; } if (minIndex != i) std::swap(arr[i], arr[minIndex]); } } ``` #### 4. 希尔排序 希尔排序是对直接插入排序的一种改进版本,其基本思想是在待排序列上构建间隔逐渐减小的子序列来进行排序操作,最后当增量降为1时即完成了最终的一轮完整的插入排序过程[^5]。 ```cpp void shellSort(std::vector<int>& arr) { for (int gap = arr.size() / 2; gap > 0; gap /= 2) { for (size_t i = gap; i < arr.size(); ++i) { int temp = arr[i]; int j; for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) { arr[j] = arr[j - gap]; } arr[j] = temp; } } } ``` #### 5. 快速排序 快速排序采用分治策略,选取一个基准元素将原始数组划分为两部分——小于等于基准的部分位于左侧而大于它的则置于右侧,之后递归地对这两边应用相同的操作,直到所有区间都被完全划分完毕[^2]。 ```cpp void quickSort(std::vector<int>& arr, int low, int high) { if (low < high) { int pi = partition(arr, low, high); quickSort(arr, low, pi - 1); // 对左半区进行快排 quickSort(arr, pi + 1, high); // 对右半区进行快排 } } int partition(std::vector<int>& arr, int low, int high) { int pivot = arr[high]; // 取最后一个作为枢轴 int i = low - 1; for (int j = low; j <= high - 1; ++j) { if (arr[j] < pivot) { ++i; std::swap(arr[i], arr[j]); } } std::swap(arr[i + 1], arr[high]); return i + 1; } ``` #### 6. 堆排序 堆排序利用了二叉堆这种特殊的数据结构特性,先建立最大(小)根堆再逐个删除堆顶节点从而达到升序或者降序的效果。 ```cpp void heapify(std::vector<int>& arr, int n, int i) { int largest = i; int l = 2 * i + 1; int r = 2 * i + 2; if (l < n && arr[l] > arr[largest]) largest = l; if (r < n && arr[r] > arr[largest]) largest = r; if (largest != i) { std::swap(arr[i], arr[largest]); heapify(arr, n, largest); } } void heapSort(std::vector<int>& arr) { int n = arr.size(); for (int i = n / 2 - 1; i >= 0; --i) heapify(arr, n, i); for (int i = n - 1; i >= 0; --i) { std::swap(arr[0], arr[i]); heapify(arr, i, 0); } } ``` #### 7. 归并排序 归并排序也是一种基于分治原则的经典排序技术,主要思路就是把原表不断分割成较小规模的问题求解后再逐步合并回原来大小的过程。 ```cpp void merge(std::vector<int>& arr, int const left, int const mid, int const right) { auto subArrayOne = mid - left + 1; auto subArrayTwo = right - mid; std::vector<int> leftArray(subArrayOne), rightArray(subArrayTwo); for (auto i = 0; i < subArrayOne; i++) leftArray[i] = arr[left + i]; for (auto j = 0; j < subArrayTwo; j++) rightArray[j] = arr[mid + 1 + j]; int indexOfSubArrayOne = 0, indexOfSubArrayTwo = 0; int indexOfMergedArray = left; while (indexOfSubArrayOne < subArrayOne && indexOfSubArrayTwo < subArrayTwo) { if (leftArray[indexOfSubArrayOne] <= rightArray[indexOfSubArrayTwo]) { arr[indexOfMergedArray] = leftArray[indexOfSubArrayOne++]; } else { arr[indexOfMergedArray] = rightArray[indexOfSubArrayTwo++]; } indexOfMergedArray++; } while (indexOfSubArrayOne < subArrayOne) { arr[indexOfMergedArray++] = leftArray[indexOfSubArrayOne++]; } while (indexOfSubArrayTwo < subArrayTwo) { arr[indexOfMergedArray++] = rightArray[indexOfSubArrayTwo++]; } } void mergeSort(std::vector<int>& arr, int const begin, int const end) { if (begin >= end) return; auto mid = begin + (end - begin) / 2; mergeSort(arr, begin, mid); mergeSort(arr, mid + 1, end); merge(arr, begin, mid, end); } ``` #### 8. 计数排序 不同于上述几种内部排序方式,计数排序属于外部排序范畴,适用于整型数据集且范围有限的情况。此算法创建了一个额外的空间用于统计输入序列中各数值出现次数的信息,进而重构出新的有序序列。 ```cpp void countSort(std::vector<int>& arr) { int maxElement = *std::max_element(arr.begin(), arr.end()); int minElement = *std::min_element(arr.begin(), arr.end()); int range = maxElement - minElement + 1; std::vector<int> count(range, 0); for(auto& num : arr){ count[num-minElement]++; } int index = 0; for(int a=0;a<range;++a){ while(count[a]>0){ arr[index++]=a+minElement; --count[a]; } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值