笔者过两天就要去面试,但是连最简单的排序算法都其实还写的不是很清楚,昨天又听了一节左程云老师的公开课吧,原来快速排序的空间复杂度是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中的实现,另外一般链表头作为参数一定要用指针的指
针,不然没法修改.
#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(N/2),其实就相当与二叉树的叶子节点数,
如果用栈结构的话应该能降低到O(logN),当然是在划分比较平均的情况下,一般情况可以通过pivot来选择关键字,增加排序效率.