排序方法了解一下(冒泡排序、选择排序、堆排序、插入排序、希尔排序、归并排序、快速排序、基数排序)

看个排序的算法居然看了一周,真是罪过,效率低得可怕。。。。。

排序方法有冒泡排序、选择排序、堆排序、插入排序、希尔排序、归并排序、快速排序、基数排序

其中写基数排序时候被自己蠢死了,在一个循环里,用i作为计数器,在循环里的另一个循环又用了一次,然后死活发现不了错误。下次还是不要重复用同一个i,每个循环单独声明一个变量

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "HEAP.h"

#define MAXDIGIT 4
#define RADIX 10

typedef int ElementType;

void swapElement(ElementType *a, ElementType *b);
void swapElement(ElementType *a, ElementType *b)
{
    ElementType tmp;
    tmp = *a;
    *a = *b;
    *b = tmp;
}

void printArray(ElementType a[], int len);
void printArray(ElementType a[], int len)
{
    int i;
    for(i=0; i<len; i++)
    {
        printf("%d ", a[i]);
    }
    printf("\n");
}

/**< 冒泡排序
eg: len == 4    {4 3 2 1}
一   1    {3 4 2 1}     经过第一轮i=0,就可以把最大的数移动最后
     2    {3 2 4 1}     即重的泡泡沉底,轻的泡泡全部上升一位
     3    {3 2 1 4}

二   1    {2 3 1 4}     所以第二个循环中,判断条件是(len-1-i)
     2    {2 1 3 4}     每经一次大循环后,最后一位是最大的数,
                        无需再比较了。
三   1    {1 2 3 4}

最优情况时间复杂度为O(N), 最差情况时间复杂度为O(N2)
 */
void bubbleSort(ElementType a[], int len);
void bubbleSort(ElementType a[], int len)
{
    int i, j;
    bool isSwap;    /**< 用来标记该小循环有没有进行过交换,如果没有,则证明数组已经有序 */
    for(i=0; i<len-1; i++)
    {
        isSwap = false;
        for(j=0 ; j<len-1-i; j++)
        {
            if(a[j] > a[j+1])
            {
                swapElement(&a[j], &a[j+1]);
                isSwap = true;
            }
        }
        if(!isSwap) /**< 如果没有进行过交换,数组已经有序,直接退出循环 */
            break;
    }
}


/** 选择排序
 *  每轮找出该轮最小的数,然后把它放到首位
 *  时间复杂度在任何情况下都不变,为O(N2)
 */
void selectSort(ElementType a[], int len);
void selectSort(ElementType a[], int len)
{
    int i, j, min;
    for(i=0; i<len-1; i++)
    {
        min = i;
        for(j=i+1; j<len; j++)
        {
            if(a[j]<a[min])
            {
                min = j;
            }
            swapElement(&a[i], &a[min]);
        }
    }
}

/** 堆排序
 *  void heapSort(ElementType a[], int len)是接口函数,保持和其他函数接口一致
 *  void perdown(ElementType a[], int tree, int size)是将size个元素的数组a以a[tree]为根的子堆调整为最大堆
 *  其实所谓下滤(perdown)跟最大堆的插入操作基本一样,下滤的原理是从最小的堆开始调整,一直到根,就可以形成最大堆
 *  又其实所谓的调整是,取当前子树的数值看成一个代插入的元素,和其最大的子树比较。
 *  需要注意的是做最大堆时,a[0]是作为哨兵存在的,不参与任何运算,但对数组排序时,a[0]是其中一个待排数据
 */
void perdown(ElementType a[], int tree, int size);
void perdown(ElementType a[], int tree, int size)
{
    int parent, child;
    ElementType x = a[tree];

    for(parent=tree; (parent*2+1)<size; parent=child )
    {
        child = parent*2+1;
        if((child<size-1)&&(a[child]>a[child+1]))
        {
            child++;
        }
        if(a[child]<x)
        {
            break;
        }
        else
        {
            a[parent]=a[child];
        }
        a[child] = x;
    }
}
void heapSort(ElementType a[], int len);
void heapSort(ElementType a[], int len)
{
    int i;

    for(i=len/2; i<len; i++)
    {
        perdown(a, i, len);
    }

    for(i=len-1; i>0; i--)
    {
        swapElement(&a[0], &a[i]);
        perdown(a, 0, i);
    }
}

/** \插入排序
 * 插入排序把数组分成两部分,已排序部分和未排序部分
 * 每次从未排序部分取出一个元素,和已排序部分比较,找出比该元素小的那个元素后一位,就是该元素的位置
 * 比该元素大的元素全部往后移一位
 */
void insertSort(ElementType a[], int len);
void insertSort(ElementType a[], int len)
{
    int i, j;

    for(i=1; i<len; i++)
    {
        ElementType tmp = a[i];
        for(j=i; j>0; j--)
        {
            if(tmp>a[j-1])
            {
                break;
            }
            else
            {
                a[j] = a[j-1];
            }
        }
        a[j] = tmp;
    }
}


