快速排序(递归与非递归)c语言实现

1、算法设计原理分析

快速排序是对冒泡排序的一种改进,快速排序的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据比另一部分的所有数据要小,再按这种方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,使整个数据变成有序序列。

基本步骤为:1)先从数列中取出一个数作为基准数;2)分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。3)再对左右区间重复第二步,直到各区间只有一个数。

非递归实现方法,需要把递归实现中函数调用部分换为迭代中调用函数,这里就可以用队列,或者栈来保存每次递归中的开始位置和结束位置,从而,可以在每次快排结束后,从队列,或者栈中跳出一组开始、结束位置下标,再进行快排,直到队列或者栈为空时停止。我采用了栈来保存开始、结束的位置,每次都先进行左边的快排,所以在对位置进栈操作时,先把右边的开始、结束标记位置推入栈,再把左边的推入栈

2、程序设计

递归实现:

#include<stdio.h>

#include<stdlib.h>

void QuickSort_GetKey(double *p,int len);

void QuickSort_Recursion(double *p,int len);

int main()

{

       int i;

       double arr[]={-34,4,0,6000.354,5.43,-343.23};

       int n=sizeof(arr)/sizeof(double);

       printf("排序前的数组为:\n");

       for(i=0;i<n;i++)

              printf("%lf ",arr[i]);

       QuickSort_Recursion(arr,n);

       printf("\n快速排序后的数组为:\n");

       for(i=0;i<n;i++)

              printf("%lf ",arr[i]);

       return 0;

}



void QuickSort_Recursion(double *p,int len) //定义递归方式的快速排序算法函数

{

       int i=0,j=len-1;

       QuickSort_GetKey(p,len-1);

       if(len<=1)

              return;

       double key=p[j];        //选取一个关键字(key)作为枢轴

       while(i<j)

       {

              while(i<j&&p[i]<key)

              {

                     i++;

              }

              p[j]=p[i];

              while(i<j&&p[j]>key)

              {

                     j--;

              }

              p[i]=p[j];

       }

       p[i]=key;

       QuickSort_Recursion(p,j); //对前一子数组进行快速排序

       QuickSort_Recursion(p+j+1,len-j-1); //对后一子数组进行快速排序

}



void QuickSort_GetKey(double *p,int len)  //定义找枢纽的函数,取前中末三数的中位数作为枢纽放末尾

{

       int tem;

       if(p[0]>p[len/2])

       {

              tem=p[0];

              p[0]=p[len/2];

              p[len/2]=tem;

       }

       if(p[0]>p[len])

       {

              tem=p[0];

              p[0]=p[len];

              p[len]=tem;

       }

       if(p[len/2]<p[len])

       {

              tem=p[len/2];

              p[len/2]=p[len];

              p[len]=tem;

       }    

 }

非递归方式实现:

#include<stdio.h>

#include<stdlib.h>

void quickSort(int *arr, int size);

int QuickSort_Getposition(int *arr, int begin, int end);



typedef struct Stack   //定义结构体栈

{ 

       int *data;

       int size;  

}stack;



void  InitStack(stack *s)   //初始化栈

{

       int *data = (int*)malloc(20 * sizeof(int)); //申请开辟一个长度为20的数组空间

       if (data == NULL)     //若申请不到,则报错退出

       {

              return;

       }

       s->data = data;

       s->size = 0;

}

void PushStack(stack *s,int d)   //入栈函数

{

       if (s->size > 20) //若栈满了就返回

       {

              return;

       }

       else

              s->data[s->size++] = d;

}

void PopStack(stack *s) //出栈函数

{

       if (s->size == 0)   //若栈里没有数据就返回

       {

              return;

       }

       else

              s->size--;

}



int TopStack(stack *s) //显示栈尾的内容

{

       return s->data[s->size-1];

             

}



int EmptyStack(stack *s)  //判断栈是否为空的函数

{

       return(s->size==0);

}



void Print(int *arr, int size)  //打印函数

{

       int i = 0;

       for (i = 0; i < size; i++)

       {

              printf("%d ", arr[i]);

       }

       printf("\n");

}



