目录
一、冒泡排序:
#include<stdio.h>
void swap(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
//冒泡排序
void BubbleSort(int* a, int n)
{
int end = n - 1;//不能是n,不然会越界
while(end)
{
int exchange = 0;//优化,比较之后没有交换,说明已经排好了,就break循环
for (int i = 0; i < end; i++)
{
if (a[i] < a[i + 1])
{
swap(&a[i], &a[i + 1]);
exchange++;
}
}
if (exchange == 0) break;
end--;
}
}
二、插入排序:
//插入排序
void InsertSort(int* a, int n)
{
for (int i = 1; i < n; i++)
{
if (a[i] < a[i - 1])//先判断,如果i下标的值大于前面的数,就不进入
{
int tmp = a[i];
int j;
for (j = i - 1; j >= 0 && a[j] >tmp; j--)
{
a[j+1] = a[j];
}
a[j+1] = tmp;
}
}
}
//两次循环就可以实现
//内部循环完成一趟的插入
//外层循环完成插入排序
三、选择排序:
//选择排序
void SelectSort(int* a, int n)
{
for (int i = 0; i < n-1; i++)//i<n-1当它是最后一个数的时候不需要进行交换排序
{
int min = i;
int j;
for (j = i; j < n; j++)
{
if (a[j] < a[min])
{
min=j;
}
}
swap(&a[i], &a[min]);//交换函数,前面的代码中有出现,我就不重复写了
}
}
四、希尔排序:
//希尔排序
/*步骤:
1.先选定一个小于N的整数gap作为第一增量,然后将所有距离为gap的元素分在同一组,并对每一组的元素进行直接插入排序。然后再gap--,重复上述操作。
2.当gap==1时就是直接插入排序,就相当于整个序列被分到一组,进行一次直接插入排序,排序完成。*/
void ShellSort(int* a, int n)
{
//这里相当于把插入排序的1换成gap
int gap = n;
while (gap>1)
{
gap = gap / 3 + 1;
for (int i = gap; i < n; i++)
{
if (a[i] < a[i - gap])
{
int tmp = a[i];
int j;
for (j = i - gap; j >= 0 && a[j] > tmp; j-=gap)//这里是j-=gap
{
a[j + gap] = a[j];
}
a[j + gap] = tmp;
}
}
}
}
五、堆排序:
//向下调整算法(要满足它下面的都满足堆,才能用)
void AdjustDown(int* a, int n, int root)
{
int parent = root;
int child = parent * 2 + 1;
while (child < n)
{
if (child + 1 < n && a[child] < a[child + 1]) child+=1;//把他移到右孩子那里
if (a[child] > a[parent])
{
swap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
else break;
}
}
堆排序
void HeapSort(int* arr, int n)
{
//建大堆
//从最后一个根开始,就相当于它下面的都满足堆,就可以用向下调整算法
for (int i = (n-1-1)/2; i >= 0; i--)//n-1-1是因为数组的最后一个元素下标是n-1
{
AdjustDown(arr, n, i);
}
//排序
for (int i = n; i > 1; i--)
{
swap(&arr[0],&arr[i - 1]);
AdjustDown(arr, i-1, 0);
}
}
六、快速排序:
//1.挖坑法的快速排序
void QuickSort(int* a,int left,int right)
{
if (left >= right)//不能写成pivot==left,pivot-1与left不匹配,会报错
{
return;
}
int begin = left,end = right;
int key = a[begin];//挖了一个关键字
int pivot = begin;//挖了一个坑
while (begin < end)
{
//右边找小,一定要先右边找小,放在pivot
while (begin < end&&a[end] >= key)//在这里也要判断begin < end,因为这里面end--
{
end--;
}
//小的放在左边的坑里,然后形成新的坑位
a[pivot] = a[end];
pivot = end;
//左边找大
while (begin < end && a[begin] <= key)
{
begin++;
}
a[pivot] = a[begin];
pivot = begin;
}
//begin==end
a[pivot] = key;
//[left,right]
//[left,pivot-1] pivot [pivot+1,right]
//如果左子区间和右子区间都有序,就全部有序。那就分治递归。
QuickSort(a, left, pivot - 1);
QuickSort(a, pivot+1, right);
}
void QuickSort(int* a, int left, int right)
{
if (left >= right)
{
return;
}
int begin = left, end = right;
int key = begin;//这里与挖坑法不同的地方,因为要交换key的那个数组中那个位置的数,而不是值
while (begin < end)
{
while (begin < end && a[end] >= a[key])
{
end--;
}
while (begin < end && a[begin] <= a[key])
{
begin++;
}
Swap(&a[begin], &a[end]);
}
Swap(&a[begin], &a[key]);
QuickSort(a, left, begin - 1);
QuickSort(a, begin + 1, right);
}
void QuickSort(int* a, int left,int right)
{
if (left >= right)
{
return;
}
int index=GetMidIndex(a,left, right);
swap(&a[left], &a[index]);
int key = left;
int prev = left;
int cur = left+1;
while (cur <= right)
{
if (a[cur] < a[key])
{
prev++;
swap(&a[cur], &a[prev]);
}
/*可以简写成cur++,
但是当时一定要注意不要放在if语句的前面,因为if语句里面有让cur与prev交换的,cur==right跳出循环,但是a[cur]超过数组的范围,会越界范围。
while (cur<=right&&a[cur] >= a[key])
{
cur++;
}*/
cur++;
}
swap(&a[prev], &a[key]);
QuickSort(a, left, prev - 1);
QuickSort(a, prev+1,right);
}
6.4优化快排
三数取中法:取左端、中间、右端三个数,然后进行比较,将中值数当做key
否则有序时时间复杂度为O(N^2)
三数取中法可以套入三种方法中,这里我就写一种
//三数取中
int GetMidIndex(int* a, int left, int right)
{
int mid = (left + right) / 2;
if (a[mid] >= a[left])
{
if (a[mid] <= a[right])
{
return mid;
}
else
{
if (a[right] >= a[left])
{
return right;
}
else
{
return left;
}
}
}
else//a[left]>a[mid]
{
if (a[right] >= a[left])
{
return left;
}
else
{
if (a[right] >= a[mid])
{
return right;
}
else
{
return mid;
}
}
}
}
//交换
void swap(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
//前后指针法
void QuickSort(int* a, int left,int right)
{
if (left >= right)
{
return;
}
int index=GetMidIndex(a,left, right);
swap(&a[left], &a[index]);
int key = left;
int prev = left;
int cur = left+1;
while (cur <= right)
{
if (a[cur] < a[key])
{
prev++;
swap(&a[cur], &a[prev]);
}
cur++;
}
swap(&a[prev], &a[key]);
QuickSort(a, left, prev - 1);
QuickSort(a, prev+1,right);
}
七、归并排序:
!!!需要开一个_MergeSort,而不是直接在MergeSort中直接递归,是因为MergeSort中有一个malloc
归并排序很像二叉树中的后序思想,先递归,递归到最后的时候再合并。!!!
//归并排序
void _MergeSort(int* a, int left, int right, int* tmp)//在这个函数中调用递归{
if (left >= right)
{
return;
}
int mid = (left + right) >> 1;
_MergeSort(a, left, mid, tmp);
_MergeSort(a, mid+1, right, tmp);
//合并
int begin1 = left, end1 = mid;
int begin2 = mid + 1, end2 = right;
int i = left;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] <= a[begin2])
{
tmp[i++] = a[begin1++];
}
else
{
tmp[i++] = a[begin2++];
}
}
while (begin1 <= end1)
{
tmp[i++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[i++] = a[begin2++];
}
for (int j = left; j <= right; j++)
{
a[j] = tmp[j];
}
}
void MergeSort(int* a, int n)
{
int* tmp = (int*)malloc(sizeof(int) * n);
_MergeSort(a, 0, n - 1, tmp);
free(tmp);
}
八、桶排序:
//桶排序
void bucket_sort(int a[],int size,int bucket_size) {
int i,j; //数组,数组长度,桶的大小
//定义动态的指针数组
KeyNode **bucket_num = (KeyNode **)malloc(bucket_size * sizeof(KeyNode*));
for(i = 0;i < bucket_size;i++)
{
bucket_num[i] = (KeyNode*)malloc(sizeof(KeyNode));//为每个链表定义头结点
bucket_num[i]->num = 0;
bucket_num[i]->next = NULL; //指针变量初始化为空
}
for(j = 0;j < size;j++) //准备插入
{
KeyNode *node = (KeyNode *)malloc(sizeof(KeyNode));//定义一个节点
node->num = a[j]; //数据域存数据
node->next = NULL; //指向空
int index = a[j]/100; //映射函数 计算桶号
KeyNode *p = bucket_num[index];//p指向链表的头
//链表结构的插入排序
while(p->next != NULL && p->next->num <= node->num)
{
p = p->next; //1.链表为空,p->next==NULL,进入不了循环
} //2.链表不为空,因为链表从无开始按顺序插入,数据为有序的,
//可以找到 前一个节点 <= node <=后一个节点
//节点插入链表
node->next = p->next;
p->next = node;
(bucket_num[index]->num)++; //记录一下该链表中有几个有效节点
}
//打印结果
KeyNode * k = NULL; //定义一个空的结构体指针用于储存输出结果
for(i = 0;i < bucket_size;i++)
{
//for(k = bucket_num[i]->next;k!=NULL;k=k->next)//通过最后一个指针指向空
k = bucket_num[i]->next;
for(int m=0;m<bucket_num[i]->num;m++) //通过头指针记录节点数
{
printf("%d ",k->num);
k=k->next;
}
printf("\n");
}
九、计数排序:
一种特殊的排序,唯一种没有比较的排序(指没有前后比较,还是有交换的)
以数组的下标当做数值,有这个数的时候a[i]++;
局限:适用于整数。数要求集中(否则空间的浪费大)
9.1绝对映射:
int * countingSort1(int arr[],int count,int max) {
int index = 0;
int *tmpArr = (int *)malloc(max*sizeof(int));
int *result = (int *)malloc(max*sizeof(int));
for(int k = 0;k<max;k++) {
tmpArr[k] = 0;
}
for (int i = 0; i<count; i++) {
tmpArr[arr[i]]++;
}
for (int j = 0; j<max; j++) {
while (tmpArr[j]) {
result[index++] = j;
tmpArr[j]--;
}
}
free(tmpArr);
tmpArr = NULL;
return result;
}
9.2现对映射:
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* count = (int*)malloc(sizeof(int) * range);
memset(count, 0, sizeof(int) * range);
for (int i = 0; i < n; i++)
{
count[a[i] - min]++;
}
int i = 0;
for (int j = 0; j < range; j++)
{
while (count[j]--)
{
a[i++] = j + min;
}
}
free(count);
}
十、基数排序:
#include<math.h>
testBS()
{
inta[] = {2, 343, 342, 1, 123, 43, 4343, 433, 687, 654, 3};
int *a_p = a;
//计算数组长度
intsize = sizeof(a) / sizeof(int);
//基数排序
bucketSort3(a_p, size);
//打印排序后结果
inti;
for(i = 0; i < size; i++)
{
printf("%d\n", a[i]);
}
intt;
scanf("%d", t);
}
//基数排序
voidbucketSort3(int *p, intn)
{
//获取数组中的最大数
intmaxNum = findMaxNum(p, n);
//获取最大数的位数,次数也是再分配的次数。
intloopTimes = getLoopTimes(maxNum);
inti;
//对每一位进行桶分配
for(i = 1; i <= loopTimes; i++)
{
sort2(p, n, i);
}
}
//获取数字的位数
intgetLoopTimes(intnum)
{
intcount = 1;
inttemp = num / 10;
while(temp != 0)
{
count++;
temp = temp / 10;
}
returncount;
}
//查询数组中的最大数
intfindMaxNum(int *p, intn)
{
inti;
intmax = 0;
for(i = 0; i < n; i++)
{
if(*(p + i) > max)
{
max = *(p + i);
}
}
returnmax;
}
//将数字分配到各自的桶中,然后按照桶的顺序输出排序结果
voidsort2(int *p, intn, intloop)
{
//建立一组桶此处的20是预设的根据实际数情况修改
intbuckets[10][20] = {};
//求桶的index的除数
//如798个位桶index=(798/1)%10=8
//十位桶index=(798/10)%10=9
//百位桶index=(798/100)%10=7
//tempNum为上式中的1、10、100
inttempNum = (int)pow(10, loop - 1);
inti, j;
for(i = 0; i < n; i++)
{
introw_index = (*(p + i) / tempNum) % 10;
for(j = 0; j < 20; j++)
{
if(buckets[row_index][j] == NULL)
{
buckets[row_index][j] = *(p + i);
break;
}
}
}
//将桶中的数,倒回到原有数组中
intk = 0;
for(i = 0; i < 10; i++)
{
for(j = 0; j < 20; j++)
{
if(buckets[i][j] != NULL)
{
*(p + k) = buckets[i][j];
buckets[i][j] = NULL;
k++;
}
}
}
}