Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
математическая логика и теория алгоритмов.doc
Скачиваний:
118
Добавлен:
10.05.2014
Размер:
2.32 Mб
Скачать
          1. 4. Функция нахождения подстроки в строке

Прототип функции может иметь следующий вид:

char * substr(char *string1, char *string2);

Функция возвращает указатель на первое вхождение подстроки string2в строкуstring1илиNULL, если подстрокаstring2не входит в строкуstring1. Схема алгоритма функции приведена на рис.II–17.

Рис. II–17

Нужно обратить внимание на следующее: так как внутренний цикл может закончиться по любому из двух условий (блоки D2 – найден конец второй строки (строки 2) или D3 – обнаружены несовпадающие символы строк), на выходе требуется дополнительная проверка (блок E2). Если цикл закончился по условию обнаружения конца строки 2, это означает, что все символы строки 2 совпадали с соответствующими символами первой (строки 1), а следовательно, строка 2 является подстрокой строки 1, и функция завершается. Если же внутренний цикл закончился по другому условию, значит, нужно продолжать проверку.

Можно было сократить количество итераций внешнего цикла, если проверять не просто нуль-байт в конце первой строки, а учитывать длину второй строки; тогда, если вторая строка окажется длиннее первой, цикл не будет выполнен ни разу (такой вариант функции, конечно, предпочтительнее).

Текст функции приводится ниже и в файле stringv.cpp.

char *substr(char *string1, char *string2)

{

char *ptr;

int i, l = strlen(string2) - 1;

for(ptr = string1; *(ptr + l); ptr++){

for(i = 0; string2[i] && ptr[i] == string2[i]; i++)

;

if(string2[i] == '\0')

return ptr;

}

return NULL;

}

        1. Строка-список

Строка может быть отображена линейным односвязным или двусвязным списком, что наиболее соответствует смыслу строки. В этом случае каждый элемент списка отображает один элемент строки. Если элемент строки имеет фиксированный размер, тогда он (элемент) может быть размещен непосредственно в элементе списка (пример – строка символов). Если же элементы строки имеют переменный размер, тогда в элементе списка размещается указатель на элемент строки. В этом случае информация о длине такого элемента может быть включена или в элемент списка, или в сам элемент строки. Примером может служить строка слов, в которой слова имеют разные длины и каждое слово представляется нуль ограниченным массивом символов. Представление строки списком может усложнить или, наоборот, упростить отдельные алгоритмы обработки строк (например, сравнение строк)

Рассмотрим реализацию тех же функций обработки строк:

  • сцепление двух строк,

  • поэлементное сравнение двух строк,

  • разбиение строки на части,

  • нахождение подстроки.

          1. 1. Сцепление двух строк

Исходные строки заданы списками; в результате сцепления получаем объединенный список, в котором вторая строка добавлена в конец первой. Функция возвращает указатель на результирующую строку-список.

Возможны два способа реализации данной функции.

Первый способ: вторая строка непосредственно подцепляется к концу первой строки (рис. II–18). Если первая строка задана пустым списком, результатом будет вторая строка. В результате работы функции вторая строка перестает существовать, что необходимо учитывать в вызывающих программах. Во избежание возможных недоразумений было бы полезно так реализовать функцию, чтобы она модифицировала указатель на второй список.

Рис. II–18

Алгоритм функции приведен на рис. II–19.

Рис. II–19

В результате работы функции меняются указатели и на первую строку, и на вторую, поэтому оба параметра целесообразно определить как ссылки.

Второй способ: в конец первой строки добавляются (копируются) символы из второй строки, при этом вторая строка сохраняется. В этом случае возможно изменение только указателя на первую строку, поэтому только один (первый) параметр определяется как ссылка.

Тексты функции приводятся ниже и в файле stringl.cpp.

struct Item{

char s;

Item *next;

};

Item *concat1(Item *&str1, Item *&str2)

{

Item *cur;

/* сначала проверим, что первый список не пуст */

if(!str1)

str1 = str2;

else{

/* формируем указатель на последний элемент первого списка */

for(cur = str1; cur->next; cur = cur->next)

;

/* включаем второй список в конец первого */

cur->next = str2;

}

str2 = NULL;

return str1;

}

Используя возможности языка С/С++, эту функцию можно реализовать более компактно, не проверяя специально условие, когда первый список пуст:

Item *concat1m(Item *&str1, Item *&str2)

{

Item **cur;

/* формируем указатель на поле указателя в последнем элементе списка */

for(pcur = &str1; *cur; cur = &(*cur)->next)

;

/* включаем второй список в конец или вместо первого */

*cur = str2;

str2 = NULL;

return str1;

}

Item *concat2(Item *&str1, Item *str2)

{

Item **cur;

/* формируем указатель на поле указателя в последнем элементе списка */

for(cur = &str1; *cur; cur = &(*cur)->next)

;

/* добавляем элементы второй строки в конец или вместо первого */

for(; str2; str2 = str2->next){

*cur = new Item;

(*cur)->s = str2->s;

(*cur)->next = NULL;

cur = &(*cur)->next;

}

return str1;

}