一、插入类排序:
1.直接插入排序
#include
void print(int a[], int n)
{
for (int i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
printf("\n");
}
void insertSort(int a[], int n)
{
int i, j;
for ( i = 1; i < n; i++)
{
int key = a[i];
//注意有等号则算法就不稳定了
for ( j = i - 1; j >= 0 && a[j] > key; j--)
{
a[j + 1] = a[j];
}
a[j + 1] = key;
}
}
int main()
{
printf("插入排序:\n");
int a[] = { 2,4,6,8,10,1,3,5,7,9 };
print(a, sizeof(a) / sizeof(a[0]));
insertSort(a, 10);
print(a, sizeof(a) / sizeof(a[0]));
return 0;
}
2.希尔排序
//方式一
#include
void print(int a[], int n)
{
for (int i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
printf("\n");
}
void shellSort(int a[], int n)
{
int gap = 3;
int i, j;
while (gap--)
{
for ( i = gap; i < n; i++)
{
int key = a[i];
for ( j = i - gap; j >= 0 && a[j] > key; j-=gap)
{
a[j + gap] = a[j];
}
a[j + gap] = key;
}
}
}
int main()
{
int a[] = { 2,4,6,8,10,1,3,5,7,9 };
printf("希尔排序:\n");
print(a, sizeof(a) / sizeof(a[0]));
shellSort(a, 10);
print(a, sizeof(a) / sizeof(a[0]));
return 0;
}
//方式二(注意gap差别)
#include
void print(int a[], int n)
{
for (int i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
printf("\n");
}
void shellSort(int a[], int n)
{
int gap = n;
while (gap>1)
{
gap = gap / 3 + 1;
int i, j;
//int i, j;
//这里i++而不是i+gap原因是比较下一组(隔相同步数的为一组)
for ( i = gap; i < n; i++)
{
int key = a[i];
for (j = i - gap; j >= 0 && key < a[j]; j-=gap)
{
a[j + gap] = a[j];
}
a[j + gap] = key;
}
//gap--;
}
}
int main()
{
int a[] = { 1,3,5,7,9,2,4,6,8,10 };
printf("希尔排序:\n");
print(a, sizeof(a) / sizeof(a[0]));
shellSort(a, sizeof(a) / sizeof(a[0]));
print(a, sizeof(a) / sizeof(a[0]));
return 0;
}
二、选择类排序
1.简单选择排序
//方式一--先排最大的,即将最大的排在后面
#include
void print(int a[], int n)
{
for (int i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
printf("\n");
}
void selectSort(int a[], int n)
{
int i, j;
for ( i = 0; i < n - 1; i++)
{
//max为当前最大值下标,从下标为0到下标为max-1中找最大的,不断更新max
int max = n-1-i;
for (j = 0; j < n - 1 - i; j++)
{
if (a[j] > a[max])
{
max = j;
}
}
if (max != j)
{
int temp = a[j];
a[j] = a[max];
a[max] = temp;
}
}
}
//或用以下写法
/*
void selectSort(int array[], int size)
{
for (int i = 0; i < size - 1; ++i)
{
// 找最大元素的位置
int maxPos = 0;
for (int j = 1; j < size - i; j++)
{
if (array[j] > array[maxPos])
maxPos = j;
}
if (maxPos != size - i - 1)
swap(&array[maxPos], &array[size - i - 1]);
}
}
*/
int main()
{
int a[] = { 1,3,5,7,9,2,4,6,8,10 };
printf("选择排序:\n");
print(a, sizeof(a) / sizeof(a[0]));
selectSort(a, sizeof(a) / sizeof(a[0]));
print(a, sizeof(a) / sizeof(a[0]));
return 0;
}
//方式二--先排最小的,即将最小的放在前面
#include
void print(int a[], int n)
{
for (int i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
printf("\n");
}
void selectSort(int a[], int n)
{
for (int i = 0; i < n - 1; i++)
{
int min = i;
for (int j = i + 1; j < n; j++)
{
if (a[j] < a[min])
{
int temp = a[j];
a[j] = a[min];
a[min] = temp;
}
}
}
}
int main()
{
int a[] = { 1,3,5,7,9,2,4,6,8,10 };
printf("选择排序:\n");
print(a, sizeof(a) / sizeof(a[0]));
selectSort(a, sizeof(a) / sizeof(a[0]));
print(a, sizeof(a) / sizeof(a[0]));
return 0;
}
//也可以不用每趟交换多次,找到后面最小的和前面元素交换一次就好,如下:
#include
using namespace std;
void selectSort(int r[], int n){
int i,index,j,temp;
for(i=1; i r[j])//记录序列中最小值的位置
{
index = j;
}
}
if(index != i)//如果无序序列中第一个记录不是最小值,则进行交换
{
temp = r[index];
r[index] = r[i];
r[i] = temp;
}
}
}
int main()
{
int r[] = {0,5,6,8,4,9,6,74,65,123,94};
int n = sizeof(r)/sizeof(r[0]);
selectSort(r, n);
for(int i=1; i
#include
void swap(int* a, int* b)
{
int t = *a;
*a = *b;
*b = t;
}
void PrintArray(int array[], int size)
{
for (int i = 0; i < size; ++i)
{
printf("%d ", array[i]);
}
printf("\n");
}
void SelectSort(int* a, int n)
{
assert(a);
int begin = 0, end = n - 1;
while (begin < end)
{
int min = begin, max = begin;
for (int i = begin; i <= end; i++)
{
if (a[i] >= a[max])
max = i;
if (a[i] < a[min])
min = i;
}
//最小的放在
swap(&a[begin], &a[min]);
//如果最大的位置在begin位置
//说明min是和最大的交换位置
//这个时候max的位置就发生了变换
//max变到了min的位置
//所以要更新max的位置
if (begin == max)
max = min;
swap(&a[end], &a[max]);
++begin;
--end;
//PrintArray(a, n);
}
}
int main()
{
int a[] = { 3, 4, 6, 1, 2, 8, 0, 5, 7 };
SelectSort(a, sizeof(a) / sizeof(int));
PrintArray(a, sizeof(a) / sizeof(int));
return 0;
}
2.堆排序
#include
void print(int a[], int n)
{
for (int i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
printf("\n");
}
//n表示父节点,size表示总节点个数
void adjustDown(int a[], int size, int n)
{
//n相当于parent
int child = n * 2 + 1;
while (child < size)
{
//若要排降序,只要该为a[child+1] a[child])
{
child = child + 1;
}
if (a[child] > a[n])
{
int temp = a[child];
a[child] = a[n];
a[n] = temp;
n = child;
child = child * 2 + 1;
}
else
{
return;
}
}
}
void heapSort(int a[], int n)
{
//建堆
for (int i = (n - 2) / 2; i >= 0; i--)
{
adjustDown(a, n, i);
}
//利用堆删除思想排序
int end = n - 1;
while (end)
{
int temp = a[0];
a[0] = a[end];
a[end] = temp;
//heapSort(a, end);
//上一次end的下标刚好是下一次要排的元素个数
adjustDown(a, end, 0);
end--;
}
}
int main()
{
int a[] = { 1,3,5,7,9,2,4,6,8,10 };
printf("堆排序:\n");
print(a, sizeof(a) / sizeof(a[0]));
heapSort(a, sizeof(a) / sizeof(a[0]));
print(a, sizeof(a) / sizeof(a[0]));
return 0;
}
三、交换类排序
1.冒泡排序
#include
void print(int a[], int n)
{
for (int i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
printf("\n");
}
void bubbleSort(int a[], int n)
{
for (int i = 0; i < n - 1; i++)
{
int flag = 1;
for (int j = 0; j < n - 1 - i; j++)
{
if (a[j + 1] < a[j])
{
int temp = a[j + 1];
a[j + 1] = a[j];
a[j] = temp;
flag = 0;
}
}
if (flag == 1)
{
break;
}
}
}
int main()
{
int a[] = { 2,4,6,8,10,1,3,5,7,9 };
printf("冒泡排序:\n");
print(a, sizeof(a) / sizeof(a[0]));
bubbleSort(a, sizeof(a) / sizeof(a[0]));
print(a, sizeof(a) / sizeof(a[0]));
return 0;
}
2.快速排序
//有三种方式取基准值,分别是PartSort1、PartSort2、PartSort3
#include
#include
#include
#include
typedef int DataType;
// 动态
typedef struct Stack
{
DataType* array;
int capacity;
int top; // 标记栈顶---实际就是顺序表中的有效元素的个数
}Stack;
void StackInit(Stack* ps,int n)
{
assert(ps);
ps->array = (DataType*)malloc(sizeof(DataType) * n);
if (NULL == ps->array)
assert(0);
ps->capacity = n;
ps->top = 0;
}
void StackCheckCapacity(Stack* ps)
{
assert(ps);
if (ps->top == ps->capacity)
{
int newCapacity = (ps->capacity << 1);
// 1. 开辟新空间
DataType* temp = (DataType*)malloc(sizeof(DataType) * newCapacity);
if (NULL == temp)
assert(0);
// 2. 拷贝元素
memcpy(temp, ps->array, sizeof(DataType) * ps->capacity);
// 3. 释放旧空间,使用新空间
free(ps->array);
ps->array = temp;
ps->capacity = newCapacity;
}
}
// 入栈---尾插
void StackPush(Stack* ps, DataType data)
{
StackCheckCapacity(ps);
ps->array[ps->top] = data;
ps->top++;
}
// 检测栈是否为空,如果为空返回真,否则返回假
int StackEmpty(Stack* ps)
{
assert(ps);
return 0 == ps->top;
}
// 出栈
void StackPop(Stack* ps)
{
if (StackEmpty(ps))
return;
ps->top--;
}
// 获取栈顶元素
DataType StackTop(Stack* ps)
{
assert(ps);
// return ps->array[--ps->top]; // 错误写法
return ps->array[ps->top - 1]; // 正确的
}
void PrintArray(int array[], int size)
{
for (int i = 0; i < size; ++i)
{
printf("%d ", array[i]);
}
printf("\n");
}
void swap(int* a, int* b)
{
int t = *a;
*a = *b;
*b = t;
}
// 三数取中法,三个中取一个中间值
int GetMidIndex(int* a, int begin, int end)
{
int mid = begin + ((end - begin) >> 1);
if (a[begin] < a[mid])
{
if (a[mid] < a[end])
{
return mid;
}
else if (a[begin] > a[end])
{
return begin;
}
else
{
return end;
}
}
else // begin >= mid
{
if (a[mid] > a[end])
{
return mid;
}
else if (a[begin] < a[end])
{
return begin;
}
else
{
return end;
}
}
}
int PartSort1(int* a, int begin, int end)
{
int midindex = GetMidIndex(a, begin, end);
swap(&a[begin], &a[midindex]);
int key = a[begin];
int start = begin;
/*
这里要从右边走,如果从左边走,
可能最后一步,如果找不到大于
基准值的,会导致begin == end
即相遇,但是右边还没有走,所以
这里的值一定大于基准值,最后交换
就会出问题,所以一定要从右边走,
即使最后一次找不到小于基准值的,
会和左边相遇,而左边此时还没走,
一定比基准值小,最后交换肯定没有问题
*/
while (begin < end)
{
// end 找小
while (begin < end && a[end] >= key)
--end;
// begin找大
while (begin < end && a[begin] <= key)
++begin;
swap(&a[begin], &a[end]);
}
//最后的交换一定要保证a[begin] < a[start], 所以要从右边走
swap(&a[begin], &a[start]);
return begin;
}
int PartSort2(int* a, int begin, int end)
{
//begin是坑
int key = a[begin];
while (begin < end)
{
while (begin < end && a[end] >= key)
--end;
// end给begin这个坑,end就变成了新的坑。
a[begin] = a[end];
while (begin < end && a[begin] <= key)
++begin;
// end给begin这个坑,begin就变成了新的坑。
a[end] = a[begin];
}
a[begin] = key;
return begin;
}
/*
前后指针法
*/
int PartSort3(int* a, int begin, int end)
{
int midindex = GetMidIndex(a, begin, end);
swap(&a[begin], &a[midindex]);
int key = a[begin];
int prev = begin;
int cur = begin + 1;
while (cur <= end)
{
// cur找小,把小的往前翻,大的往后翻
if (a[cur] < key && ++prev != cur)
swap(&a[cur], &a[prev]);
++cur;
}
swap(&a[begin], &a[prev]);
return prev;
}
void insertSort(int a[], int n)
{
int j;
for (int i = 1; i < n; i++)
{
int temp = a[i];
for (j = i - 1; a[j] > temp && j >= 0; j--)
{
a[j + 1] = a[j];
}
a[j + 1] = temp;
}
}
void QuickSort(int* a, int left, int right)
{
if (left >= right)
return;
if (right - left + 1 < 10)
{
insertSort(a + left, right - left + 1);
}
else
{
int div = PartSort1(a, left, right);
//[left, div-1]
//[div+1, right]
QuickSort(a, left, div - 1);
QuickSort(a, div + 1, right);
}
}
//用栈模拟递归,用队列也可以实现
void QuickSortNor(int array[], int size)
{
Stack s;
StackInit(&s,10);
int left = 0;
int right = size;
StackPush(&s, right);
StackPush(&s, left);
while (!StackEmpty(&s))
{
left = StackTop(&s);
StackPop(&s);
right = StackTop(&s);
StackPop(&s);
if (right - left <= 16)
insertSort(array + left, right - left);
else
{
int div = PartSort2(array, left, right);
// 基准值的左侧:[left, div)
// 基准值的右侧:[div+1, right);
StackPush(&s, right);
StackPush(&s, div + 1);
StackPush(&s, div);
StackPush(&s, left);
}
}
}
/*
void QuickSortR(int* a, int left, int right)
{
Stack st;
StackInit(&st, 10);
//先入大区间
if (left < right)
{
StackPush(&st, right);
StackPush(&st, left);
}
//栈不为空,说明还有没处理的区间
while (StackEmpty(&st) != 0)
{
left = StackTop(&st);
StackPop(&st);
right = StackTop(&st);
StackPop(&st);
//快排单趟排序
int div = PartSort1(a, left, right);
// [left div-1]
// 把大于1个数的区间继续入栈
if (left < div - 1)
{
StackPush(&st, div - 1);
StackPush(&st, left);
}
// [div+1, right]
if (div + 1 < right)
{
StackPush(&st, right);
StackPush(&st, div + 1);
}
}
}
*/
int main()
{
int a[] = { 3, 4, 6, 1, 2, 8, 0, 5, 7 };
printf("快速排序:\n");
PrintArray(a, sizeof(a) / sizeof(int));
//QuickSort(a, 0, sizeof(a) / sizeof(int) - 1);
QuickSortNor(a, sizeof(a) / sizeof(int) );
PrintArray(a, sizeof(a) / sizeof(int));
return 0;
}
或:
#include
#include
using namespace std;
void quickSort(int nums[], int l, int r) {
if (l + 1 >= r) return;
int begin = l, end = r - 1, key = nums[begin];
while (begin < end)
{
//右指针 从右向左扫描 将⼩于piv的放到左边
while (begin < end && nums[end] >= key)
end--;
nums[begin] = nums[end];
//左指针 从左向右扫描 将⼤于piv的放到右边
while (begin < end && nums[begin] <= key)
begin++;
nums[end] = nums[begin];
}
nums[begin] = key;//更新piv
quickSort(nums, l, begin);//递归排序 //以L为中间值,分左右两部分递归调⽤
quickSort(nums, begin + 1, r);
}
int main()
{
int m[] = { 2,4,6,8,10,1,3,5,7,9 };
int n = sizeof(m) / sizeof(m[0]);
for (int i = 0; i < n; i++)
{
cout << m[i] << " ";
}
cout << endl;
quickSort(m, 0, 10);
for (int i = 0; i < n; i++)
{
cout << m[i] << " ";
}
}
四、归并排序:
//有递归和非递归两种方式,已测试
#include
#include
#include
#include
void PrintArray(int array[], int size)
{
for (int i = 0; i < size; ++i)
{
printf("%d ", array[i]);
}
printf("\n");
}
void _MergeSort(int* a, int left, int right, int* tmp)
{
if (left >= right)
return;
int mid = left + ((right - left) >> 1);
// [left, mid]
// [mid+1, right]
_MergeSort(a, left, mid, tmp);
_MergeSort(a, mid + 1, right, tmp);
int begin1 = left, end1 = mid;
int begin2 = mid + 1, end2 = right;
int index = left;
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++];
}
memcpy(a + left, tmp + left, sizeof(int) * (right - left + 1));
}
//封装一下,让用户好调用
void MergeSort(int* a, int n)
{
assert(a);
int* tmp = (int*)malloc(sizeof(int) * n);
_MergeSort(a, 0, n - 1, tmp);
free(tmp);
}
/*
非递归排序与递归排序相反,将一个元素与相邻元素构成有序数组,
再与旁边数组构成有序数组,直至整个数组有序。
要有mid指针传入,因为不足一组数据时,重新计算mid划分会有问题
需要指定mid的位置
*/
void merge(int* a, int left, int mid, int right, int* tmp)
{
// [left, mid]
// [mid+1, right]
int begin1 = left, end1 = mid;
int begin2 = mid + 1, end2 = right;
int index = left;
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++];
}
memcpy(a + left, tmp + left, sizeof(int) * (right - left + 1));
}
/*
k用来表示每次k个元素归并
*/
void mergePass(int* arr, int k, int n, int* temp)
{
int i = 0;
//从前往后,将2个长度为k的子序列合并为1个
while (i < n - 2 * k + 1)
{
merge(arr, i, i + k - 1, i + 2 * k - 1, temp);
i += 2 * k;
}
//合并区间[i, n - 1]有序的左半部分[i, i + k - 1]以及不及一个步长的右半部分[i + k, n - 1]
if (i < n - k)
{
merge(arr, i, i + k - 1, n - 1, temp);
}
}
// 归并排序非递归版
void MergeSortNonR(int* arr, int length)
{
int k = 1;
int* temp = (int*)malloc(sizeof(int) * length);
while (k < length)
{
mergePass(arr, k, length, temp);
k *= 2;
}
free(temp);
}
int main()
{
int a[10] = { 4,1,3,2,7,6,5,9,10,8 };
printf("归并排序:\n");
PrintArray(a, 10);
MergeSort(a, 10);
PrintArray(a, 10);
//printf("归并排序--非递归:\n");
//MergeSortNonR(a, 10);
//PrintArray(a, 10);
return 0;
}
或:
#include
#include
using namespace std;
void mergeCount(int a[], int L, int mid, int R) {
//int* tmp = new int[L + mid + R];
int* t = (int*)malloc((R + 1) * sizeof(int));
int begin1 = L;
int end1 = mid;
int begin2 = mid + 1;
int end2 = R;
int k = 0;
while (begin1 <= end1 && begin2 <= end2) {
if (a[begin1] < a[begin2])
t[k++] = a[begin1++];
else
t[k++] = a[begin2++];
}
///判断哪个⼦数组中有剩余的数据
while (begin1 <= end1)
t[k++] = a[begin1++];
while (begin2 <= end2)
t[k++] = a[begin2++];
/// 将 tmp 中的数组拷⻉回 A[p...r]
for (int i = 0; i < k; ++i)
a[L + i] = t[i];
//delete tmp;
free (t);
}
void mergeSort(int a[], int L, int R) {
///递归终⽌条件 分治递归
/// 将 A[L...m] 和 A[m+1...R] 合并为 A[L...R]
if (L >= R) { return; }
int mid = L + (R - L) / 2;
mergeSort(a, L, mid);
mergeSort(a, mid + 1, R);
mergeCount(a, L, mid, R);
}
int main() {
int a[] = { 1,34,66,2,5,95,4,46,2,33 };
int nums = sizeof(a) / sizeof(int);
cout << "数组元素个数:" << sizeof(a) / sizeof(int) << endl;//10
for (int i = 0; i < nums; ++i) {
std::cout << a[i] << " "; // print => 1 2 4 5 27 34 46 66 95
}
//传递数组下标
mergeSort(a, 0, nums-1);
cout << endl;
for (int i = 0; i < nums; ++i) {
std::cout << a[i] << " "; // print => 1 2 4 5 27 34 46 66 95
}
std::cout << endl;
return 0;
}
五、计数排序:
#include
#include
#include
#include
void PrintArray(int array[], int size)
{
for (int i = 0; i < size; ++i)
{
printf("%d ", array[i]);
}
printf("\n");
}
void CountSort(int* a, int n)
{
int max = a[0], min = a[0];
for (int i = 0; i < n; ++i)
{
if (a[i] > max)
max = a[i];
if (a[i] < min)
min = a[i];
}
//找到数据的范围
int range = max - min + 1;
int* countArray = (int*)malloc(range * sizeof(int));
memset(countArray, 0, sizeof(int) * range);
//存放在相对位置,可以节省空间
for (int i = 0; i < n; ++i)
{
countArray[a[i] - min]++;
}
//可能存在重复的数据,有几个存几个
int index = 0;
for (int i = 0; i < range; ++i)
{
while (countArray[i]--)
{
a[index++] = i + min;
}
}
}
//该方式好理解
void CountSort2(int array[], int size)
{
// 0. 获取数据的范围
int minValue = array[0];
int maxValue = array[0];
for (int i = 1; i < size; ++i)
{
if (array[i] > maxValue)
maxValue = array[i];
if (array[i] < minValue)
minValue = array[i];
}
// 数据范围在[minValue, maxValue] 假设数据在1000-1009,其实只需要10个空间就可以
int range = maxValue - minValue + 1;
int* count = (int*)calloc(range, sizeof(int));
if (NULL == count)
{
assert(0);
return;
}
// 1. 先统计每个元素出现的次数
for (int i = 0; i < size; ++i)
{
count[array[i] - minValue]++;
}
// 2. 排序--按照计数数组的下标对数据进行回收
int index = 0;
for (int i = 0; i < 10; ++i)
{
// 回收
while (count[i] > 0)
{
array[index++] = i + minValue;//展开
count[i]--;
}
}
free(count);
}
int main()
{
int a[10] = { 4,1,3,2,7,6,5,9,10,8 };
printf("计数排序:\n");
PrintArray(a, 10);
CountSort2(a, 10);
PrintArray(a, 10);
return 0;
}