快速排序模拟实现

快速排序,时间复杂度为O(NlogN),属于排序中相对快的那一列,以下是快排的模拟实现:

法一:左右指针交换法

void swap(int* x, int* y)
{
    int tmp = *x;
    *x = *y;
    *y = tmp;
}//交换函数


int getmid(int* a, int left, int right)
{   
    int mid = (left + right) / 2;
    if (a[left] < a[right])
    {
        if (a[mid] > a[right])
        {
            return right;
        }
        else
        {
            if (a[mid] > a[left])
            {
                return mid;
            }
            else
            {
                return left;
            }
        }
    }
    else  //left大于right
    {
        if (a[mid] < a[right])
        {
            return right;
        }
        else
        {
            if (a[mid] < a[left])
            {
                return mid;
            }
            else
            {
                return left;
            }
        }
    }


}//三数取中



int PartSort1(int* a, int left, int right)
{
    int mid = getmid(a, left, right);
    int keyi = left;

    while (left < right)
    {

        while (left < right && a[right]>=a[keyi])
        {
            right--;
        }
        while (left < right && a[left] <=a[keyi])
        {
            left++;
        }
        swap(&a[left], &a[right]);

    }

    swap(&a[keyi], &a[left]);
    return left;


}


void sort(int* arr, int left, int right)
{
	if (left < right)
	{

		int mid = PartSort1(arr, left, right);
		sort(arr, left, mid - 1);
		sort(arr, mid + 1, right);

	}



}

本思路是以left下标所指的元素为分界线,left指针向右移动找比分界元素大的,right指针向左移动找比分解元素小的,然后两者交换。通过这样循环,使得左侧的元素都是比分界元素小的,右侧元素都是比分界元素大的,且此时分界元素已经放在了排好序后的正确位置上。再对分界元素左侧、右侧调用同样的方法,最后就能实现排序。三数取中是一种优化方式,使得left下标所指向的元素更加贴近当前left到righ范围内的中间值。最后之所以用left指向位置和keyi指向位置进行交换,是因为left此时所指元素一定小于等于keyi所指向的元素。下面会证明为什么left此时所指元素一定小于等于keyi所指向的元素:

当循环停止以后,循环前的最后一次移动分两种情况,一种是right指针左移动碰到left,一种是left指针右移动碰到right。对于第一种情况,此时left指针所指的位置是前面left和right所指元素交换后的,所以此时left所指元素一定是小于keyi的。对于第二种情况,此时right指针已经结束移动,所指向的位置也是小于keyi的元素。所以left此时所指元素一定小于等于keyi所指向的元素。当然,如果先移动left指针再移动right指针,就不能符合上述结论。

法二:挖坑法

// 挖坑法
int PartSort2(int* a, int left, int right)
{
     int mid = getmid(a, left, right);
     swap(&a[left], &a[mid]);
    //三数取中
    int key = a[left];
    int hole = left;

    while (left < right)
    {

        while (left < right && a[right] >= key)
        {
            right--;
        }
      
        a[hole] = a[right];
        hole = right;
        while (left < right && a[left] <= key)
        {
            left++;
        }
        a[hole] = a[left];
        hole = left;
    }

    a[hole] = key;
    return hole;

}

void sort(int* arr, int left, int right)
{
	if (left < right)
	{

		int mid = PartSort2(arr, left, right);
		sort(arr, left, mid - 1);
		sort(arr, mid + 1, right);

	}



}

该方法的思路是先把left所指的位置视为坑,保存最左的元素到可以中 ,此后利用right指针和left指针移动找元素填坑和创建新坑。此时整个数组中一直保持着有一个下标指向坑,最后再将最开始保存的key放入坑中,形成完整的数组。left和right指针的移动规则仍然是left找比key大的,right找比key小的。

法三:前后指针法

int PartSort3(int* a, int left, int right)
{

    int prev = left;
    int cur = left+1;

    while (cur <= right)
    {
        while(cur <= right&&a[cur] <= a[left])
        {  
            prev++;
            swap(&a[cur], &a[prev]);
            cur++;
           
        }
        if (cur > right)
        {
            break;
        }
        while (cur <= right && a[cur] > a[left])
        {
            cur++;

        }
        if (cur > right)
        {
            break;
        }

    }
    swap(&a[prev], &a[left]);
    
    return prev;
}


void sort(int* arr, int left, int right)
{
	if (left < right)
	{

		int mid = PartSort2(arr, left, right);
		sort(arr, left, mid - 1);
		sort(arr, mid + 1, right);

	}



}

思路是让prev的下一位元素是比a[left]大的元素,cur所指的元素是比a[left]小的元素,然后交换,使得小于a[left]的元素往左移动,比a[left]大的元素不断往右移动。

你可能感兴趣的:(算法,排序算法,java,数据结构,c语言,c++)