void InsertSort(int numbers[],int length)
{
int p; //保存当前的位置
int tempValue; //保存当前变量
for (int i = 1;i < length ;i++)
{
tempValue = numbers[i]; //从第二个元素开始
p = i - 1; //标记上一个元素的位置
while (p >= 0 && tempValue < numbers[p]) {
//与上一个数比较,如果上一个数>当前要比较的数,将上一个数后移
numbers[p + 1] = numbers[p];
p --; //再与上一个数的上一个数进行比较
}
numbers[p+1] = tempValue; //如果上一个数<当前要比较的数,则将当前数插入到相应的位置
}
}
主函数的实现
/*
随机生成一组数,测试使用,当然可以自己手动构建一组数进行测试
*/
#include
#include
#include
void initARandom(int nums[],int length)
{
srand((unsigned)time(NULL));
for (int i = 0; i < length; ++i) {
nums[i] = rand()%60;
}
}
/*
打印数组中的值,方便测试
*/
void print_array(int A[],int length,char *print_string){
printf("%s\n", print_string);
for (int i = 0; i < length ; ++i){
printf("%d\t",A[i]);
}
printf("\n");
}
int main(int argc, char const *argv[])
{
int length = 9;
int numbers[length];
initARandom(numbers, length);
print_array(numbers, length, "before sort:");
InsertSort(numbers, length);
print_array(numbers,length,"after sort:");
return 0;
}
输出结果:
before sort:
38 15 54 18 35 31 51 34 46
after sort:
15 18 31 34 35 38 46 51 54
Program ended with exit code: 0
O(n)
O(n^2)
O(n^2)
O(1)
/*
查找最大值,返回index
*/
int findMax(int arr[],int length)
{
int max = arr[0];
int index = 0;
for (int i = 0; i < length; i++) {
if (max < arr[i])
{
max = arr[i];
index = i;
}
}
return index;
}
void selection_sort(int arr[],int length)
{
int maxPos;
while (length > 1)
{
maxPos = findMax(arr, length);
int temp = arr[length - 1];
arr[length - 1] = arr[maxPos];
arr[maxPos] = temp;
length--;
}
}
主函数中的实现
int main(int argc, char const *argv[])
{
int length = 9;
int numbers[length];
initARandom(numbers, length);
print_array(numbers, length, "before sort:");
selection_sort(numbers, length);
print_array(numbers,length,"after sort:");
return 0;
}
测试结果
before sort:
25 16 10 52 51 21 7 59 49
after sort:
7 10 16 21 25 49 51 52 59
Program ended with exit code: 0
O(n^2)
O(n^2)
O(n^2)
O(1)
算法分析
主要分两段:
第一段是合并算法
第二段是分治思想递归分解每一段,对每一小段进行排序
第一段合并算法:假设我们已经有了一个分为两段排好序的数组(例如:[6, 7, 8, 9,0,1,2,3,4])
i
,j
k
,i指针指向第一段[6,7,8,9]中的第一个首元素,j指向第二段[0,1,2,3,4]中的0,k指针指向要输出的数组首地址,[6,7,8,9,0,1,2,3,4]中的6第二段:产生有序的两段数组,为步骤1,步骤2做准备
/*
leftStart:表示数组开始点
rightEnd:表示数组结束点
m:表示要将数组分割的分割点
*/
void merge(int array[],int leftStart,int m,int rightEnd)
{
int LEFT_SIZE = m - leftStart; //计算左边数组的长度
int RIGHT_SIZE = rightEnd - m + 1; //计算右边数组的长度
int leftArray[LEFT_SIZE]; //初始化分段左边的数组
int rightArray[RIGHT_SIZE];//初始化分段右边的数组
//1.将传入的数组中前leftSize个元素分别输出的leftArray数组中
for (int i = leftStart ; i < m; i++)
{
leftArray[i - leftStart] = array[i];
}
//2.将m - rightEnd之间的数据输出到rightArray数组中
for (int i = m; i <= rightEnd; i++)
{
rightArray[i - m] = array[i];
}
int i = 0,j = 0,k = leftStart;
//将两个数组内容合并,假如leftArray 或者 rightArray中某一个数组已经达到了它的长度,那么跳出循环
while (i < LEFT_SIZE && j < RIGHT_SIZE)
{
if (leftArray[i] < rightArray[j])
{
array[k] = leftArray[i];
i++;
k++;
}else
{
array[k] = rightArray[j];
j++;
k++;
}
}
//如果是rightArray达到了它的长度,则将leftArray剩余的数据输出到输出的数组
while (i < LEFT_SIZE)
{
array[k] = leftArray[i];
k++;
i++;
}
//如果是leftArray达到了它的长度,则将rightArray剩余的数据输出到输出的数组
while (j < RIGHT_SIZE)
{
array[k] = rightArray[j];
k++;
j++;
}
}
分段算法:
//分治法思想,切分乱序数组
void mergeSort(int array[],int leftStart,int rightEnd)
{
if (leftStart == rightEnd) return; else {
int m = (leftStart + rightEnd) / 2;//找出中心位置
mergeSort(array, leftStart, m);//切分左边数组
mergeSort(array, m + 1, rightEnd);//切分右边数组
merge(array, leftStart, m + 1, rightEnd);//合并左右两边的数组
}
}
主函数中的实现:
int main(int argc, char const *argv[])
{
int length = 9;
int numbers[length];
initARandom(numbers, length);
print_array(numbers, length, "before sort:");
mergeSort(numbers, 0, length - 1);
print_array(numbers,length,"after sort:");
return 0;
}
实现结果:
before sort:
14 49 50 50 11 13 59 51 56
after sort:
11 13 14 49 50 50 51 56 59
Program ended with exit code: 0
算法分析:
首先要了解一下二叉树的概念:
(i- 1)/2 向下取整
2i + 1
,右孩子结点为2i+2
n - 1
,n为结点个数过程:
/*
交换数组中两个元素之间的顺序
*/
void swap(int arr[],int i, int j)
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
/*
除该节点外,子结点均为堆时,可以直接调用此方法,此方法是堆排序的最小化单元
*/
void heapify(int tree[],int n,int i)
{
if (i >= n) //递归出口
{
return;
}
int left = 2 * i + 1; //第i个结点的左结点
int right = 2 * i + 2; //第i个结点的右结点
int max = i;
if (left < n && (tree[max] < tree[left]))
{
//当左结点不是叶子结点的时候(因为叶子结点没有子结点了)
max = left;
}
if (right < n && (tree[max] < tree[right]))
{
max = right;
}
//以上两个判断是找最大值,如果最大值不是当前结点,交换使得当前结点最大
if (max != i)
{
swap(tree, max, i);
//递归当前结点,当前结点达到跳出递归的条件,也就是到了叶子结点,跳出递归
heapify(tree, n, max);
}
}
以上heapify
算法是除了当前传入的结点,子结点已经是堆了,才会调用该方法,那么如果是一个乱序的数组,则需要首先创建大根堆
void build_heap(int tree[],int n)
{
int last_node = n - 1;//找到最后一个叶子结点,自下而上的将所有父亲结点都变为大根堆
int parent = (last_node - 1) / 2;//找到父亲结点
for (int i = parent; i >= 0; i--)
{
heapify(tree, n, i);将每一个结点都变为大根堆
}
}
排序实现算法
void heap_short(int tree[],int n)
{
build_heap(tree,n); //首先要创建一个大根堆
int last_node = n - 1; //找到最后一个叶子结点
for (int i = last_node;i >= 0; i--)
{
swap(tree, i, 0);//交换根节点与叶子结点,交换后,根节点再是大根堆结点,但是除了最后一个结点,其他结点的子结点均为大根堆结点,所以需要对根节点重新做一次heapify
heapify(tree, i, 0);
}
}
主函数中的实现:
int main(int argc, char const *argv[])
{
int length = 9;
int numbers[length];
initARandom(numbers, length);
print_array(numbers, length, "before sort:");
heap_short(numbers, length);
print_array(numbers,length,"after sort:");
return 0;
}
before sort:
10 47 40 30 51 37 13 25 23
after sort:
10 13 23 25 30 37 40 47 51
Program ended with exit code: 0
算法分析:
算法实现:
//首先要获取数组的最大值
int getMax(int nums[],int length)
{
int max = nums[0];
for (int i = 1; i < length; i++) {
if (nums[i] > max)
{
max = nums[i];
}
}
return max;
}
//计数方法
void counting(int numbers[],int bArray[],int k,int length)
{
//找出最大值,确认在计数排序数组中的位置
int cArray[k + 1];
for (int i = 0; i < k + 1; i++)
{
cArray[i] = 0;
}
//计数排序核心,记录每个数据出现的次数,在cArray中对应的位置做+1操作
for (int i = 0; i < length; i++) {
cArray[numbers[i]] += 1;
}
//将cArray中每一项与前一项做加法,得到i(这里的i其实是原数组中的元素) 元素在即将要输出数组中的位置
for (int i = 1 ;i < k + 1; i++)
{
cArray[i] += cArray[i - 1];
}
//输出到B数组
for (int i = 0; i < length ; i++)
{
//输出一次,那么久相应的要在c数组中对应的位置减一
cArray[numbers[i]] --;
bArray[cArray[numbers[i]]] = numbers[i];
}
numbers
}
//排序的实现
void counting_sort(int array[],int bArray[],int length)
{
int max = getMax(array, length);
counting(array, bArray, max, length);
}
在主函数中的实现:
int main(int argc, char const *argv[])
{
int length = 9;
int numbers[length];
initARandom(numbers, length);
print_array(numbers, length, "before sort:");
int bArray[length];
counting_sort(numbers,bArray, length);
print_array(bArray,length,"after sort:");
return 0;
before sort:
6 21 14 32 2 21 33 34 25
after sort:
2 6 14 21 21 25 32 33 34
Program ended with exit code: 0
//返回枢值(中心值,也就是left与right指针重合的地方)
int partition(int array[],int left,int right)
{
int key = array[left];// 将第1个作为关键字
while (left < right) {
// 两端交替向中间扫描
// 移动最右边的指针,找到比pivotKey值小的值
while (left < right && array[right] >= key) --right;
array[left] = array[right];// 将比关键字小的移动到左边
// 移动左指针,找到比pivotKey大的值
while (left < right && array[left] <= key) ++left;
array[right] = array[left];// 将比关键字大的移动到右边
}
array[left] = key;// 此时left就是一趟快速排序后的关键字所在的位置
return left;
}
//排序算法
void quickShort(int array[],int left,int right)
{
if (left < right)
{
int mid = partition(array,left,right);
quickShort(array, left, mid - 1); //递归对左子数组排序
quickShort(array, mid + 1, right);//递归对右子数组排序
}
}
主函数中的实现
int main(int argc, char const *argv[])
{
int length = 9;
int numbers[length];
initARandom(numbers, length);
print_array(numbers, length, "before sort:");
quickShort(numbers, 0, length - 1);
print_array(numbers,length,"after sort:");
return 0;
}
int main(int argc, char const *argv[])
{
int length = 9;
int numbers[length];
initARandom(numbers, length);
print_array(numbers, length, "before sort:");
quickShort(numbers, 0, length - 1);
print_array(numbers,length,"after sort:");
return 0;
}