正在加载……
专注、离线、切勿分心
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define N 10
void swap(int *,int *);
void qsort(int *,int,int);
void init(int *);
void show(int *);
int main()
{
        int arr[N]={0};
        init(arr);
        show(arr);
        qsort(arr,0,N-1);
        show(arr);
        system("pause");
}
void swap(int *a,int *b)
{
        int tmp;
        tmp = *a;
        *a = *b;
        *b = tmp;
}
void init(int *arr)
{
        int i;
        srand( time(NULL) );
        for(i=0;i<N;i++)
        {
                arr[i]=rand()%100;
        }
}
void show(int *arr)
{
        int i;
        for(i=0;i<N;i++)
        {
                printf("%4d",arr[i]);
                if(i!=0&&(i+1)%20==0)        { printf("\n"); }
        }
        printf("\n");
}
void qsort(int *arr,int left,int right)
{
        int qleft = left , qright = right;
        int pivot=arr[qleft];
        //if( qleft<=qright ) // 这样写也可以,就是不能用while,不然一直循环了
        while( qleft<qright )
        {
                while( qleft!=qright )
                {
                        while( qleft<qright && arr[qright]>=pivot )
                                qright--;
                        arr[qleft] = arr[qright];
                        while( qleft<qright && arr[qleft]<=pivot )
                                qleft++;
                        arr[qright] = arr[qleft];
                }
                arr[qleft] = pivot;  //基准放在最终位置
                qsort(arr,left,qleft-1);
                qsort(arr,qright+1,right);
        }
}


void qsort(int *arr,int _left,int _right)
{
        int left=_left,right=_right,current=_left;
        int pivot=arr[_left];
        if( left<right )
        {
                current++;
                while( current<=right )
                {
                        if( arr[current]<=pivot )
                        {
                                swap(&arr[left],&arr[current]);
                                left++;
                                current++;
                        }//循环到最后,left就是基准的最终位置。arr[left]的值永远等于基准,left和current紧挨在一起
                        else
                        {
                                swap(&arr[current],&arr[right]);
                                right--;
                        }
                }
                qsort(arr,_left,left-1);
                qsort(arr,right+1,_right);
        }
}



void swap(int *a,int *b)
{
        int tmp;
        tmp = *a;
        *a = *b;
        *b = tmp;
}


// 递归调用函数要注意递归出口,没有IF,这里会一直执行到qsort

//考虑算法的时候要多想想边界条件和极端条件,还有出循环的条件。

// 这个改进也不用想这么复杂,和正常的快速排序一样,left永远指向下一个要交换的左边元素,current指向当前要比较的元素,right指向最右边要比较交换的元素。最终确定一个元素,由current指向;这时候还要对0~left-1的元素快排,还有right+1~end的元素快排。


// 模拟测试数据{2,1,3,2,3}和{3,1,2,3,2}



void qsort1(int *arr ,int _left,int _right)
{
        int left = _left,right = _right,current=_left;
        int pivot = arr[left];
        if(left<right)
        {
                while(current<=right)  // 为什么要有=,可以考虑下最简单的只有两个元素{2,1},else if 和 if 开始循环的头两次都要执行到
                {
                        if( arr[current]<pivot )
                        {
                                swap(&arr[left],&arr[current]);  // 初始第一次进入循环会执行current++,然后第二次执行会执行交换,所以left永远指向的值都等于基准。
                                left++;
                                current++;
                        }
                        else if( arr[current]==pivot ) // 如果和基准元素一样就直接偏移寻找下一个元素比较,这样到最后left-1和它左边的就都是小于基准的,right+1和它右边的就都是大于基准的
// left 和 current 之间的就都是和基准一样的值
                        {
                                current++;
                        }
                        else
                        {
                                swap(&arr[current],&arr[right]);
                                right--;
                        }
                }
                qsort1(arr,_left,left-1);  // 这里left减不减1都一样正确。
                qsort1(arr,right+1,_right);  // 试想特殊情况,数组有序,最后都会执行else造成right--,所以这里如果不right+1这里就会死循环出不去
// eg:{1,2},执行while,countz++==1,right--==0,退出循环,到这里又变成0,1。
// 最后跳出 while 循环的条件是current>right,current前的都是排好序的,所以后面right+1
// 循环最后都是right在current的后面一个位置
        }
}