int MiddleNumber(int *arr, int begin, int end)

{

       int mid = begin + ((end - begin) /2);

       if (arr[begin] > arr[mid])

       {

              if (arr[begin] > arr[end])

              {

                     if (arr[mid] > arr[end])

                     {

                            return mid;

                     }

                     else

                            return end;

              }

              else

                     return begin;

       }

       else

       {

              if (arr[mid] > arr[end])

              {

                     if (arr[begin] > arr[end])

                     {

                            return begin;

                     }

                     else

                     {

                            return end;

                     }

              }

              else

                     return mid;

       }

}



int main()

{

       int arr[] = {0,5,3,2,9,8,7,6,4,1};

       printf("排序前: ");   //打印

       Print(arr,sizeof(arr)/sizeof(int));

       quickSort(arr,sizeof(arr)/sizeof(int));

       printf("排序后: ");

       Print(arr, sizeof(arr)/sizeof(int));

       return 0;

}



void quickSort(int *arr, int size)  //定义快速排序非递归实现函数

{

       stack s;  //用于存储起点和终点标记的栈

       int position;

       int left = 0;

       int right = 0;

       InitStack(&s);

       PushStack(&s, 0);

       PushStack(&s, size);

       while (!EmptyStack(&s))

       {

              right = TopStack(&s);

              PopStack(&s);

              left=TopStack(&s);

              PopStack(&s);

              position = QuickSort_Getposition(arr, left, right-1);

              //先快排基准左侧,则先将后侧的下标入栈

              if ((right-left)>position+1)

              {

                     PushStack(&s,position+1);

                     PushStack(&s,right-left);

              }

              if (position>0)

              {

                     PushStack(&s,0);

                     PushStack(&s,position);

              }

       }

}





int QuickSort_Getposition(int *arr, int begin, int end)  //定义找基准值的函数(挖坑法)

{

       int index = MiddleNumber(arr, begin, end);

       if (index != end)

       {

              int tem=arr[index];

              arr[index]=arr[end];

              arr[end]=tem;

       }

       //第一个坑

       int key = arr[end];

       int k = end;

       while (begin != end)

       {

              /*begin从左边开始找比关键字大的元素将其入坑

              ,begin所在位置变为坑*/

              while (arr[begin] <= key&&begin < end)

              {

                     begin++;

              }

              if (begin != end)

              {

                     arr[end] = arr[begin];

                     end--;

              }

              /*end从右开始找比关键字小的元素将其入begin坑*/

              while (arr[end] >= key&&begin < end)

              {

                     end--;

              }

              if (begin != end)

              {

                     arr[begin] = arr[end];

                     begin++;

              }

       }

       if (begin != k)

       {

              arr[begin] = key;

       }

       return begin;

}

3、运行结果

 

4、算法分析(复杂度)

    快速排序的时间主要耗费在划分操作上,对长度为n的区间进行划分,共需n-1次关键字的比较,时间复杂度为O(n)。对n个元素进行快速排序的过程构成一棵递归树,在这样的递归树中,每一层最多对n个元素进行划分,所花的时间为O(n)。当初始排序数据随机分布,使每次分成的两个子区间中的元素个数大致相等时,递归树高度为log2n,快速排序呈现最好情况,即最好情况下的时间复杂度为O(nlog2n)。快速排序算法的平均时间复杂度也是O(nlog2n)。

非递归方式实现算法的时间复杂度是一样的,因为非递归的实现过程和递归是一样的,不同之处在于,非递归减少了栈的开销,每迭代调用一个函数之后,就把该函数对栈的开销去除掉,对下一次函数调用开辟新的开销。

     

5、解题收获

       快速排序算法时间复杂度最坏情况为O(n2),最好和平均时间复杂度都为O(nlog2n),时间复杂度的好坏与原数组的排序方式和基准值有关,所以快排是一种不稳定的算法,为了使快速排序更加稳定,我们可以设计一些找关键字的方法,比如我在写代码时,就定义了一个取前中末三数的中位数作为关键字,这是可以避免每次找到的关键字为最大或者最小,从而提高快排的稳定性,当然也可以通过取随即值为关键字等方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值