直接插入排序
插入排序的基本思想是:
每次将一个待排的记录,按照其关键字的大小,插入到前面已经排好序的有序区中适当的位置,直到全部记录插入完毕为止。
假设待排序的记录存放在数组R[0..n]中,初始时R[0]是一个有序区,R[1..n]是无序区,从i=1开始,依次将R[i]插入到有序区R[0..i-1]中,生成一个包含n个记录的有序区。
Sort.h
#pragma once
void PrintArray(int *a, size_t n)
{
for (size_t i = 0; i < n; ++i)
{
cout << a[i] << "";
}
cout << endl;//换行
}
void InsertSort(int *a, size_t n)
{
assert(a);
for (size_t i = 0; i < n - 1; ++i)
{
int end = i;
int tmp = a[end + 1];
while (end >= 0)
{
if (a[end]>tmp)
{
a[end + 1] = a[end];
--end;
}
else
{
break;
}
}
a[end + 1] = tmp;
}
}
void TestInsertSort()
{
int a[] = { 2, 5, 4, 9, 3, 6, 8, 7, 1, 0 };
PrintArray(a, sizeof(a) / sizeof(a[0]));
InsertSort(a, sizeof(a) / sizeof(a[0]));
PrintArray(a, sizeof(a) / sizeof(a[0]));
}
Test.cpp
#include<iostream>
#include<assert.h>
using namespace std;
#include"Sort.h"
int main()
{
TestInsertSort();
return 0;
}
SHELL排序
希尔排序又称为缩小增量排序,它是插入排序的一种变形。
希尔排序:
设待排序元素有n个,首先取一个整数gap
#pragma once
void PrintArray(int *a, size_t n)
{
for (size_t i = 0; i < n; ++i)
{
cout << a[i] << "";
}
cout << endl;//换行
}
void ShellSort(int *a, size_t n)
{
assert(a);
int gap = n;
while (gap > 1)
{
gap = gap / 3 + 1;
for (size_t i= 0; i < n - gap; ++i)
{
int end = i;
int tmp = a[end + gap];
while (end >= 0)
{
if (a[end]>tmp)
{
a[end + gap] = a[end];
end -= gap;
}
else
break;
}
a[end + gap] = tmp;
}
}
}
void TestShellSort()
{
int a[] = { 2, 5, 4, 9, 3, 6, 8, 7, 1, 0 };
PrintArray(a, sizeof(a) / sizeof(a[0]));
ShellSort(a, sizeof(a) / sizeof(a[0]));
PrintArray(a, sizeof(a) / sizeof(a[0]));
}
Test.cpp
#include<iostream>
#include<assert.h>
using namespace std;
#include"Sort.h"
int main()
{
TestShellSort();
return 0;
}
选择排序
选择排序的基本思想:初始时,有序区为0,每一趟在无序区中选出一个关键字最小的元素,然后与无序区第一个元素交换,然后无序区减1,有序区加1,直到记录全部排完。
直接选择排序:第一趟排序在R[0..n]中选出一个关键字最小的与R[0]交换,第二趟在R[1..n]中选择一个最小的与R[1]进行交换,以此类推直到无序区的记录只剩一个时排序完成。
Sort.h
#pragma once
void PrintArray(int *a, size_t n)
{
for (size_t i = 0; i < n; ++i)
{
cout << a[i] << "";
}
cout << endl;//换行
}
void SelectSort(int *a, size_t n)
{
assert(a);
size_t left = 0, right = n - 1;
while (left < right)
{
size_t min = left, max = left;
for (size_t i = left; i <= right; ++i)
{
if (a[min]>a[i])
min = i;
if (a[max] < a[i])
max = i;
}
//修正
swap(a[min], a[left]);
if (max == left)
max = min;
swap(a[max], a[right]);
++left; --right;
}
}
void TestSelectSort()
{
int a[] = { 9, 5, 4, 9, 3, 6, 8, 7, 1, 0 };
PrintArray(a, sizeof(a) / sizeof(a[0]));
SelectSort(a, sizeof(a) / sizeof(a[0]));
PrintArray(a, sizeof(a) / sizeof(a[0]));
}
Test.cpp
#include<iostream>
#include<assert.h>
using namespace std;
#include"Sort.h"
int main()
{
TestSelectSort();
return 0;
}
堆排序
时间复杂度: 第一次建堆的时间复杂度:O(N*lgN)。 每次调整的时间复杂度是O(lgN),总共有N次,即:O(N*lgN); 所以:
堆排序的时间复度:O(N*lgN)
Sort.h
#pragma once
void PrintArray(int *a, size_t n)
{
for (size_t i = 0; i < n; ++i)
{
cout << a[i] << "";
}
cout << endl;//换行
}
void AdjustDown(int *a, size_t root, size_t n)
{
size_t parent = root;
size_t child = parent * 2 + 1;
while (child < n)
{
if (child + 1 < n && a[child + 1] > a[child])
{
++child;
}
if (a[child]>a[parent])
{
swap(a[child], a[parent]);
parent = child;
child = 2 * parent + 1;
}
}
}
void HeapSort(int *a,size_t n)
{
assert(a);
for (int i = (n - 2) / 2; i >= 0; --i)
{
AdjustDown(a, i, n);
}
size_t end = n - 1;
while (end > 0)
{
swap(a[0], a[end]);
AdjustDown(a, 0, end);
}
}
void TestHeapSort()
{
int a[] = { 9, 5, 4, 9, 3, 6, 8, 7, 1, 0 };
PrintArray(a, sizeof(a) / sizeof(a[0]));
HeapSort(a, sizeof(a) / sizeof(a[0]));
PrintArray(a, sizeof(a) / sizeof(a[0]));
}
Test.cpp
#include<iostream>
#include<assert.h>
using namespace std;
#include"Sort.h"
int main()
{
TestHeapSort();
return 0;
}
冒泡排序
Sort.h
#pragma once
void PrintArray(int *a, size_t n)
{
for (size_t i = 0; i < n; ++i)
{
cout << a[i] << "";
}
cout << endl;//换行
}
void BubbleSort(int *a, size_t n)
{
assert(a);
int end = n;
while (end > 0)
{
bool exchange = false;
for (int i = 1; i < end; ++i)
{
if (a[i - 1]>a[i])
{
swap(a[i - 1], a[i]);
exchange = true;
}
}
if (exchange == false)
{
break;
}
--end;
}
}
void TestBubbleSort()
{
int a[] = { 1,2,3,4,5,7,6 };
PrintArray(a, sizeof(a) / sizeof(a[0]));
BubbleSort(a, sizeof(a) / sizeof(a[0]));
PrintArray(a, sizeof(a) / sizeof(a[0]));
}
Test.cpp
#include<iostream>
#include<assert.h>
using namespace std;
#include"Sort.h"
int main()
{
TestBubbleSort();
return 0;
}
快速排序是一种划分交换的方法,它采用分治法进行排序。其基本思想是取待排序元素序列中的某个元素作为基准值,按照这个元素的大小,将整个元素序列划分成两个左右两个子序列,使得左子序列的值都比这个元素小,右子序列中的值都比这个元素值要大于或等于,基准元素值则排在这两个序列中间,然后再对这两个子序列进行同样的方法,直到所有元素都排在相应的位置(即序列中只有一个元素或者没有元素的时候)。
快速排序方法一左右指针法
Sort.h
#pragma once
void PrintArray(int *a, size_t n)
{
for (size_t i = 0; i < n; ++i)
{
cout << a[i] << "";
}
cout << endl;//换行
}
//快速排序左右指针法
int PartSort1(int *a, int left, int right)
{
int key = a[right];
int begin = left;
int end = right;
while (begin < end)
{
while (begin < end && a[begin] <= key)
{
++begin;
}
while (begin < end && a[end] >= key)
{
--end;
}
if (begin < end)
swap(a[begin], a[end]);
}
swap(a[begin], a[right]);
return begin;
}
void QuickSort(int *a, int left, int right)
{
assert(a);
if (left < right)
{
int div = PartSort1(a, left, right);
QuickSort(a, left, div - 1);
QuickSort(a, div + 1, right);
}
}
void TestQuickSort()
{
int a[] = { 5,0,4,9,3,6,5,7,1,5};
PrintArray(a, sizeof(a) / sizeof(a[0]));
QuickSort(a,0, sizeof(a) / sizeof(a[0]) - 1);
PrintArray(a, sizeof(a) / sizeof(a[0]));
}
Test.cpp
#include<iostream>
#include<assert.h>
using namespace std;
#include"Sort.h"
int main()
{
TestQuickSort();
return 0;
}
换个测试用例试试:
快速排序方法二
挖坑法
Sort.h
#pragma once
void PrintArray(int *a, size_t n)
{
for (size_t i = 0; i < n; ++i)
{
cout << a[i] << "";
}
cout << endl;//换行
}
//快速排序之挖坑法
int PartSort2(int *a, int left, int right)
{
int key = a[right];
while (left < right)
{
//找大
while (left < right && a[left] <= key)
{
++left;
}
//找到比key大的数放到右边的坑里,左边形成新的坑
a[right] = a[left];
while (left < right && a[right] >= key)
{
--right;
}
a[left] = a[right];
}
a[left] = key;
return left;
}
void QuickSort(int *a, int left, int right)
{
assert(a);
if (left < right)
{
int div = PartSort2(a, left, right);
QuickSort(a, left, div - 1);
QuickSort(a, div + 1, right);
}
}
void TestQuickSort()
{
int a[] = { 5,0,4,9,3,6,5,7,1,5};
PrintArray(a, sizeof(a) / sizeof(a[0]));
QuickSort(a,0, sizeof(a) / sizeof(a[0]) - 1);
PrintArray(a, sizeof(a) / sizeof(a[0]));
}
Test.cpp
#include<iostream>
#include<assert.h>
using namespace std;
#include"Sort.h"
int main()
{
TestQuickSort();
return 0;
}
快速排序方法三
前后指针法
Sort.h
#pragma once
void PrintArray(int *a, size_t n)
{
for (size_t i = 0; i < n; ++i)
{
cout << a[i] << "";
}
cout << endl;//换行
}
//快速排序之前后指针法
int PartSort3(int *a, int left, int right)
{
int prev = left - 1;
int cur = left;
int key = a[right];
while (cur < right)
{
if (a[cur] < key && ++prev != cur)
{
swap(a[prev], a[cur]);
}
++cur;
}
swap(a[++prev], a[right]);
return prev;
}
void QuickSort(int *a, int left, int right)
{
assert(a);
if (left < right)
{
int div = PartSort3(a, left, right);
QuickSort(a, left, div - 1);
QuickSort(a, div + 1, right);
}
}
void TestQuickSort()
{
int a[] = { 5,0,4,9,3,6,5,7,1,5};
PrintArray(a, sizeof(a) / sizeof(a[0]));
QuickSort(a,0, sizeof(a) / sizeof(a[0]) - 1);
PrintArray(a, sizeof(a) / sizeof(a[0]));
}
Test.cpp
#include<iostream>
#include<assert.h>
using namespace std;
#include"Sort.h"
int main()
{
TestQuickSort();
return 0;
}
快排的最坏情况:有序 (解决:三数取中)
用第一种方法示例:
Sort.h
#pragma once
void PrintArray(int *a, size_t n)
{
for (size_t i = 0; i < n; ++i)
{
cout << a[i] << "";
}
cout << endl;//换行
}
int GetMidIndex(int*a, int left, int right)
{
int mid = left + (right - left) / 2;
//left mid right
if (a[left] < a[mid])
{
if (a[mid] < a[right])
{
return mid;
}
else if (a[left]>a[right])
{
return left;
}
else
{
return right;
}
}
else //left>min right
{
if (a[mid] > a[right])
return mid;
else
if (a[left] < a[right])
return left;
else
return right;
}
}
int PartSort1(int *a, int left, int right)
{
//三数取中
int mid = GetMidIndex(a, left, right);
swap(a[mid], a[right]);
int key = a[right];
int begin = left;
int end = right; //防止有序排成无序
while (begin < end)
{
while (begin < end && a[begin] <= key)
{
++begin;
}
while (begin < end && a[end] >= key)
{
--end;
}
if (begin < end)
swap(a[begin], a[end]);
}
swap(a[begin], a[right]);
return begin;
}
void QuickSort(int *a, int left, int right)
{
assert(a);
if (left < right)
{
int div = PartSort1(a, left, right);
QuickSort(a, left, div - 1);
QuickSort(a, div + 1, right);
}
}
void TestQuickSort()
{
int a[] = { 5,0,4,9,3,6,5,7,1,5};
PrintArray(a, sizeof(a) / sizeof(a[0]));
QuickSort(a,0, sizeof(a) / sizeof(a[0]) - 1);
PrintArray(a, sizeof(a) / sizeof(a[0]));
}
Test.cpp
#include<iostream>
#include<assert.h>
using namespace std;
#include"Sort.h"
int main()
{
TestQuickSort();
return 0;
}
快速排序非递归
//快速排序非递归
#include<stack>
void QuickSortNonR(int *a, int left, int right)
{
assert(a);
stack<int> s;
if (left < right)
{
s.push(right);
s.push(left);
}
while (!s.empty())
{
int begin = s.top();
s.pop();
int end = s.top();
s.pop();
int div = PartSort1(a, begin, end);
//begin div-1
//div+1 end
if (begin < div - 1)
{
s.push(div - 1);
s.push(begin);
}
if (div + 1 < end)
{
s.push(end);
s.push(div + 1);
}
}
}
归并排序
归并排序是一种基于分治法的一种排序方法。它将要排序的序列分成两个长度相等的子序列,为每一个子序列进行排序,然后再将子序列合并成一个有序的序列。
void _MergeSort(int *a,int begin,int end,int *tmp)
{
int mid = ((begin^end) >> 1) + (begin&end);
if (mid > begin)
_MergeSort(a,begin,mid,tmp);
if (mid + 1 < end)
_MergeSort(a,mid+1,end,tmp);
int begin1 = begin;
int end1 = mid;
int begin2 = mid + 1;
int end2 = end;
int index = begin;
while(begin1<=end1&&begin2<=end2) //先将归并时的元素放到辅助数组中,如果放到原数组的话有可能会覆盖掉其他元素产生错误
{
if (a[begin1] < a[begin2])
{
tmp[index++] = a[begin1++];
}
else
{
tmp[index++] = a[begin2++];
}
}
while(begin1 <= end1)
{
tmp[index++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[index++] = a[begin2++];
}
while (begin <= end) //将辅助数组中的元素再拷贝到原数组中
{
a[begin] = tmp[begin++];
}
}
void MergeSort(int *a,int begin,int end)
{
assert(a);
int *tmp = new int[end-begin+1];
_MergeSort(a,begin,end,tmp);
delete[] tmp;
}
计数排序主要思想:
给定一组要排序的序列,找出这组序列中的最大值,然后开辟一个最大值加1大小的数组,将这个数组里面的元素全部置零,然后用这个数组统计出要排序的序列中各个元素出现的次数。等到统计完成的时候,排序就已经完成了。基数排序的主要思想:
基数排序又称”桶子法”,他从低位开始将待排序的数按照这一位的值放到相应的编号为0到9的桶中。等到低位排完之后得到一个序列,再将这个序列按照次低位的大小进入相应的桶中。以此类推,直到将所有的位都排完之后,这组数就已经有序了。