Символни низове

Задача 10. Дадената задача е решена в урока. Предложеното решение е разширено, като е приложена функцията cin.getline(), чрез която могат да се въвеждат низове, съдържащи интервали, табулации и знак за край на ред (Enter).

Решение:

#include<iostream>
using namespace std;
int main()
{
   char str[100];
   cin.getline(str,100);
   int i=0;
   while(str[i]!='\0') i++;
   cout<<i<<endl;
   return 0;
}

Задача 11. Решението използва предходната задача, като още при първото обхождане на низа се намира броят на срещанията на символа в низа.

Решение:

#include<iostream>
using namespace std;
int main()
{
   char str[100],s;
   cin>>str>>s;
   int br=0,i=0;
   while(str[i]!='\0')
   {
    if(str[i]==s) br++;
    i++;
   }
   cout<<br<<endl;
   return 0;
}

Ако е необходимо низът и символът да се въведат на един ред посредством функцията cin.getline, то трябва да се зададе трети параметър (интервал) на тази функция:. cin getline(str,100,’ ’)

cin>>s;

Забележка: При решението на задачата може да се използва и функцията strlen(), която намира дължината на низа, вместо да се търси знак за край на низ \0. Използването на тази функция обаче не е особено рационално. Тя забавя изпълнението на програмата, защото й е необходимо време за допълнително обхождане на низа и преброяване на символите му.

Задача 12. Задачата може да се реши на базата на решенията на предходните две задачи, без да се ползва функцията за дължина на низ. При обхождането в цикъла се извежда всеки символ, различен от интервал. При срещане на интервал се извежда знак за нов ред.

Решение:

#include<iostream>
using namespace std;
int main()
{
   char str[100];
   cin.getline(str,100);
   int i=0;
   while(str[i]!='\0')
   {
    if(str[i]!=' ')cout<<str[i];
    else cout<<endl;
    i++;
   }
   return 0;
}

Задача 13. Дадената задача е аналогична на задача 11, с единствената разлика, че се броят интервали, тъй като всяка дума завършва с интервал (без последната). След като се намери броят на интервалите, се извежда броят на думите. Този брой е с единица по-голям от броя на интервалите. Това решение е удачно само ако е сигурно, че думите са разделени точно с един интервал.

Решение:

#include<iostream>
using namespace std;
int main()
{
   char str[81];
   cin.getline(str,81);
   int br=0,i=0;
   while(str[i]!='\0')
   {
      if(str[i]==' ')br++;
      i++;
   }    
   cout<<(br+1)<<endl;
   return 0;
}

По условие изречението завършва с точка и условието за края на цикъла може да бъде при срещане на символа ‘.’, а не при символа за край на низ \0.

Ако въвеждането на низа е направено с указване на завършващ символ ‘.’ – cin.getline(str,81,’.’), трябва да се отбележи, че самата точка няма да се въведе в низа. Затова в този случай низът трябва да се обхожда до срещане на символа за край на низ.

Задача 14. Решението е съобразено с коректен вход, при който разделител между думите е само един интервал. Прави се последователно обхождане на символите на низа, като при срещане на интервал трябва да се провери дали по-следващият символ е интервал или точка. Ако това е вярно, се увеличава променлива брояч. При изречение, започващо с еднобуквена дума, тя няма да бъде отчетена, поради което се налага предварителна проверка.

Решение:

#include<iostream>
using namespace std;
int main()
{
   char str[81];
   cin.getline(str,81);
   int br=0,i=0;
   if(str[1]==' ')br++;
   //Докато не се стигне до точка
   while(str[i]!='.')
   {
    if(str[i]==' ')
    {
            //Ако е край на дума или край на изречение
            if(str[i+2]==' '||str[i+2]=='.')br++;
    }
    i++;
   }
   cout<<br<<endl;
   return 0;
}

Задача 15. Тази задача е аналогична на задача 31, след темата за масиви. Единствената разлика е, че предварително трябва да се намери дължината на низа.

Решение:

#include<iostream>
#include<string>
using namespace std;
int main()
{
   char str[51];
   cin.getline(str,51);
   int n,i;
   n=strlen(str);
   for(i=0;i<n/2;i++)
      if(str[i]!=str[n-1-i])break;
   if(i<n/2)cout<<"No"<<endl;
   else cout<<"Yes"<<endl;
   return 0;
}

Задача 16. Ако за вход се въведат низовете ananas и ana, то изходът трябва да бъде 2. Защо?

В решението е приложен следният алгоритъм:

