本文主要内容:
- 插入排序
- 选择排序
- 冒泡排序
- 快速排序
- 归并排序
- 堆排序
- 基数排序
- 希尔排序
- 计数排序
- 桶排序
本文所有代码均使用C#编写
240505天气:小雨转多云
算法总结图1
1 插入排序2
插入排序(Insertion Sort):将序列分为已排序和未排序两部分,从未排序的部分选择元素插入到已排序的部分中,直到所有元素都被插入到已排序的部分。时间复杂度O(n2)。
void InsertSort(int[] nums)
{
int n = nums.Length;
for(int i = 1; i < n; i++)
{
int t = nums[i];
int j = i;
while(j > 0 && nums[j - 1] > t)
{
nums[j] = nums[j - 1];
j--;
}
nums[j] = t;
}
}
2 选择排序
从序列中选择最小的元素,放到序列的起始位置,再从剩余元素中选择最小的元素放到已排序序列的末尾。时间复杂度O(n2)。
void SelectSort(int[] nums)
{
int n = nums.Length;
for(int i = 0; i < n - 1; i++)
{
int minIndex = i;
for(int j = i + 1; j < n; j++)
if(nums[j] < nums[minIndex])
minIndex = j;
(nums[minIndex], nums[i]) = (nums[i], nums[minIndex]);
}
}
3 冒泡排序
相邻元素比较,逐步将最大元素“冒泡”到序列最后。时间复杂度O(n^2)。
void BubbleSort(int[] nums)
{
int n = nums.Length;
for(int i = 0; i < n - 1; i++)
for(int j = 0; j < n - 1 - i; j++)
if(nums[j] > nums[j + 1])
(nums[j], nums[j + 1]) = (nums[j + 1], nums[j]);
}
4 快速排序
1.基于分治的思想
2.先在递归区间内找到一个元素作为枢轴(pivot),将该区间处理成所有数小于等于pivot和所有数大于等于pivot的两个子区间
3.继续递归处理两个子区间,直到子区间长度小于等于1时结束递归
void QuickSort(int[] nums, int l, int r)
{
if(l >= r)return;
int i = l, j = r;
int pivot = nums[l];
while(i < j)
{
while(i < j && nums[j] >= pivot)j--;//前
while(i < j && nums[i] <= pivot)i++;//后
if(i < j)
(nums[i], nums[j]) = (nums[j], nums[i]);
}
nums[l] = nums[i];
nums[i] = pivot;
QuickSort(nums, l, i - 1);
QuickSort(nums, i + 1, r);
}
5 归并排序
1.基于分治的思想
2.将数组区间一分为而,先递归排序左子区间,再递归排序右子区间
3.将两个已经排好序的子区间归并成一个有序数组,然后结束递归
void MergeSort(int[] nums, int left, int right)
{
if(left >= right)
return;
int midIndex = left + right >> 1;
MergeSort(nums, left, midIndex);
MergeSort(nums, midIndex + 1, right);
int[] tempArr = new int[nums.Length];
for(int i = 0; i < nums.Length; i++)
tempArr[i] = nums[i];
int p = left, q = midIndex + 1, r = left;
while(p <= midIndex && q <= right)
{
if(tempArr[p] <= tempArr[q])
nums[r++] = tempArr[p++];
else
nums[r++] = tempArr[q++];
}
while(p <= midIndex)
nums[r++] = tempArr[p++];
while(q <= right)
nums[r++] = tempArr[q++];
}
6 堆排序
将数组存入小根堆中,第1次取出的堆顶元素就是最小的,然后移除堆顶元素,第2次取出的堆顶元素就是第2小的,以此类推
void HeapSort(int[] nums)
{
int n = nums.Length;
int[] myHeap = new int[n];
int myHeapSize = myHeap.Length;
for(int i = 0; i < n; i++)
myHeap[i] = nums[i];
for(int i = n / 2; i >= 0; i--)
Down(myHeap, i, myHeapSize);
for(int i = 0; i < n; i++)
{
nums[i] = myHeap[0];
(myHeap[0], myHeap[myHeapSize - 1]) = (myHeap[myHeapSize - 1], myHeap[0]);
myHeapSize--;
Down(myHeap, 0, myHeapSize);
}
}
//下沉
void Down(int[] myHeap, int curIndex, int myHeapSize)
{
int minIndex = curIndex;
int leftSon = curIndex * 2, rightSon = curIndex * 2 + 1;
if(leftSon < myHeapSize && myHeap[leftSon] < myHeap[minIndex])
minIndex = leftSon;
if(rightSon < myHeapSize && myHeap[rightSon] < myHeap[minIndex])
minIndex = rightSon;
if(minIndex != curIndex)
{
(myHeap[curIndex], myHeap[minIndex]) = (myHeap[minIndex], myHeap[curIndex]);
Down(myHeap, minIndex, myHeapSize);
}
}
7 基数排序
将待排序的整数拆分成多个数字位上的值,然后从最低位到最高位依次对每个数字位上的值进行排序。
练习题:164. 最大间距
void RadixSort(int[] nums)
{
int n = nums.Length;
int exp = 1;
int[] numCnt = new int[10];
int[,] tempSet = new int[10,n];
for(int i = 0; i < 10; i++){
for(int j = 0; j < n; j++){
int k = (nums[j] / exp) % 10;
tempSet[k,numCnt[k]] = nums[j];
numCnt[k]++;
}
for(int j = 0, t = 0; j < 10; j++){
for(int k = 0; k < numCnt[j]; k++){
nums[t++] = tempSet[j,k];
}
numCnt[j] = 0;
}
exp *= 10;
}
}
8 希尔排序
对插入排序的一种优化。将数组分为gap个组,组内进行插入排序,然后缩小分组,继续进行插入排序,最后整个数组分为1个组,进行插入排序时移动元素的次数会减少很多
void ShellSort(int[] nums)
{
int n = nums.Length;
int gap = n / 2;
while(gap > 0)
{
for(int i = gap; i < n; i++)
{
int temp = nums[i];
int j = i;
while(j - gap >= 0 && nums[j - gap] > temp)
{
nums[j] = nums[j - gap];
j -= gap;
}
nums[j] = temp;
}
gap /= 2;
}
}
9 计数排序
将原数组中每个数nums[i]出现的次数保存到另一个数组中count[],数组下标就为nums[i],数组值为nums[i]出现的次数,然后根据count[]来对原数组nums[]进行排序
void CountingSort(int[] nums)
{
int n = nums.Length;
if(n < 1)
return;
int minNum = nums[0];
int maxNum = nums[0];
foreach(int num in nums)
{
minNum = Math.Min(minNum, num);
maxNum = Math.Max(maxNum, num);
}
int range = maxNum - minNum + 1;
int[] count = new int[range];
foreach(int num in nums)
count[num - minNum]++;
for(int i = 1; i < range; i++)
count[i] += count[i - 1];
int[] temp = new int[n];
foreach(int num in nums)
{
int index = count[num - minNum] - 1;
temp[index] = num;
count[num - minNum]--;
}
Array.Copy(temp, nums, nums.Length);
}
10 桶排序
桶排序可以看做时计数排序的一种优化,计数排序可以看做单个元素作为1个桶的桶排序,桶排序一般以区间作为桶的宽度(即每个桶能装的元素种类数)。
桶排序的原理是将原数组分为若干段,每一段元素丢到一个桶中,再对每个桶分别排序,最后将各个桶中的元素从头到尾连起来
void BucketSort(int[] nums)
{
int n = nums.Length;
if(n < 1)
return;
int minNum = nums[0];
int maxNum = nums[0];
for(int i = 1; i < n; i++)
{
minNum = Math.Min(minNum, nums[i]);
maxNum = Math.Max(maxNum, nums[i]);
}
int range = maxNum - minNum;
int bucketCount = range / n + 1;
List<List<int>> buckets = new List<List<int>>(bucketCount);
for(int i = 0; i < bucketCount; i++)
buckets.Add(new List<int>());
foreach(int num in nums)
{
int bucketIndex = (num - minNum) / n;
buckets[bucketIndex].Add(num);
}
buckets.ForEach((List<int> list)=> list.Sort());
int numsIndex = 0;
for(int i = 0; i < bucketCount; i++)
{
List<int> bucket = buckets[i];
bucket.ForEach((int num) => nums[numsIndex++] = num);
}
}
10个排序算法完整代码(C#)
using System.Net;
int[] nums = {125, 16, 214, 111, 2, 30};
void InsertSort(int[] nums)
{
int n = nums.Length;
for(int i = 1; i < n; i++)
{
int t = nums[i];
int j = i;
while(j > 0 && nums[j - 1] > t)
{
nums[j] = nums[j - 1];
j--;
}
nums[j] = t;
}
}
void SelectSort(int[] nums)
{
int n = nums.Length;
for(int i = 0; i < n - 1; i++)
{
int minIndex = i;
for(int j = i + 1; j < n; j++)
if(nums[j] < nums[minIndex])
minIndex = j;
(nums[minIndex], nums[i]) = (nums[i], nums[minIndex]);
}
}
void BubbleSort(int[] nums)
{
int n = nums.Length;
for(int i = 0; i < n - 1; i++)
for(int j = 0; j < n - 1 - i; j++)
if(nums[j] > nums[j + 1])
(nums[j], nums[j + 1]) = (nums[j + 1], nums[j]);
}
void QuickSort(int[] nums, int l, int r)
{
if(l >= r)return;
int i = l, j = r;
int pivot = nums[l];
while(i < j)
{
while(i < j && nums[j] >= pivot)j--;
while(i < j && nums[i] <= pivot)i++;
if(i < j)
(nums[i], nums[j]) = (nums[j], nums[i]);
}
nums[l] = nums[i];
nums[i] = pivot;
QuickSort(nums, l, j - 1);
QuickSort(nums, j + 1, r);
}
void MergeSort(int[] nums, int left, int right)
{
if(left >= right)
return;
int midIndex = left + right >> 1;
MergeSort(nums, left, midIndex);
MergeSort(nums, midIndex + 1, right);
int[] tempArr = new int[nums.Length];
for(int i = 0; i < nums.Length; i++)
tempArr[i] = nums[i];
int p = left, q = midIndex + 1, r = left;
while(p <= midIndex && q <= right)
{
if(tempArr[p] <= tempArr[q])
nums[r++] = tempArr[p++];
else
nums[r++] = tempArr[q++];
}
while(p <= midIndex)
nums[r++] = tempArr[p++];
while(q <= right)
nums[r++] = tempArr[q++];
}
void HeapSort(int[] nums)
{
int n = nums.Length;
int[] myHeap = new int[n];
int myHeapSize = myHeap.Length;
for(int i = 0; i < n; i++)
myHeap[i] = nums[i];
for(int i = n / 2; i >= 0; i--)
Down(myHeap, i, myHeapSize);
for(int i = 0; i < n; i++)
{
nums[i] = myHeap[0];
(myHeap[0], myHeap[myHeapSize - 1]) = (myHeap[myHeapSize - 1], myHeap[0]);
myHeapSize--;
Down(myHeap, 0, myHeapSize);
}
}
void Down(int[] myHeap, int curIndex, int myHeapSize)
{
int minIndex = curIndex;
int leftSon = curIndex * 2, rightSon = curIndex * 2 + 1;
if(leftSon < myHeapSize && myHeap[leftSon] < myHeap[minIndex])
minIndex = leftSon;
if(rightSon < myHeapSize && myHeap[rightSon] < myHeap[minIndex])
minIndex = rightSon;
if(minIndex != curIndex)
{
(myHeap[curIndex], myHeap[minIndex]) = (myHeap[minIndex], myHeap[curIndex]);
Down(myHeap, minIndex, myHeapSize);
}
}
void RadixSort(int[] nums)
{
int n = nums.Length;
int exp = 1;
int[] numCnt = new int[10];
int[,] tempSet = new int[10,n];
for(int i = 0; i < 10; i++){
for(int j = 0; j < n; j++){
int k = (nums[j] / exp) % 10;
tempSet[k,numCnt[k]] = nums[j];
numCnt[k]++;
}
for(int j = 0, t = 0; j < 10; j++){
for(int k = 0; k < numCnt[j]; k++){
nums[t++] = tempSet[j,k];
}
numCnt[j] = 0;
}
exp *= 10;
}
}
void ShellSort(int[] nums)
{
int n = nums.Length;
int gap = n / 2;
while(gap > 0)
{
for(int i = gap; i < n; i++)
{
int temp = nums[i];
int j = i;
while(j - gap >= 0 && nums[j - gap] > temp)
{
nums[j] = nums[j - gap];
j -= gap;
}
nums[j] = temp;
}
gap /= 2;
}
}
void CountingSort(int[] nums)
{
int n = nums.Length;
if(n < 1)
return;
int minNum = nums[0];
int maxNum = nums[0];
foreach(int num in nums)
{
minNum = Math.Min(minNum, num);
maxNum = Math.Max(maxNum, num);
}
int range = maxNum - minNum + 1;
int[] count = new int[range];
foreach(int num in nums)
count[num - minNum]++;
for(int i = 1; i < range; i++)
count[i] += count[i - 1];
int[] temp = new int[n];
foreach(int num in nums)
{
int index = count[num - minNum] - 1;
temp[index] = num;
count[num - minNum]--;
}
Array.Copy(temp, nums, nums.Length);
}
void BucketSort(int[] nums)
{
int n = nums.Length;
if(n < 1)
return;
int minNum = nums[0];
int maxNum = nums[0];
for(int i = 1; i < n; i++)
{
minNum = Math.Min(minNum, nums[i]);
maxNum = Math.Max(maxNum, nums[i]);
}
int range = maxNum - minNum;
int bucketCount = range / n + 1;
List<List<int>> buckets = new List<List<int>>(bucketCount);
for(int i = 0; i < bucketCount; i++)
buckets.Add(new List<int>());
foreach(int num in nums)
{
int bucketIndex = (num - minNum) / n;
buckets[bucketIndex].Add(num);
}
buckets.ForEach((List<int> list)=> list.Sort());
int numsIndex = 0;
for(int i = 0; i < bucketCount; i++)
{
List<int> bucket = buckets[i];
bucket.ForEach((int num) => nums[numsIndex++] = num);
}
}
// InsertSort(nums);
// SelectSort(nums);
// BubbleSort(nums);
// QuickSort(nums, 0, nums.Length - 1);
// MergeSort(nums, 0, nums.Length - 1);
// HeapSort(nums);
// RadixSort(nums);
// ShellSort(nums);
// CountingSort(nums);
BucketSort(nums);
for(int i = 0; i < nums.Length; i++)
Console.Write(nums[i] + " ");
参考资料:
https://www.cnblogs.com/guoyaohua/p/8600214.html ↩︎
https://blog.csdn.net/weixin_64600209/article/details/131354250?ops_request_misc=&request_id=&biz_id=102&utm_term=%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-3-131354250.nonecase&spm=1018.2226.3001.4187 ↩︎