看个排序的算法居然看了一周,真是罪过,效率低得可怕。。。。。
排序方法有冒泡排序、选择排序、堆排序、插入排序、希尔排序、归并排序、快速排序、基数排序
其中写基数排序时候被自己蠢死了,在一个循环里,用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");
}