1)      В цикъл се обхожда първият низ и се търси равенство с първия символ на втория низ. При намиране на такова чрез вложен цикъл се прави сравнение дали следващите символи от втория низ съвпадат със съответните им следващи от първия.

2)      След приключване на втория цикъл чрез неговата управляваща променлива се проверява дали той е обходен докрай, или цикълът е бил прекъснат. Ако е обходен докрай, се увеличава променлива брояч.

Решение:

#include<iostream>
using namespace std;
int main()
{
   char str1[100],str2[100];
   cin.getline(str1,100);
   cin.getline(str2,50);
   int i=0,j,br=0;
   while(str1[i]!='\0')
   {
      //Нулира се управляващата променлива на вложения цикъл
      j=0;
      if(str1[i]==str2[0])
      {
         while(str2[j]!='\0')
         {
            //Сравняват се съответните символи
           if(str1[i+j]!=str2[j])break;
           j++;
         }
      }
      /*Броячът се увеличава, ако j е равна на 
      индекса на символа '\0' във втория низ*/
      if(str2[j]=='\0')br++;
      i++;
   }
   cout<<br<<endl;
   return 0;
}

Защо управляващата променлива jсе нулира всеки път в началото на тялото на външния цикъл?

Задача 17. В решението е използван един цикъл, като е приложен следният алгоритъм:

1) Декларират си променливи с имена max, br и s, в които ще се пазят съответно максималният брой еднакви поредни символи, текущият брой максимални поредни символи и самият символ. Първоначалните инициализации са max=1, br=1 и s=str[0];

2) В цикъл със следусловие се обхожда низът, започвайки от втория символ. На всяка стъпка се сравняват два съседни символа (текущият и предходният му символ).

3) Ако символите са еднакви, броячът се увеличава и обхождането продължава. Ако символите са различни, се проверява дали броячът е по-голям от max и ако е така, на max се присвоява стойността на брояча, а на s – стойността на предишния символ. След което на брояча отново се задава стойност 1.

Решение:

#include<iostream>
using namespace std;
int main()
{
   char str[100],s;
   cin.getline(str,100);
   int i=0,max=1,br=1;
   s=str[0];
   do
   {
    i++;
    if(str[i]==str[i-1])br++;
    else
    {
        if(br>max)
        {
            max=br;
            s=str[i-1];
        }
        br=1;
    }
   }while(str[i]!='\0');
   cout<<max<<" "<<s<<endl;
   return 0;
}

Защо управляващата променлива на цикъла (i) се увеличава в неговото начало?

По-стандатно решение на задачата може да се направи, като се използват два вложени цикъла за обхождане на низа. В този случай трябва да се сравняват символи от вътрешния и външния цикъл.

Задача 18. Решението на задачата може да бъде реализирано чрез два вложени цикъла и един флаг, който да маркира първото срещане на повтарящите се символи. Алгоритъмът, описващ решението е следният:

1) В един цикъл се обхождат всички елементи на низа.

2) За всеки символ от низа се задава стойност на флаг 0 и в нов вложен цикъл този символ се сравнява с всички останали елементи на низа, намиращи се след него.

3) Ако се намери равенство, флагът приема стойност 1, символът и позициите, в които е намерен, се извеждат и вложеният цикъл се прекъсва.

4) Изпълнението продължава с тялото на първия цикъл, където се проверява стойността на флага. Ако тя е 1, и този цикъл се прекъсва. В противен случай се преминава към следващата итерация.

5) При завършване на цикъла се проверява стойнността на флага. Ако тази стойност е 0, то в низа не са намерени повтарящи се символи.

Решение:

