#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
|