您的位置:首页 > 编程语言 > C语言/C++

C语言几种常用排序

2017-08-04 09:12 363 查看
C语言几种常用排序
[pái xù]  


排序

 编辑

排序是计算机内经常进行的一种操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列。分内部排序外部排序。若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序。反之,若参加排序的记录数量很大,整个序列的排序过程不可能在内存中完成,则称此类排序问题为外部排序。内部排序的过程是一个逐步扩大记录的有序序列长度的过程。


概念描述

编辑

将杂乱无章的数据元素,通过一定的方法按关键字顺序排列的过程叫做排序。假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的。


常见排序算法

快速排序希尔排序堆排序直接选择排序不是稳定的排序算法,而基数排序冒泡排序直接插入排序、折半插入排序、归并排序是稳定的排序算法

排序算法大体可分为两种:

    一种是比较排序,时间复杂度O(nlogn) ~ O(n^2),主要有:冒泡排序,选择排序,插入排序,归并排序,堆排序,快速排序等。

    另一种是非比较排序,时间复杂度可以达到O(n),主要有:计数排序基数排序桶排序等。

  这里我们来探讨一下常用的比较排序算法,非比较排序算法将在后续文章中介绍。下表给出了常见比较排序算法的性能:

  


 

  有一点我们很容易忽略的是排序算法的稳定性(腾讯校招2016笔试题曾考过)。

  排序算法稳定性的简单形式化定义为:如果Ai = Aj,排序前Ai在Aj之前,排序后Ai还在Aj之前,则称这种排序算法是稳定的。通俗地讲就是保证排序前后两个相等的数的相对顺序不变。

  对于不稳定的排序算法,只要举出一个实例,即可说明它的不稳定性;而对于稳定的排序算法,必须对算法进行分析从而得到稳定的特性。需要注意的是,排序算法是否为稳定的是由具体算法决定的,不稳定的算法在某种条件下可以变为稳定的算法,而稳定的算法在某种条件下也可以变为不稳定的算法。

  例如,对于冒泡排序,原本是稳定的排序算法,如果将记录交换的条件改成A[i] >= A[i + 1],则两个相等的记录就会交换位置,从而变成不稳定的排序算法。

  其次,说一下排序算法稳定性的好处。排序算法如果是稳定的,那么从一个键上排序,然后再从另一个键上排序,第一个键排序的结果可以为第二个键排序所用。基数排序就是这样,先按低位排序,逐次按高位排序,低位排序后元素的顺序在高位也相同时是不会改变的。

 

冒泡排序

#include <stdio.h>

// 交换函数

void swap (int a[], int i, int j)

{
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;

}

// 打印数组

void printA (int *a, int len)

{
int i;
for (i = 0; i < len; i++)
{
printf ("%4d", a[i]);
}

printf ("\n");

}

// 冒泡排序

int main1()

{
int a[10] = {9,6,8,0,3,5,2,4,7,1};
int len = sizeof(a) / sizeof(a[0]);

int i,j;
// 外层循环控制轮数,每一轮找出一个最大的树沉底
for (i = 0; i < len -1; i++)
{
// 内层循环控制每一轮比较的次数
for (j = 0; j < len-1-i; j++)
{
if (a[j] > a[j+1])
{
swap (a, j, j+1);
}
}
}

printA (a, len);

return 0;

}

// 鸡尾酒排序

int main()

{
int a[10] = {9,6,8,0,3,5,2,4,7,1};
int len = sizeof(a) / sizeof(a[0]);

int i;
int left  = 0;
int right = len - 1;

while (left < right)
{
// 从左往右找到一个最大的数放到right的位置
for (i = left; i < right; i++)
{
if (a[i] > a[i+1])
{
swap (a, i, i+1);
}
}
right--;     

// 从右往左找到一个最小的数放到left的位置
for (i = right; i > left; i--)
{
if (a[i-1] > a[i])
{
swap (a, i, i-1);
}
}
left++;
}

printA (a, len);

return 0;

}

选择排序

#include <stdio.h>

// 交换函数

void swap (int a[], int i, int j)

{
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;

}

// 打印数组

void printA (int *a, int len)

{
int i;
for (i = 0; i < len; i++)
{
printf ("%4d", a[i]);
}

printf ("\n");

}

// 冒泡排序