#include<iostream>
using namespace std;
int main()
{
   char str[71];
   cin.getline(str,71);
   int i=0,j,flag;
   while(str[i]!='\0')
   {
    flag=0;
    j=i+1;
    while(str[j]!='\0')
    {
        if(str[i]==str[j])
        {
            cout<<str[j]<<" "<<i<<" "<<j<<endl;
            flag=1;
            break;
        }
        j++;
    }
    if(flag)break;
    i++;
   }
   if(flag==0)cout<<"No"<<endl;
   return 0;
}

  • Задача 19. Решението на задачата е аналогично на предходното. Тук е необходимо да се намерят началният и крайният индекс на най-дългата дума, след което да бъдат отпечатани всички символи между тези два индекса. Следният алгоритъм описва действията, които са необходими:

    1) Декларират се променливи n1 и n2, които да маркират началния и крайния индекс на най-дългата дума. Необходими са междинните променливи брояч br и max, служещи съответно за намиране дължината на текущата дума и за запазване на максималната дължина. Инициализират се n1, br и max съответно: n1=0, br=0, max=0 (Защо?).

    2) Низът се обхожда в цикъл със следусловие.

    3) Всеки път в цикъла се прави проверка дали е намерен знак за интервал.

    4) Ако резултатът от проверката е истина, то се проверява дали стойността на br е по-голяма от тази на max. Ако това е вярно, max става равна на br. Намира се индексът n1, като от текущата позиция се извади стойността на br. На индекса n2 се присвоява текущата позиция. След завършване на проверката броячът br се нулира.

    5) Ако стойността на условието от точка 3 не е истина, то тогава броячът се увеличава.

    6) След завършване на цикъла отново се прави проверката за max от точка 4 с цел да се провери и последната дума.

    7) Програмата завършва с цикъл, който извежда всички символи в интервала [n1,n2), което е търсената дума.

    Решение:

#include<iostream>
using namespace std;
int main()
{
   char str[201];
   cin.getline(str,201);
   int i=0,n1=0,n2,br=0,max=0;
   while(str[i]!='\0')
   {
    if(str[i]==' '||str[i]=='\0')
    {
        if(br>max)
        {
            n1=i-br;
            n2=i;
            max=br;
        }
        br=0;
    }
    else br++;
    i++;
   }
   //Проверка за последната дума
   if(br>max)
   {
      n1=i-br;
      n2=i;
      max=br;
   }
   //Извеждане на търсената дума
   for(int j=n1;j<n2;j++)cout<<str[j];
   return 0;
}

Задача 20. Разликата между тази и предходната задача е, че се търси минималната дължина и интервалите между всяка дума може да са повече от един. Решението ползва логиката от предната задача, като е включен допълнителен цикъл, който прескача излишните интервали.

Решение:

#include<iostream>
using namespace std;
int main()
{
   char str[201];
   cin.getline(str,201);
   //Деклариране и инициализиране на необходимите променливи
   int i=0,br=0,min=200;
   while(str[i]!='\0')
   {
    if(str[i]==' ')
    {
        if(min>br)min=br;
        br=0;
        //Прескачат се допълнителните интервали
        while(str[i+1]==' ') i++;
    }
    else br++;
    i++;
   }
   if(min>br)min=br;
   cout<<min<<endl;
   return 0;
}

Задача 21. За решението на задачата може да се използва задача 13. Там броят на думите се намира, като се преброят интервалите, разделящи думите. Разликата тук е, че думите може да са разделени с повече от един интервал. При намиране на интервал той ще се брои, а ако след него има други интервали, те ще се прескачат.

Решение:

#include<iostream>
using namespace std;
int main()
{
   char str[201];
   cin.getline(str,201);
   int br=0,i=0;
   while(str[i]!='\0')
   {
    if(str[i]==' ')
    {
        br++;
        while(str[i+1]==' ') i++;
    }
    i++;
   }    
   cout<<(br+1)<<endl;
   return 0;
}

Задача 22. Задачата може да се реши на базата на предходните две задачи. В цикъл се обхожда низът и на екрана се извежда всеки негов символ, след което се проверява дали текущият символ е интервал. Ако е интервал, се стартира втори цикъл, който да прескача следващите го излишни интервали.

Решение:

#include<iostream>
using namespace std;
int main()
{
   char str[201];
   cin.getline(str,81);
   int i=0;
   while(str[i]!='\0')
   {
    cout<<str[i];
    if(str[i]==' ')
    {
        while(str[i+1]==' ') i++;
    }
    i++;
   }
   return 0;
}

Задача 23. Задача 19 решава същия проблем, с тази разлика, че там думите са разделени само с един интервал. Използвайки същата идея, може да се реши и дадената задача, но при намиране на интервал трябва да се добави още един цикъл. Той ще прескача излишните интервали до началото на следващата дума.

Решение:

#include<iostream>
using namespace std;
int main()
{
   char str[201];
   cin.getline(str,201);
   int i=0,n,br=0,min=200;
   while(str[i]!='\0')
   {
    if(str[i]==' ')
    {
        if(br<min)
        {
            n=i;
            min=br;
        }
        br=0;
        while(str[i+1]==' ') i++;
    }
    else br++;
    i++;
   }
   if(br<min)
   {
     n=i;
     min=br;
   }
   n=n-min;
   cout<<min<<" "<<n<<endl;
   return 0;
}