笔者过两天就要去面试,但是连最简单的排序算法都其实还写的不是很清楚,昨天又听了一节左程云老师的公开课吧,原来快速排序的空间复杂度是lon(n)。虽然快速排序大大概实现逻辑心里是清楚的,但是对于边界控制,返回时机真是不甚了了,故而痛定思痛,准备把快速排序的主流的实现都记忆一下。
以下为笔者写的快速排序递归实现:
#include "stdio.h" #include "stdlib.h" void swap(int *a , int *b) { int tmp = *a; *a = *b; *b = tmp; } void quicksort(int array[], int start , int end, int len) { if(start<0||end>=len||start>end) { return 0; } int key = array[end]; int i = start; int j= end-1; while(i<=j)//if len of array equals 2, recycle needs; { while(array[i] < key) i++; while(array[j]>=key&&i<=j) j--; if(i<j) { swap(&array[i], &array[j]); i++,j--; } } if(i == end) return; swap(&array[i], &array[end]); if(i-start>1) quicksort(array, start, i-1, len); if(end - i>1) quicksort(array, i+1, end,len); } #define len(a) sizeof(a)/sizeof(int) int main() { int n; scanf("%d",&n); int *a=(int*)malloc(n*sizeof(int)); for(int i =0; i!=n; i++) scanf("%d", &a[i]); quicksort(a, 0, n-1, n); for(int index=0; index!=n; index++) printf("%d\n", a[index]); return 0; } 下面是非递归实现,我用链表先实现了一个队列来存储还有哪些快排区间需要排序,每次从队列头取出区间来计算, 然后在队列尾插入划分好的两个需要计算的区间,然后将队列头出队,知道队列为空,则停止计算.其中的partition的 思路和一般的快速排序的思路不太一样,参考了剑指OFFER中的实现,另外一般链表头作为参数一定要用指针的指 针,不然没法修改.
非递归实现很容易看出我的实现的额外空间复杂读为O(N/2),其实就相当与二叉树的叶子节点数,#include "stdio.h" #include "stdlib.h" void swap(int *a, int *b) { int tmp = *a; *a = *b; *b = tmp; } typedef struct listnode { int start; int end; struct listnode * next; }listnode; typedef listnode** plisthead; void push_back(plisthead list, listnode* nodeptr) { if(list==NULL) { perror("warning:list is null"); return; } if(*list == NULL) *list = nodeptr; else { listnode * ptail = *list; while(ptail->next != NULL) ptail = ptail->next; ptail->next = nodeptr; nodeptr->next = NULL; } } listnode* pop_front(plisthead list) { if(list == NULL||(*list)==NULL) return NULL; listnode *headnode = *list; (*list) = headnode->next; return headnode; } int partition(int array[], int start, int end, int len) { if(start<0||end>=len||start>=end) return; int key = array[end]; int small = start -1; for(int index=start; index<end; index++) //该实现很精巧 { if(array[index]<key) { small++; if(index!=small) swap(&array[index], &array[small]); } } ++small; //最后不要忘了++small swap(&array[small], &array[end]); return small; } void quicksort(int array[], int len) { listnode * plistnode = (listnode*)malloc(sizeof(listnode)); plistnode->start = 0; plistnode->end = len-1; plistnode->next = NULL; plisthead phead= &plistnode; //首先把链表头数据置为应该进行排序的数组的区间 while((*phead)!=NULL) { int partitionpos = partition(array, (*phead)->start, (*phead)->end, len); //进行划分,并得到划分点 int formerlen = partitionpos - (*phead)->start; int latterlen = (*phead)->end - partitionpos; if(formerlen > 1) { listnode * plistnode = (listnode*)malloc(sizeof(listnode)); plistnode->start = (*phead)->start; plistnode->end = partitionpos-1; plistnode->next = NULL; push_back(phead, plistnode); } if(latterlen > 1) { listnode * plistnode = (listnode*)malloc(sizeof(listnode)); plistnode->start = partitionpos+1; plistnode->end = (*phead)->end; plistnode->next = NULL; push_back(phead, plistnode); } listnode* pnode = pop_front(phead); if(pnode != NULL) free(pnode); } return; } int main() { int A[] = {4,3,3,5,2}; quicksort(A, 5); for(int index=0; index!=5; index++) printf("%d\n", A[index]); return 0; }
如果用栈结构的话应该能降低到O(logN),当然是在划分比较平均的情况下,一般情况可以通过pivot来选择关键字,增加排序效率.