#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define N 9
void swap(int *,int *);
void show(int *);
int find_once(int *,int,int);
int find_once_quick(int *);
// 两组测试数据,方便模拟程序
// {2,1,3,3,2}; {3,1,2,3,2}
void find_doubleOnce(int *,int,int);
// 测试数据
// {0,9,9,3,0,1};
void find_threeOnce(int *,int,int);
int main()
{
        int arr[N]={0,9,9,3,0,1,2,1,4};
        int result;
        //init(arr);
        show(arr);
        //result = find_once(arr,0,N-1);
        //result = find_once_quick(arr);
        //printf("%d\n",result);
        //find_doubleOnce(arr,0,N-1);
        find_threeOnce(arr,0,N-1);
        printf("\n");
        show(arr);
        system("pause");
}
void swap(int *a,int *b)
{
        int tmp;
        tmp = *a;
        *a = *b;
        *b = tmp;
}
void show(int *arr)
{
        int i;
        for(i=0;i<N;i++)
        {
                printf("%4d",arr[i]);
                if(i!=0&&(i+1)%20==0)        { printf("\n"); }
        }
        printf("\n");
}
//有101个整数,其中有50个数出现了两次,1个数出现了一次, 找出出现了一次的那个数.
int find_once(int *arr,int _left,int _right)
{
        int left=_left,right=_right,current=_left;
        int pivot=arr[_left];
        while(current<=right)
        {
                if( arr[current]<pivot )
                {
                        swap(&arr[left],&arr[current]);
                        left++;
                        current++;
                }
                else if( arr[current]==pivot )
                {
                        current++;
                }
                else
                {
                        swap(&arr[current],&arr[right]);
                        right--;
                }
        }
        if(left==right)        // 本来left和current之间的都是基准元素的值,跳出while循环的时候,right==current-1,都是两两相同的数,如果left==right,说明就是要找的只出现一次的数。
        {
                return arr[left];
        }
        else if( (left%2)==1 )        // 唯一的一个出现一次的数在左边
        {
                find_once(arr,_left,left-1);
        }
        else if(((_right-right)%2)==1)
        {
                find_once(arr,right+1,_right);
        }
}
int find_once_quick(int *arr)
{
        int result=0;
        int i;
        for(i=0;i<N;i++)
        {
                result = result^arr[i];
        }
        return result;
}

// 有102个整数,其中有50个数出现了两次,2个数出现了一次, 找出出现了一次的那2个数.
void find_doubleOnce(int *arr,int _left,int _right)
{
        int left=_left,right=_right,current=left;
        int pivot=arr[left];
        if( _left<=_right )
        {
                while(current<=right)
                {
                        if( arr[current]<pivot )
                        {
                                swap(&arr[left],&arr[current]);
                                left++;
                                current++;
                        }
                        else if( arr[current]==pivot )
                        {
                                current++;
                        }
                        else
                        {
                                swap(&arr[right],&arr[current]);
                                right--;
                        }
                }
                if( left==right )
                {
                        printf("%3d\t",arr[left]);
                        if( left%2==1 )
                        {
                                find_doubleOnce(arr,_left,left-1);
                        }
                        else
                        {
                                find_doubleOnce(arr,right+1,_right);
                        }
                }
                else
                {
                        find_doubleOnce(arr,_left,left-1);
                        find_doubleOnce(arr,right+1,_right);
                }
        }
}
// 有103个整数,其中有50个数出现了两次,3个数出现了一次, 找出出现了一次的那3个数.
void find_threeOnce(int *arr,int _left,int _right)
{
        int left=_left,right=_right,current=_left;
        int pivot=arr[_left];
        if(left<=right)
        {
                while(current<=right)
                {
                        if( arr[current]<pivot )
                        {
                                swap(&arr[current],&arr[left]);
                                left++;
                                current++;
                        }
                        else if( arr[current]==pivot ) 
                        {
                                current++;
                        }
                        else
                        {
                                swap(&arr[current],&arr[right]);
                                right--;
                        }
                }
                if( left==right )
                {
                        printf("%3d\t",arr[left]);
                }
                find_threeOnce(arr,_left,left-1);
                find_threeOnce(arr,right+1,_right);
        }
}
//这三个问题都是一类的,之所以能这样做是因为从都的数都是两两出现,left和current只有两种情况:
//第一种就是第一个元素出现两次,那么这时候left和current之间就都是这个数。最后right==current,所以它们两个数之间相差1,不可能相等
//第二种情况就是第一个数只出现一次,这样最后left==right

posted on 2017-12-11 15:54  正在加载……  阅读(283)  评论(0编辑  收藏  举报