以“二维数组的列排序”为例练习“ 考虑问题的全局性"以及“ 声明数组必须要分配内存并清零”:
题目要求:
给出一个二维数组,请将这个二维数组按第i列(i从1开始)排序,如果第i列相同,则对相同的行按第i+1列的元素排序,如果第i+1列的元素也相同,则继续比较第i+2列,以此类推,直到最后一列。如果第i列到最后一列都相同,则按原序排列。
实现以下接口:
输入一个m*n 的整数数组,实现按规则排列,返回排列后的数组。
比如输入数组为:
1,2,3
2,3,4
2,3,1
1,3,1
按第二列排序:
输出:
1,2,3
2,3,1
1,3,1
2,3,4
一个失败的程序:
void RangeArray(int * pArray,unsigned int m, unsigned int n,unsigned int i)
{
/*if((0 == pArray) || (i > n) || (m <= 0) || (n <= 0)|| (i <= 0))*///i可以为0的
if((0 == pArray) || (i > n) || (m < 0) || (n < 0)|| (i < 0))
return;
//int temp_col[m] = {0};//中间数组,存储某一列的m行上的数据
//int temp_row[n] = {0};//中间数组,存储某一行的n列上的数据
int * temp_col;//上面的编译不通过,因为编译器把m、n认为是变量。数组的个数应该是常量的
int * temp_row;
temp_col = (int *)malloc(sizeof(int) * m);//必须加这个分配内存的,不然编译可以通过,但运行时异常蹦出,提示temp_col变量未定义
temp_row = (int *)malloc(sizeof(int) * n);
memset(temp_col,0,m);
memset(temp_row,0,n);
for(unsigned int cnt = 0;cnt < m;++cnt)//这一步可以省去,在下面中直接用pArray[i - 1 + cnt * n]来比较也是可以的
{
temp_col[cnt] = pArray[i - 1 + cnt * n];
}
for(unsigned int rnum = 0;rnum < m - 1;++rnum)//冒泡排序法排序
{
for(unsigned int j = m - 1;j > rnum;--j)
if(temp_col[j] < temp_col[j - 1])
{
/*memcpy(temp_row,pArray + j * m,n);
memcpy(pArray + j * m,pArray + (j - 1) * m,n);
memcpy(pArray + j * m,temp_row,n);*/
memcpy(temp_row,pArray + j * n,n * sizeof(int));
memcpy(pArray + j * n,pArray + (j - 1) * n,n * sizeof(int));
memcpy(pArray + j * n,temp_row,n * sizeof(int));
}
else if(temp_col[j] == temp_col[j - 1])
{
/*int cnum = i - 1;*/
unsigned int cnum = i;//在数组中因为是从0开始,所以实际上是i的后一列,
/*while(cnum < n - 1)*/ //最后 n-1的那列也要计算
while(cnum < n)
{
if(pArray[cnum + j * n] < pArray[cnum + (j - 1) * n])
{
/*memcpy(temp_row,pArray + j * m,n);
memcpy(pArray + j * m,pArray + (j - 1) * m,n);
memcpy(pArray + j * m,temp_row,n);*/
memcpy(temp_row,pArray + j * n,n * sizeof(int));//这样有一个大缺陷是改变了前面大循环中的顺序
memcpy(pArray + j * n,pArray + (j - 1) * n,n * sizeof(int));//即前面的列比较的过程被打乱了。当目前的小循环结束返回前个循环时已经不是原来的循环了。
memcpy(pArray + j * n,temp_row,n * sizeof(int));//一种比较好的方案是从最后一列排序,一直排到参考的i列。这样最后的结果时,第i列是完全排序好的
break;
}
else if(pArray[cnum + j * n] == pArray[cnum + (j - 1) * n])
{
++cnum;
}
}
}
}
return;
}
一种比较好的方案是从最后一列排序,一直排到参考的i列。这样最后的结果时,第i列是完全排序好的。代码如下:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "oj.h"
// 功能:排列一个m行n列 大小的数组
// 输入: int * pArray 指向数组第一个元素的指针,m为行数, n为列数 ,请按第i列排列
// 输出:按第i列排序完成后的数组放到入参指定的地址中 (i的取值范围 1 - n)
// 返回:
void RangeArray(int * pArray,unsigned int m, unsigned int n,unsigned int i)
{
if((NULL == pArray) || (i > n) || (m < 0) || (n < 0)|| (i < 0))
return;
int * temp = new int[n];//存储某行的n个数
//int * temp ;//存储某行的n个数
//temp = (int *)malloc(sizeof(int) * n);
memset(temp,0,n * sizeof(int));
unsigned int cnt = n - 1;
while(cnt >= (i - 1)) //冒泡排序法
//for(;cnt >= (i - 1);--cnt)
{
for(unsigned int ni = 0;ni < m - 1;++ni) // 下面用的nj与nj-1比较,就把这里ni压一个
{
//for(unsigned int nj = m - 2;nj >= ni;--nj)//带等号,nj == ni这种情况不可以,运行时出错;去掉等号就不是冒泡排序法了,有一例未通过
//if(pArray[cnt + (nj + 1) * n] < pArray[cnt + nj * n])
// {
// memcpy(temp,pArray + nj * n,sizeof(int) * n);
// memcpy(pArray + nj*n,pArray + (nj + 1) * n,sizeof(int) * n);
// memcpy(pArray + (nj + 1) *n,temp,sizeof(int) * n);
// }
for(unsigned int nj = m - 1;nj > ni;--nj)//
{
if(pArray[cnt + nj * n] < pArray[cnt + (nj - 1) * n])
{
memcpy(temp,pArray + nj * n,sizeof(int) * n);
memcpy(pArray + nj * n,pArray + (nj - 1) * n,sizeof(int) * n);
memcpy(pArray + (nj - 1) *n,temp,sizeof(int) * n);
}
}
for(unsigned int nj = 0;nj < m - ni - 1;++nj)//这种也可以
//{
// if(pArray[cnt + nj * n] < pArray[cnt + (nj - 1) * n])
// {
// memcpy(temp,pArray + nj * n,sizeof(int) * n);
// memcpy(pArray + nj*n,pArray + (nj + 1) * n,sizeof(int) * n);
// memcpy(pArray + (nj + 1) *n,temp,sizeof(int) * n);
// }
//}
}
//--cnt;//这一句要放在最后,不然对cnt为0的情况严重影响
if(cnt == 0) //这一句必须加,不然如果i为0,cnt为0,则cnt-1后在无符号整形中是很大的数,陷入死循环
break;
--cnt;
}
return;
}