int main()

{
int a[10] = {9,6,8,0,3,5,2,4,7,1};
int len = sizeof(a) / sizeof(a[0]);

int i,j;
int min;
// 外层循环控制轮数,每一轮找到一个最小的数
for (i = 0; i < len-1; i++)
{
min = i;    
// 内层循环找每一轮最小数的下标
for (j = i+1; j < len; j++)
{
if (a[min] > a[j])
{
min = j;    // 保存当前最小元素的下标
}
}

// 如果当前顶端元素不是最小的值,将最小的值和顶端元素进行交换
if (min != i)
{
swap (a, i, min);
}
}

printA (a, len);

return 0;

}

插入排序

#include <stdio.h>

// 交换函数

void swap (int a[], int i, int j)

{
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;

}

// 打印数组

void printA (int *a, int len)

{
int i;
for (i = 0; i < len; i++)
{
printf ("%4d", a[i]);
}

printf ("\n");

}

// 冒泡排序

int main()

{
int a[10] = {9,6,8,0,3,5,2,4,7,1};
int len = sizeof(a) / sizeof(a[0]);

int get;   // 抓牌
int i,j;
for (i = 1; i < len; i++)
{
get = a[i];         // 抓牌
j = i - 1;

// 找到第一个比抓到的牌小的元素,并且进行移位
while (j >= 0 && a[j] > get)
{
a[j+1] = a[j];     // 如果元素比新抓到的元素大,往后移一个位置
j--;
}
a[j+1] = get;          // 将新元素插入第一个比它小的元素的后面
}

printA (a, len);

return 0;

}

插入排序改进二分排序

#include <stdio.h>

// 交换函数

void swap (int a[], int i, int j)

{
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;

}

// 打印数组

void printA (int *a, int len)

{
int i;
for (i = 0; i < len; i++)
{
printf ("%4d", a[i]);
}

printf ("\n");

}

// 二分插入排序

int main()

{
int a[10] = {9,6,8,0,3,5,2,4,7,1};
int len = sizeof(a) / sizeof(a[0]);

int left, right,mid,i,j,get;

for (i = 1; i < len; i++)
{
get = a[i];          // 抓牌
left = 0;            // 确定左边界
right = i - 1;       // 确定右边界

// 找插入位置:查找完后要插入的位置在下标为left的位置
while (left <= right)
{
mid = (left + right)/2;
if (a[mid] > get)     // 要插入的位置在mid的左边
{
right = mid - 1;  // 重新设定右边界
}
else                  // 要插入的位置在mid的右边
{
left = mid + 1;   // 重新设定左边界
}
}

// 移位操作:将left开始右边的所有元素都右移一位
for (j = i-1; j >= left; j--)
{
a[j+1] = a[j];
}

a[left] = get;     // 插入新元素

}

printA (a, len);

return 0;

}

希尔排序

#include <stdio.h>

// 交换函数

void swap (int a[], int i, int j)

{
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;

}

// 打印数组

void printA (int *a, int len)

{
int i;
for (i = 0; i < len; i++)
{
printf ("%4d", a[i]);
}

printf ("\n");

}

// 希尔排序

int main1()

{
int a[10] = {9,6,8,0,3,5,2,4,7,1};
int len = sizeof(a) / sizeof(a[0]);

int i,j,get;
int d = len;    // d代表每一次的步长

do
{
d = d / 3 + 1;
for (i = d; i < len; i++)
{
get = a[i];
j = i - d;

while (j >= 0 && a[j] > get)
{
a[j+d] = a[j];
j -= d;
}
a[j+d] = get;
}
}while (d > 1);

printA (a, len);

return 0;

}

int main()

{
int a[10] = {9,6,8,0,3,5,2,4,7,1};
int len = sizeof(a) / sizeof(a[0]);

int i,j,get;
int d = 0;    // d代表每一次的步长

while (d < len)
{
d = d * 3 + 1;  // 0 1 4 13
}

while (d >= 1)
{

for (i = d; i < len; i++)
{
get = a[i];
j = i - d;

while (j >= 0 && a[j] > get)
{
a[j+d] = a[j];
j -= d;
}
a[j+d] = get;
}
d = (d-1) / 3;   // 4 1 0
}
printA (a, len);

return 0;

}

#include <stdio.h>

// 交换函数

