练习5-14 修改排序程序,使它能处理-r标记。该标记表明,以逆序(递减)方式排序。要保证-r和-n能够组合在一起使用。
练习5-15 增加选项-f,使得排序过程不考虑字母大小写之间的区别。例如,比较a和A时认为它们相等。
练习5-16 增加选项-d(代表目录顺序)。该选项表明,只对字母、数字和空格进行比较。要保证该选项可以和-f组合使用。
解:
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
#define REVERSE 1
#define NUMERIC 2
#define FOLD 4
#define DIR 8
#define MAXLINES 100
char *lineptr[MAXLINES];
int getline(char *line, int maxlen);
char *alloc(int len);
void afree(char *p);
int readlines(char *lineptr[],int maxlines);
int numcmp(char *s, char *t); //数字比较
int charcmp(char *s, char *t); //不区分大小写字母比较
int listcmp(char *s, char *t); //只比较字母,数字,空格
int char_listcmp(char *s, char *t); //只比较字母,数字,空格,但不区分大小写字母
void swap(void *v[], int left, int right);
void qsort(void *lineptr[], int left, int right, int(*cmp)(void *s,void *t));
void writelines(char *lineptr[], int nlines, int mode);
void Strcpy(char *s, char *t);
int main(int argc, char *argv[]) {
int i;
int option=0;
int c;
int nlines;
if (argc > 1){
while (--argc>0 && (*++argv)[0] == '-')
while (c = *++argv[0])
switch (c) {
case 'r':
option |= REVERSE;
break;
case'n':
option |= NUMERIC;
break;
case'f':
option |= FOLD;
break;
case'd':
option |= DIR;
break;
default:
printf("sort:illegal option %c\n", c);
break;
}
}
nlines = readlines(lineptr, MAXLINES);
if (option&NUMERIC)
qsort((void **)lineptr, 0, nlines - 1, (int(*)(void *, void *))numcmp);
else if ((option&FOLD) && !(option&DIR))
qsort((void **)lineptr, 0, nlines - 1, (int(*)(void *, void *))charcmp);
else if ((option&DIR) && !(option&FOLD))
qsort((void **)lineptr, 0, nlines - 1, (int(*)(void *, void *))listcmp);
else if (option&FOLD&DIR)
qsort((void **)lineptr, 0, nlines - 1, (int(*)(void *, void *))char_listcmp);
else
qsort((void **)lineptr, 0, nlines - 1, (int(*)(void *, void *))strcmp);
writelines(lineptr, nlines, option | REVERSE);
return 0;
}
int getline(char *line, int maxlen) {
int i;
char c;
for (i = 0; (c = getchar()) != EOF &&c != '\n' &&i < maxlen - 1; i++)
line[i] = c;
if (c == '\n')
line[i++] = '\n';
line[i] = '\0';
return i;
}
#define ALLOCSIZE 5000
static char allocbuf[ALLOCSIZE];
static char *allocp = allocbuf;
char *alloc(int len) {
if (allocbuf + ALLOCSIZE - allocp >= len) {
allocp += len;
return allocp - len;
}
else
return 0;
}
void afree(char *p) {
if (p >= allocbuf && p <= allocbuf + ALLOCSIZE - 1)
allocp = p;
}
#define MAXLEN 100
int readlines(char *lineptr[], int maxlines) {
char line[MAXLEN];
char *p;
int len,nlines=0;
while ((len = getline(line, MAXLEN)) > 0) {
if (nlines <= maxlines && (p = alloc(len)) != NULL) {
line[len - 1] = '\0';
Strcpy(line, p);
lineptr[nlines++] = p;
}
else
return -1;
}
return nlines;
}
int numcmp(char *s, char *t) {
double v1, v2;
v1 = atof(s);
v2 = atof(t);
if (v1 >= v2)
return 0;
else return -1;
}
int charcmp(char *s, char *t){
for (; *s && *t && tolower(*s) == tolower(*t); s++, t++)
;
if (tolower(*s) < tolower(*t))
return -1;
else if (tolower(*s) > tolower(*t))
return 1;
else
return 0;
}
int listcmp(char *s, char *t) {
int c1, c2;
do
{
while (!isalnum(*s) && *s != ' ' && *s != '\0')
s++;
while (!isalnum(*t) && *t != ' ' && *t != '\0')
t++;
if (*s == '\0' && *t == '\0')
return 0;
c1 = *s;
s++;
c2 = *t;
t++;
} while (c1 == c2);
if (c1 < c2)
return -1;
else
return 1;
}
int char_listcmp(char *s, char *t) {
int c1, c2;
do
{
while (!isalnum(*s) && *s != ' ' && *s != '\0')
s++;
while (!isalnum(*t) && *t != ' ' && *t != '\0')
t++;
if (*s == '\0' && *t == '\0')
return 0;
c1 = tolower(*s);
s++;
c2 = tolower(*t);
t++;
} while (c1 == c2);
if (c1 < c2)
return -1;
else
return 1;
}
void swap(void *v[], int i, int j) {
void *temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
void qsort(void *v[], int left, int right, int(*cmp)(void *s, void *t)) {
int last,i;
if (left >= right)
return;
swap(v, left,(left+right)/2);
last = left;
for (i = left+1; i <=right; i++) {
if ((*cmp)(v[i], v[left]) < 0)
swap(v, ++last, i);
}
swap(v, left, last);
qsort(v, left, last-1,cmp);
qsort(v, last + 1, right, cmp);
}
void writelines(char *lineptr[], int nlines, int mode) {
int i;
if (!mode)
for (i = 0; i < nlines; i++)
printf("%s\n", lineptr[i]);
else
for (i = nlines-1; i >=0; i--)
printf("%s\n", lineptr[i]);
}
void Strcpy(char *s, char *t) {
int i;
for (i = 0; s[i] != 0; i++)
t[i] = s[i];
if (s[i] == '\0')
t[i] = '\0';
}