一. 冒泡排序(BubbleSort)
基本思想:两个数比较大小,较大的数下沉,较小的数冒起来。
过程:
比较相邻的两个数据,如果第二个数小,就交换位置。
从后向前两两比较,一直到比较最前两个数据。最终最小数被交换到起始的位置,这样第一个最小数的位置就排好了。
继续重复上述过程,依次将第2.3…n-1个最小数排好位置。
public static void BubbleSort(int [] arr){
int temp;//临时变量
for(int i=0; i<arr.length-1; i++){ //表示趟数,一共arr.length-1次。
for(int j=arr.length-1; j>i; j--){
if(arr[j] < arr[j-1]){
temp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = temp;
}
}
}
}
二. 选择排序(SelctionSort)
基本思想:
在长度为N的无序数组中,第一次遍历n-1个数,找到最小的数值与第一个元素交换;
第二次遍历n-2个数,找到最小的数值与第二个元素交换;
。。。
第n-1次遍历,找到最小的数值与第n-1个元素交换,排序完成。
public static void select_sort(int array[],int lenth){
for(int i=0;i<lenth-1;i++){
int minIndex = i;
for(int j=i+1;j<lenth;j++){
if(array[j]<array[minIndex]){
minIndex = j;
}
}
if(minIndex != i){
int temp = array[i];
array[i] = array[minIndex];
array[minIndex] = temp;
}
}
}
三. 插入排序(Insertion Sort)
基本思想:
在要排序的一组数中,假定前n-1个数已经排好序,现在将第n个数插到前面的有序数列中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。
for(i=1;i<n;i++){
/**
* temp为本次循环待插入有序列表中的数
*/
int temp = a[i];
/**
* 寻找temp插入有序列表的正确位置
*/
for(j=i-1;j>=0 && a[j]>temp;j--){
/**
* 元素后移,为插入temp做准备
*/
a[j+1] = a[j];
}
/**
* 插入temp
*/
a[j+1] = temp;
print(a,n,i);
}
四. 希尔排序(Shell Sort)
在要排序的一组数中,根据某一增量分为若干子序列,并对子序列分别进行插入排序。
然后逐渐将增量减小,并重复上述过程。直至增量为1,此时数据序列基本有序,最后进行插入排序。
public static void shell_sort(int array[],int lenth){
int temp = 0;
int incre = lenth;
while(true){
incre = incre/2;
for(int k = 0;k<incre;k++){ //根据增量分为若干子序列
for(int i=k+incre;i<lenth;i+=incre){
for(int j=i;j>k;j-=incre){
if(array[j]<array[j-incre]){
temp = array[j-incre];
array[j-incre] = array[j];
array[j] = temp;
}else{
break;
}
}
}
}
if(incre == 1){
break;
}
}
}
五. 快速排序(Quicksort)
快速排序有三种实现方式
实现方式一:左右指针法
算法思想:在待排序序列中选择一个数据作为基准值(暂且将区间右端数据作为基准值),定义两个指针left,right开始分别指向待排序区间的两端,左指针向右找比基准值大的数据,找到后停下来,接着右指针向左开始找比基准值小的数据,找到后停下来,交换左右指针所指数据,直到两指针相遇,出循环后将左指针指向的值与基准值进行交换,交换成功后比基准值小的数据都在其左边,比基准值大的数据都在基准值的右边,换言之基准值已经处于合适的位置。接着递归对基准值的左区间和右区间进行排序,区间只有一个数据默认已经有序。
先从数列中取出一个数作为key值;
将比这个数小的数全部放在它的左边,大于或等于它的数全部放在它的右边;
对左右两个小数列重复第二步,直至各区间只有1个数。
//左右指针法
int PartSort1(int* a, int left, int right)//左右指针法
{
int mid = GetMidIndex(a, left, right);
QSwap(&a[mid], &a[right]);
int key = a[right];//用区间的最右边的值作为基准值
int keyidx = right;
while (left <right)
{
while (left < right && a[left] <= key)
++left;
while (left < right && a[right] >= key)
--right;
if (a[left] != a[right])
QSwap(&a[left], &a[right]);
}
QSwap(&a[left], &a[keyidx]);
return left;
}
//递归实现
void QuickSort1(int* a, int left,int right)//递归实现
{
assert(a);
if (left < right)
{
int div = PartSort1(a, left, right);
QuickSort1(a, left, div-1);//递归左区间
QuickSort1(a, div+1, right);//递归右区间
}
}
实现方式二:挖坑法
算法思想:在待排序序列中选择一个数据作为基准值(暂且将区间右端数据作为基准值),首次将坑设在基准值处,定义两个指针left,right开始分别指向待排序区间的两端,左指针向右找比基准值大的数据,找到后将该值填入坑中并且将坑的位置更新在左指针所指位置,接着右指针向左开始找比基准值小的数据,找到后将该值填入坑中并且将坑的位置更新在右指针所指位置,直到两指针相遇,出循环后比基准值小的数据都在其左边,比基准值大的数据都在基准值的右边,换言之基准值已经处于合适的位置。接着递归对基准值的左区间和右区间进行排序,区间只有一个数据默认已经有序。
public static void quickSort(int a[],int l,int r){
if(l>=r)
return;
int i = l; int j = r; int key = a[l];//选择第一个数为key
while(i<j){
while(i<j && a[j]>=key)//从右向左找第一个小于key的值
j--;
if(i<j){
a[i] = a[j];
i++;
}
while(i<j && a[i]<key)//从左向右找第一个大于key的值
i++;
if(i<j){
a[j] = a[i];
j--;
}
}
//i == j
a[i] = key;
quickSort(a, l, i-1);//递归调用
quickSort(a, i+1, r);//递归调用
}
算法实现3:前后指针法
算法思想:在待排序序列中选择一个数据作为基准值(暂且将区间右端数据作为基准值),定义两个指针prev和cur,cur首次指向待排序区间的第一个元素,prev指向cur的前一个位置,只要cur没走到区间末尾,就在中间找比基准值小的数据,每找到一次将prev++,然后如果二者所指元素不同就将其所指元素交换,直到cur走到区间的最右端退出循环,之后将prev++,将cur和prev所指的数据进行交换。至此基准值被排序到正确位置,赌鬼其左右区间即可完成整个排序。
六. 归并排序(Merge Sort)
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用。
首先考虑下如何将2个有序数列合并。这个非常简单,只要从比较2个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。
//将有序数组a[]和b[]合并到c[]中
void MemeryArray(int a[], int n, int b[], int m, int c[])
{
int i, j, k;
i = j = k = 0;
while (i < n && j < m)
{
if (a[i] < b[j])
c[k++] = a[i++];
else
c[k++] = b[j++];
}
while (i < n)
c[k++] = a[i++];
while (j < m)
c[k++] = b[j++];
}
七. 堆排序(HeapSort)
比较当前父节点是否大于子节点,如果大于就交换,直到一趟建堆完成~
/**
* 建堆
*
* @param arrays 看作是完全二叉树
* @param currentRootNode 当前父节点位置
* @param size 节点总数
*/
public static void heapify(int[] arrays, int currentRootNode, int size) {
if (currentRootNode < size) {
//左子树和右字数的位置
int left = 2 * currentRootNode + 1;
int right = 2 * currentRootNode + 2;
//把当前父节点位置看成是最大的
int max = currentRootNode;
if (left < size) {
//如果比当前根元素要大,记录它的位置
if (arrays[max] < arrays[left]) {
max = left;
}
}
if (right < size) {
//如果比当前根元素要大,记录它的位置
if (arrays[max] < arrays[right]) {
max = right;
}
}
//如果最大的不是根元素位置,那么就交换
if (max != currentRootNode) {
int temp = arrays[max];
arrays[max] = arrays[currentRootNode];
arrays[currentRootNode] = temp;
//继续比较,直到完成一次建堆
heapify(arrays, max, size);
}
}
}