void swap (int a[], int i, int j)

{
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;

}

// 打印数组

void printA (int *a, int len)

{
int i;
for (i = 0; i < len; i++)
{
printf ("%4d", a[i]);
}

printf ("\n");

}

// a 代表一个数组

// i 代表要调整的结点的下标

// len  数组的长度

void heapify(int *a, int i, int len)

{
int left = 2 * i + 1;     // 左孩子结点下标
int right = 2 * i + 2;    // 右孩子结点下标
int max = i;     // 三个节点中最大元素的下标

if (left < len && a[left] > a[max])
max = left;
if (right < len && a[right] > a[max])
max = right;

if (max != i)   // 当前父节点不是所有结点中最大的元素,需要做调整
{
swap (a, i, max);
heapify (a, max, len);   // 调整被交换的结点
}

}

void heapSort (int *a, int len)

{
// 建堆
int i;
for (i = len/2 - 1; i >= 0; i--)
{
heapify (a, i, len);
}

// 排序
for (i = len-1; i > 0; i--)
{
swap (a, 0, i);       // 拿堆顶元素与队尾元素进行交换
len--;                // 找到一个最大元素以后堆大小减1
heapify (a, 0, len);  // 调整堆顶元素
}

}

int main()

{
int a[10] = {9,6,8,0,3,5,2,4,7,1};
int len = sizeof(a) / sizeof(a[0]);

heapSort(a, len);

printA (a, len);

return 0;

}

归并排序

#include <stdio.h>

// 交换函数

void swap (int a[], int i, int j)

{
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;

}

// 打印数组

void printA (int *a, int len)

{
int i;
for (i = 0; i < len; i++)
{
printf ("%4d", a[i]);
}

printf ("\n");

}

// a 是数组  tmp  是缓冲区

void merge(int *a, int left, int mid, int right, int *tmp)

{
int i = left;
int j = mid + 1;
int k = 0;

while (i <= mid && j <= right)
{
if (a[i] > a[j])
tmp[k++] = a[j++];
else
tmp[k++] = a[i++];
}

while (i <= mid)
tmp[k++] = a[i++];

while (j <= right)
tmp[k++] = a[j++];

k = 0;
for (i = left; i <= right; i++)
{
a[i] = tmp[k++];
}

}

void mergeSort(int *a, int left, int right, int *tmp)

{
if (left >= right)
return;

int mid = (left + right)/2;
mergeSort (a, left, mid, tmp);    // 对左边部分进行归并排序
mergeSort (a, mid+1, right, tmp); // 对右边部分进行归并排序
merge (a, left, mid, right, tmp); // 将将部分数据进行归并

}

int main()

{
int a[10] = {9,6,8,0,3,1,2,4,7,5};
int len = sizeof(a) / sizeof(a[0]);
int tmp[10];
mergeSort (a, 0, len-1, tmp);
printA (a, len);

return 0;

}

快速排序

#include <stdio.h>

// 交换函数

void swap (int a[], int i, int j)

{
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;

}

// 打印数组

void printA (int *a, int len)

{
int i;
for (i = 0; i < len; i++)
{
printf ("%4d", a[i]);
}

printf ("\n");

}

// 分区操作,返回基准值的下标

int partition(int *a, int left, int right)

{
int pivot = a[right];
int index = left;   // 如果找到一个比基准值小的元素,与下标为index的元素交换
int i;
for (i = left; i < right; i++)
{
if (a[i] < pivot)
{
swap (a, i, index);
index++;
}
}
swap (a, index, right);

return index;   // 基准值所在位置下标

}

void qSort(int *a, int left, int right)

{
if (left < right)
{
int pivot = partition(a, left, right);  // 进行分区操作,找基准值下标
qSort (a, left, pivot-1);     // 对左边部分进行快速排序
qSort (a, pivot+1, right);    // 对右边部分进行快速排序

}

}

int main()

{
int a[10] = {9,6,8,0,3,1,2,4,7,5};
int len = sizeof(a) / sizeof(a[0]);

qSort (a, 0, len-1);

printA (a, len);

return 0;

}
http://sorting.at/#    动画演示

常用排序:
http://www.cnblogs.com/eniac12/p/5329396.html#s12
常见面试排序:
http://blog.csdn.net/pi9nc/article/details/12220851
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息