题目
(2018吉林大学941)一个长度为 n 的数组由负数、0、正数组成。编写函数,将其重新排序为前段都是负数,后段均为非负数的结构。要求时间复杂度为 O(n)。
一、算法的整体思想
使用了双指针,分别指向了顺序表的头与尾。从前至后遍历顺序表。
如果该结点为负数,将其与头指针交换,头指针指向向下一个结点,从交换前的后一结点开始往后遍历;
如果该结点为0,则继续遍历不用交换结点(注意此时头指针未随i一起往后移动)
如果该结点为正数,将其与尾指针交换,尾指针指向前一结点,从交换前的结点指针处开始遍历(此时结点指针处就是i指向处,也就是继续刚刚的i处继续遍历,检察刚刚换回的尾指针所指的元素 )
二、程序编写
2.1代码
代码如下:
void Sort(int A[],int length)//输入:数组 A[],数组长度length
{
int head,rear,count;//头尾指针 count为计算比较元素的个数
head=0;count=0
rear=length-1;//初始化
for(int i=head;count<length;)//终止条件
{
if(a[i]>0) //如果该结点为正数,将其与尾指针交换
{
swap(&a[i],&a[rear]);
rear--;count++;//计数+1
}
if(a[i]==0)//如果该结点为0,则不做变动,头指针保持不变,继续做遍历
{
i++;count++;//继续计数+1,接着往后遍历
}
if(a[i]<0)//如果该结点为负数,,将该结点与 头指针做交换,并将头指针往后指一个
{
swap(&a[i],&a[head]);
i++;
head++;
count++;//计数+1
}
}
}
void swap(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
/*或者C++的引用方法
void swap(&a,&b)
{
int temp;
temp=a;
a=b;
b=temp;
}
此时上面的调用swap(a[i],a[j])*/
2.2相关基础补充
2.2.1 for循环语句
2.2.2 指针和指针指向的类型
指针的类型和指针指向的类型,以下面的例子来说明:(*是间接访问符 /解引用 ,&取地址符)
int* p;
char* p;
int* *p;
int (*p)[3];
int* (*p)[3];
从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。上述例子中指针的类型为:
int* ptr; //指针的类型是int*
char* ptr; //指针的类型是char*
int* ptr; //指针的类型是int*
int (ptr)[3]; //指针的类型是int()[3]
int* (ptr)[4];//指针的类型是int()[4]
从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声明符去掉,剩下的就是指针所指向的类型。上述例子中指针指向的类型为:
int* ptr; //指针所指向的类型是int
char* ptr; //指针所指向的的类型是char
int* ptr; //指针所指向的的类型是int
int (*ptr)[3]; //指针所指向的的类型是int ()[3]
int* (ptr)[4]; //指针所指向的的类型是int ()[4]
三、时间复杂度分析
本算法只有一层循环,最坏情况时遍历整个数组,故时间复杂度为O(n)。
四、总结
此题要注意双指针的运用,在运用时要有头指针,尾指针,以及计数器count,
另外还有遍历数组时的变量i,不要搞混。
另外此题还可以借助一个新数组,将原数组进行遍历,将负数放在新数组的前侧,非负数放在新数组的后侧。
此代码的时间复杂度是O(n),但是空间复杂度是O(n),而上文代码的空间复杂度是O(1)。