/** 希尔排序
 *  插入排序的加强版
 *  插入排序因为一次只交换相邻的元素,即一次最多只消灭一对逆序对
 *  希尔排序以一定间隔交换元素,情况好时候,交换一次即可消灭多对逆序对
 *  但是这个间隔取值直接影响希尔排序的效率
 *  因此选用合适的增量序列很重要
 */
void shellSort(ElementType a[], int len);
void shellSort(ElementType a[], int len)
{
    int sIndex, gap, i, j;
    int sedgewick[] = {10000, 2537, 653, 173, 48, 15, 5, 2, 1};

    /**< 找出合适最大的sedgewick增量 */
    for(sIndex=0; sedgewick[sIndex]<=len; sIndex++)
    { }

    /**< 遍历所有gap */
    for(gap=sIndex; sedgewick[gap]>0; gap++)
    {
        for(i=gap; i<len; i++)
        {
            ElementType tmp = a[i];
            for(j=i; j>=gap; j-=gap)
            {
                if(a[j-gap]>tmp)
                {
                    a[j] = a[j-gap];
                }
                else
                {
                    break;
                }
            }
            a[j] = tmp;
        }
    }
}

/** 归并排序
 * void merge()是用来合并两个已经有序的子列,强调是已有序!
 * void msort()是用来将一个数组不断分割成两个子列,直到分割到最少单位,然后交由void merge()排序,然后递归
 * void mergeSort()是接口函数,统一函数入口,并提前声明tmpA数组;
 *
 *
 */
void merge(ElementType a[], ElementType tmpA[], int left, int right, int rightEnd );
void merge(ElementType a[], ElementType tmpA[], int left, int right, int rightEnd )
{
    int leftEnd = right - 1;

    int numElement = rightEnd - left + 1;

    int tmpIndex = left;

    int i;

    while( left<=leftEnd && right<=rightEnd )
    {
        if(a[left]>a[right])
        {
            tmpA[tmpIndex++] = a[right++];
        }
        else
        {
            tmpA[tmpIndex++] = a[left++];
        }
    }
    while(left<=leftEnd)
    {
        tmpA[tmpIndex++] = a[left++];
    }
    while(right<=rightEnd)
    {
        tmpA[tmpIndex++] = a[right++];
    }

    for(i=0; i<numElement; i++, rightEnd--)
    {
        a[rightEnd] = tmpA[rightEnd];
    }
}
void msort(ElementType a[], ElementType tmpA[], int left, int rightEnd);
void msort(ElementType a[], ElementType tmpA[], int left, int rightEnd)
{
    if(left<rightEnd)
    {
        int center = (rightEnd+left)/2;

        msort(a, tmpA, left, center);
        msort(a, tmpA, center+1, rightEnd);
        merge(a, tmpA, left, center+1, rightEnd);
    }
}
void mergeSort(ElementType a[], int len);
void mergeSort(ElementType a[], int len)
{
    ElementType *tmpA = (ElementType *)malloc(len*sizeof(ElementType));

    if(tmpA!=NULL)
    {
        msort(a, tmpA, 0, len-1);
        free(tmpA);
    }
    else
    {
        printf("Failed to create tmpA.\n");
    }
}

/** 快速排序
 * void quickSort1()是书本的写法,在待排元素数量少于一定数量时候转为插入排序。这里的主元是采用数组中间的数字的
 * void quickSort2()是网上一般写法的快排,主元用的是数组当一个字母
 *
 *
 *
 */
 ElementType findMedian(ElementType a[], int left, int right);
 ElementType findMedian(ElementType a[], int left, int right)
 {
     int center = (left+right)/2;

     if(a[left]>a[right])
     {
         swapElement(&a[left], &a[right]);
     }
     if(a[center]<a[left])
     {
         swapElement(&a[center], &a[left]);
     }
     if(a[center]>a[right])
     {
         swapElement(&a[center], &a[right]);
     }
     swapElement(&a[center], &a[right-1]);

     return a[right-1];
 }
 void quick(ElementType a[], int left, int right);
 void quick(ElementType a[], int left, int right)
 {
     int cutOff = 3;
     if(cutOff <= left-right)
     {
         int low = left;
         int high = right-1; /**< 因为经过findMedian函数,已经确定a[right]比主元大,所以直接用a[right-1]作为最右元 */

         ElementType tmp = findMedian(a, left, right);
         while(1)
         {
             while(a[++low]>tmp);
             while(a[--high]<tmp);
             if(low<high)
             {
                 swapElement(&a[low], &a[high]);
             }
             else
             {
                 break;
             }
         }
         swapElement(&a[low], &a[right-1]); /**< a[right-1]是主元,此时low左边的元素都是小于主元的,a[low]本身是大于主元的,此时交换刚好让主元处于中间(大小的中间,非位置的中间) */

         quick(a, left, low-1); /**< 主元a[low]不再参与排序*/
         quick(a, low+1, right);
     }
    else
    {
        insertSort(a+left, right-left+1);
    }
 }
 void quickSort1(ElementType a[], int len);
 void quickSort1(ElementType a[], int len)
 {
     quick(a, 0, len-1);
 }

 void quickSort2(ElementType a[], int len);
 void quickSort2(ElementType a[], int len)
 {
     quick2(a, 0, len-1);
 }
 void quick2(ElementType a[], int left, int right);
 void quick2(ElementType a[], int left, int right)
 {
     int l, r;
     l = left;
     r = right;
     ElementType tmp = a[l];
     if(l<r)
     {
         while(l<r && a[r]>tmp) r--;
         if(l<r)
         {
             a[l++] = a[r];
         }
         while(l<r && a[l]<tmp) l++;
         if(l<r)
         {
             a[r--] = a[l];
         }
         a[l] = tmp;
         quick2(a, left, l-1);
         quick2(a, l+1, right);
     }
 }

 /** 基数排序
  */
