一 问题描述
一个字符数组,里面的字符可能是a-z、A-Z、0-9.现在要求对数组进行排序,要求所有小写字符放在最前面,所有大写字符放在中间,所有数字放在最后,而且各部分内部分别有序。
二 解题思路
方法一 利用快排
如图所示,为了能够实现排序,首先将原始字符串进行一次二次划分,将所有小写字符移动到字符串的最开始,然后对此段子序列进行快速排序,然后依据同样的方法对大写字符和数字字符进行排序。
方法二:
如图所示,首先定义哈希表,然后根据原始字符串对哈希表进行初始化,那么在哈希表中,小写字符必然在大写字符前,大写字符必然在数字字符前,最后将哈希表里的内容拷贝回原始字符串中。
三 运行测试
方法一测试结果:
方法二测试结果
四 代码
方法一代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#define SIZE 100
int partition(char *array, int low, int high) {
int i, j;
char tmp;
i = low;
j = high;
tmp = array[low];
while(i < j) {
while(i < j && array[j] > tmp) j--;
if(i < j) array[i++] = array[j];
while(i < j && array[i] < tmp) i++;
if(i < j) array[j--] = array[i];
}
array[i] = tmp;
return i;
}
void self_qsort(char *array, int low, int high) {
if(low < high) {
int mid = partition(array, low, high);
self_qsort(array, low, mid - 1);
self_qsort(array, mid + 1, high);
}
}
void Arrange(char *str, int low, int high) {
int lower_end; // the end pointer to lower char array
int i, j;
/*
* to put all the lower char in the front of array
*/
i = low;
j = high;
char tmp = str[low];
while(i < j) {
while(i < j && !islower(str[j])) j--;
if(i < j) str[i++] = str[j];
while(i < j && islower(str[i])) i++;
if(i < j) str[j--] = str[i];
}
/*
* to locate the lower_end
*/
str[i] = tmp;
if(islower(str[i])) lower_end = i;
else lower_end = i - 1;
/*
* to sort the lower char in the array
*/
self_qsort(str, 0, lower_end);
/*
* to put the upper char in the front of digital char in the array
*/
int upper_end;
i = lower_end + 1;
j = high;
tmp = str[i];
while(i < j) {
while(i < j && !isupper(str[j])) j--;
if(i < j) str[i++] = str[j];
while(i < j && isupper(str[i])) i++;
if(i < j) str[j--] = str[i];
}
str[i] = tmp;
/*
* to locate the upper_end
*/
if(isupper(str[i])) upper_end = i;
else upper_end = i - 1;
self_qsort(str, lower_end + 1, upper_end); // to sort the upper char
self_qsort(str, upper_end + 1, high); // to sort the digital char
}
int main() {
char str[SIZE];
printf("input a string(only contains 'a' - 'z', 'A' - 'Z', '0' - '9')");
gets(str);
int i;
for(i = 0;str[i];i++) {
if(!islower(str[i]) && !isupper(str[i]) && !isdigit(str[i])) {
fprintf(stderr, "input error!\n");
exit(EXIT_FAILURE);
}
}
int len = strlen(str);
Arrange(str, 0, len - 1);
puts(str);
return 0;
}
方法二代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#define SIZE 100
#define HashTableLen 62
int HashTable[HashTableLen]; // to define a Hash Table
/*
* Hash Function: Mapping a char to a interger position
*/
int Hash(char ch) {
int pos;
if(islower(ch)) pos = ch - 'a';
else if(isupper(ch)) pos = ch - 'A' + 26;
else if(isdigit(ch)) pos = ch - '0' + 52;
else pos = -1;
return pos;
}
/*
* Reverse Hash Function: Mapping a position to a char
*/
char ReHash(int pos) {
if(pos < 26 && pos >= 0) return 'a' + pos;
if(pos < 52 && pos >= 26) return 'A' + pos - 26;
if(pos < 62 && pos >= 52) return '0' + pos - 52;
}
/*
* to initialize a Hash table
*/
void InitHash(char *str, int low, int high) {
int i;
int pos;
for(i = low;i <= high;i++) {
pos = Hash(str[i]);
if(pos == -1) {
perror("error position in the hash table!\n");
exit(EXIT_FAILURE);
}
HashTable[pos]++;
}
}
int main() {
char str[SIZE];
printf("input a string(only contains 'a' - 'z', 'A' - 'Z', '0' - '9')");
gets(str);
int i;
/*
* to check the validity
*/
for(i = 0;str[i];i++) {
if(!islower(str[i]) && !isupper(str[i]) && !isdigit(str[i])) {
fprintf(stderr, "input error!\n");
exit(EXIT_FAILURE);
}
}
int len = strlen(str);
InitHash(str, 0, len - 1);
int j = 0;
/*
* to regenerate the string
*/
for(i = 0; i < HashTableLen;i++) {
while(HashTable[i]-- > 0) {
str[j++] = ReHash(i);
}
}
puts(str);
return 0;
}
五 编程体会
这个问题本质还是排序问题,但是属于特殊排序,第一种方法利用快排,时间效率较高,而方法二要使用额外的空间,不过方法更加巧妙。