/**< 桶元素结点 */
typedef struct Node *PtrToNode;
typedef PtrToNode BNode;
struct Node
{
    ElementType num;
    BNode next;
}  ;
/**< 定义桶头结点 */
struct headNode
{
    BNode head, tail;
} ;
typedef struct headNode bucket[RADIX];
 /**< 计算x的第d位的数字的函数 */
int getDigit(ElementType x, int d);
int getDigit(ElementType x, int d)
 {
     int i, rlt;
     for(i=0; i<d; i++)
     {
         rlt = x%RADIX;
         x = x/RADIX;
     }
     return rlt;
 }
void LSDRadixSort(ElementType a[], int len);

void LSDRadixSort(ElementType a[], int len)
{
    int i, Dindex, dg;
    BNode list, tmp, p;
    bucket bkt;


    for(i=0; i<RADIX; i++)  /**< 将每个桶初始化为空 */
    {
        bkt[i].head = NULL;
        bkt[i].tail = NULL;
    }

    list = NULL;

    for(i=0; i<len; i++)  /**< 将数组逆序存入链表list */
    {
        tmp = (BNode)malloc(sizeof(struct Node));
        tmp->num = a[i];
        tmp->next = list;
        list = tmp;
    }

    for(dg=1; dg<=MAXDIGIT; dg++)
    {
        p = list;  /**< 将链表list复制给p作为临时变量来操作,以方便修改 */
        while(p)
        {
            Dindex = getDigit(p->num, dg);
            printf("Num: %d dg:%d Dindex:%d\n",p->num, dg, Dindex);
            /**< 将当前结点取出,p指向下一个结点 */
            tmp = p;
            p = p->next;

            /**< 将当前结点接到桶后面 */
            tmp->next = NULL;

            if(bkt[Dindex].head != NULL)
            {

                bkt[Dindex].tail->next = tmp;
                bkt[Dindex].tail = tmp;
            }
            else
            {
                bkt[Dindex].head = bkt[Dindex].tail = tmp;
            }

        }

        /**< 将上面排序好的结点收集起来 */
        list = NULL;
        for(i=RADIX-1; i>=0; i--)
        {
            if(bkt[i].head!=NULL)
            {
                bkt[i].tail->next = list; /**< 将新的桶插在list的头,因为随着i增加,后面的桶的数字是越来越小的。 */
                list = bkt[i].head;
                bkt[i].head = bkt[i].tail = NULL;
            }

        }
    }

    /**< 将list里面的内容复制回数组a[]并把list的空间释放 */
    for(i=0; i<len; i++)
    {
        tmp = list;
        list = list->next;
        a[i] = (tmp->num);
        free(tmp);
    }
}

int main()
{
    //testHeap();
    int ArraySize;
    scanf("%d", &ArraySize);
    ElementType a[ArraySize];
    int i;
    for(i=0; i<ArraySize; i++)
    {
        scanf("%d", &a[i]);
    }

//    bubbleSort(a, ArraySize);
//    printf("BubbleSort:");
//    printArray(a, ArraySize);

//    selectSort(a, ArraySize);
//    printf("SelectSort:");
//    printArray(a, ArraySize);

//    heapSort(a, ArraySize);
//    printf("HeapSort:");
//    printArray(a, ArraySize);

//    insertSort(a, ArraySize);
//    printf("InsertSort:");
//    printArray(a, ArraySize);

//    shellSort(a, ArraySize);
//    printf("ShellSort:");
//    printArray(a, ArraySize);

//    mergeSort(a, ArraySize);
//    printf("MergeSort:");
//    printArray(a, ArraySize);

//    quickSort(a, ArraySize);
//    printf("QuickSort:");
//    printArray(a, ArraySize);

//    quickSort2(a, ArraySize);
//    printf("QuickSort2:");
//    printArray(a, ArraySize);

    LSDRadixSort(a, ArraySize);
    printf("LSDRadixSort:");
    printArray(a, ArraySize);

    system("pause");
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值