h1

Курсовая работа по дисциплине САКОД (структуры и алгоритмы компьютерной обработки данных) на тему «Динамические структуры данных»

Май 28, 2010

Данная курсовая работа была написана в мае 2010 и защищена на отлично. В курсовой работе использованная опубликованная ранее программа для работы с бинарными деревьями.

Ссылка на скачаивание

Текст курсовой работы (за исключением рисунков, которые есть в документе с работой):

Содержание
Введение
1. Массовые операции
2. Виды динамических структур данных
2.1 Список
2.1.1 Определение списка
2.1.2 Ссылочная реализация списка
2.1.3 Реализация списка в языке Turbo Pascal
2.2.1 Определение понятий деревьев и графов
2.2.2 Реализация бинарного дерева на языке Turbo Pascal
Заключение
Список использованной литературы

Введение
Большинство структур данных реализуется на базе массива. Все реализации можно разделить на два класса: непрерывные и ссылочные. В непрерывных реализациях элементы структуры данных располагаются последовательно друг за другом в непрерывном отрезке массива, причем порядок их расположения в массиве соответствует их порядку в реализуемой структуре.
В ссылочных реализациях элементы структуры данных хранятся в произвольном порядке. При этом вместе с каждым элементом хранятся ссылки на один или несколько соседних элементов. В качестве ссылок могут выступать либо индексы ячеек массива, либо адреса памяти. Можно представить себе шпионскую сеть, в которой каждый участник знает лишь координаты одного или двух своих коллег. Контрразведчикам, чтобы обезвредить сеть, нужно пройти последовательно по всей цепочке, начиная с выявленного шпиона.
Ссылочные реализации обладают двумя ярко выраженными недостатками: 1) для хранения ссылок требуется дополнительная память; 2) для доступа к некоторому элементу структуры необходимо сначала добраться до него, проходя последовательно по цепочке других элементов. Казалось бы, зачем нужны такие реализации?
Все недостатки ссылочных реализаций компенсируются одним чрезвычайно важным достоинством: в них можно добавлять и удалять элементы в середине структуры данных, не перемещая остальные элементы.

1. Массовые операции
Массовые операции — это операции, затрагивающие значительную часть всех элементов структуры данных. Пусть нужно добавить или удалить один элемент. Если при этом приходится, например, переписывать значительную часть остальных элементов с одного места на другое, то говорят, что добавление или удаление приводит к массовым операциям. Массовые операции — это бедствие для программиста, то, чего он всегда стремится избежать. Хорошая реализация структуры данных — та, в которой массовых операций либо нет совсем, либо они происходят очень редко. Например, добавление элемента должно выполняться за ограниченное число шагов, независимо от того, содержит ли структура десять или десять тысяч элементов.
В непрерывных реализациях добавление или удаление элементов в середине структуры неизбежно приводит к массовым операциям. Поэтому структуры, в которых можно удалять или добавлять элементы в середине, обязательно должны быть реализованы ссылочным образом.
Пример неудачного использования непрерывных реализаций — файловые системы в некоторых старых операционных системах. В современных файловых системах файлы фрагментированы, т.е. кусочки большого файла, непрерывного с точки зрения пользователя, на самом деле могут быть разбросаны по всему диску. Раньше это было не так, файлы должны были обязательно занимать непрерывный участок на диске. При постоянной работе файлы уничтожались и создавались заново на новом месте — и всякое редактирование текстового файла приводило к его обновлению. В результате свободное пространство на диске становилось фрагментированным, т.е. состоящим из множества небольших кусков. Возникала ситуация, когда большой файл невозможно записать на диск: хотя свободного места в сумме много, нет достаточно большого свободного фрагмента. Приходилось постоянно выполять длительную и опасную процедуру сжатия диска, которая часто приводила к потере всех данных на нем.

2. Виды динамических структур данных
2.1 Список
2.1.1 Определение списка
Классический пример структуры данных последовательного доступа, в которой можно удалять и добавлять элементы в середине структуры, — это линейный список. Различают однонаправленный и двунаправленный списки (иногда говорят односвязный и двусвязный).
Элементы списка как бы выстроены в цепочку друг за другом. У списка есть начало и конец. Имеется также указатель списка, который располагается между элементами. Если мысленно вообразить, что соседние элементы списка связаны между собой веревкой, то указатель — это ленточка, которая вешается на веревку. В любой момент времени в списке доступны лишь два элемента — элементы до указателя и за указателем.
В однонаправленном списке указатель можно передвигать лишь в одном направлении — вперед, в направлении от начала к концу. Кроме того, можно установить указатель в начало списка, перед его первым элементом. В отличие от однонаправленного списка, двунаправленный абсолютно симметричен, указатель в нем можно передвигать вперед и назад, а также устанавливать как перед первым, так и за последним элементами списка.
В двунаправленном списке можно добавлять и удалять элементы до и за указателем. В однонаправленном списке добавлять элементы можно также с обеих сторон от указателя, но удалять элементы можно только за указателем.
Удобно считать, что перед первым элементом списка располагается специальный пустой элемент, который называется головой списка. Голова списка присутствует всегда, даже в пустом списке. Благодаря этому можно предполагать, что перед указателем всегда есть какой-то элемент, что упрощает процедуры добавления и удаления элементов.
В двунаправленном списке считают, что вслед за последним элементом списка вновь следует голова списка, т.е. список зациклен в кольцо.
Можно было бы точно так же зациклить и однонаправленной список. Но гораздо чаще считают, что за последним элементом однонаправленного списка ничего не следует. Однонаправленный список, таким образом, представляет собой цепочку, начинающуюся с головы списка, за которой следует первый элемент, затем второй и так далее вплоть до последнего элемента, а заканчивается цепочка ссылкой в никуда.

2.1.2 Ссылочная реализация списка
Мы рассмотрели абстрактное понятие списка. Но в программировании зачастую отождествляют понятие списка с его ссылочной реализацией на базе массива или непосредственно на базе оперативной памяти.
Основная идея реализации двунаправленного списка заключается в том, что вместе с каждым элементом хранятся ссылки на следующий и предыдущий элементы. В случае реализации на базе массива ссылки представляют собой индексы ячеек массива. Чаще, однако, элементы списка не располагают в каком-либо массиве, а просто размещают каждый по отдельности в оперативной памяти, выделенной данной задаче. (Обычно элементы списка размещаются в так называемой динамической памяти, или куче — это область оперативной памяти, в которой можно при необходимости захватывать куски нужного размера, а после использования освобождать, т.е. возвращать обратно в кучу.) В качестве ссылок в этом случае используют адреса элементов в оперативной памяти.
Голова списка хранит ссылки на первый и последний элементы списка. Поскольку список зациклен в кольцо, то следующим за головой списка будет его первый элемент, а предыдущим — последний элемент. Голова списка хранит только ссылки и не хранит никакого элемента. Это как бы пустой ящик, в который нельзя ничего положить и который используется только для того, чтобы написать на нем адреса следующего и предыдущего ящиков, т.е. первого и последнего элементов списка. Когда список пуст, голова списка зациклена сама на себя.
Указатель списка реализуется в виде ссылки на следующий и предыдущий элементы, он просто отмечает некоторое место в цепочке элементов.
В случае однонаправленного списка хранится только ссылка на следующий элемент, таким способом экономится память. Голова однонаправленного списка хранит ссылку на первый элемент списка. Последний элемент списка хранит нулевую ссылку, т.е. ссылку в никуда, т.к. в программах нулевой адрес никогда не используется.
Ценность ссылочной реализации списка состоит в том, что процедуры добавления и удаления элементов не приводят к массовым операциям. Рассмотрим, например, операцию удаления элемента за указателем. Читая ссылку на следующий элемент в удаляемом элементе, мы находим, какой элемент должен будет следовать за указателем после удаления текущего элемента. После этого достаточно связать элемент до указателя с новым элементом за указателем. А именно, обозначим через X адрес элемента до указателя, через Y — адрес нового элемента за указателем. В поле следующий для элемента с адресом X надо записать значение Y, в поле предыдущий для элемента с адресом Y — значение X. Таким образом, при удалении элемента за указателем он исключается из цепочки списка, для этого достаточно лишь поменять ссылки в двух соседних элементах. Аналогично, для добавления элемента достаточно включить его в цепочку, а для этого также нужно всего лишь модифицировать ссылки в двух соседних элементах. Добавляемый элемент может располагаться где угодно, следовательно, нет никаких проблем с захватом и освобождением памяти под элементы.

2.1.3 Реализация списка в языке Turbo Pascal
В языке Turbo Pascal предусмотрены два типа указателей – типизированные и не типизированные указатели. В случае линейного списка описание данных может выглядеть следующим образом.
type
element = record
data:string;
next: pointer;
end;
var
head: pointer;
current, last : ^element;
В данном примере элемент списка описан как запись, содержащая два поля. Поле data строкового типа служит для размещения данных в элементе списка. Другое поле next представляет собой не типизированный указатель, который служит для организации списковой структуры.
В описании переменных описаны три указателя head, last и current. Head является не типизированным указателем. Указатель current является типизированным указателем, что позволяет через него организовать доступ к полям внутри элемента, имеющего тип element. Для объявления типизированного указателя обычно используется символ ^, размещаемый непосредственно перед соответствующим типом данных. Однако описание типизированного указателя еще не означает создание элемента списка. Рассмотрим, как можно осуществить создание элементов и их объединение в список.
В системе программирования Turbo Pascal для размещения динамических переменных используется специальная область памяти “heap-область”. Heap-область размещается в памяти компьютера следом за областью памяти, которую занимает программа и статические данные, и может рассматриваться как сплошной массив, состоящий из байтов.
Попробуем создать первый элемент списка. Это можно осуществить при помощи процедуры New
New(Current);
После выполнения данной процедуры в динамической области памяти создается динамическая переменная, тип которой определяется типом указателя. Сам указатель можно рассматривать как адрес переменной в динамической памяти. Доступ к переменной может быть осуществлен через указатель. Заполним поля элемента списка.
Current^.data:= ’данные в первом элементе списка ’ ;
Сurrent^.next:=nil;
Значение указателя nil означает пустой указатель. Обратим внимание на разницу между присвоением значения указателю и данным, на которые он указывает. Для указателей допустимы только операции присваивания и сравнения. Указателю можно присваивать значение указателя того же типа или константу nil. Данным можно присвоить значения, соответствующие декларируемым типам данных. Для того чтобы присвоить значение данным, после указателя используется символ ^. Поле Сurrent^.next само является указателем, доступ к его содержимому осуществляется через указатель Current.
В результате выполнения описанных действий мы получили список из одного элемента. Создадим еще один элемент и свяжем его с первым элементом.
Head:=Current;
New(last);
Last^.data:= ’данные во втором элементе списка ’ ;
Last^.next:=nil;
Сurrent^.next:=nil;
Непосредственно перед созданием первого элемента мы присвоили указателю Head значение указателя Current. Это связано с тем, что линейный список должен иметь заголовок. Другими словами, первый элемент списка должен быть отмечен указателем. В противном случае, если значение указателя Current в дальнейшем будет переопределено, то мы навсегда потеряем возможность доступа к данным, хранящимся в первом элементе списка.
Динамическая структура данных предусматривает не только добавление элементов в список, но и их удаление по мере надобности. Самым простым способом удаления элемента из списка является переопределение указателей, связанных с данным элементом (указывающих на него). Однако сам элемент данных при этом продолжает занимать память, хотя доступ к нему будет навсегда утерян. Для корректной работы с динамическими структурами следует освобождать память при удалении элемента структуры. В языке TurboPascal для этого можно использовать функцию Dispose. Покажем, как следует корректно удалить первый элемент нашего списка.
Head:=last;
Dispose(current);

2.2 Деревья и графы
2.2.1 Определение понятий деревьев и графов
Граф — это фигура, которая состоит из вершин и ребер, соединяющих вершины. Например, схема линий метро — это граф. Ребра могут иметь направления, т.е. изображаться стрелочками; такие графы называются ориентированными. Допустим, надо построить схему автомобильного движения по улицам города. Почти во всех городах есть много улиц с односторонним движением. Поэтому такая транспортная схема должна представляться ориентированным графом. Улице с односторонним движением соответствует стрелка, с двусторонним — пара стрелок в противоположных направлениях. Вершины такого графа соответствуют перекресткам и тупикам.
Дерево — это связный граф без циклов. Кроме того, в дереве выделена одна вершина, которая называется корнем дерева. Остальные вершины упорядочиваются по длине пути от корня дерева.
Зафиксируем некоторую вершину X. Вершины, соединенные с X ребрами и расположенные дальше нее от корня дерева, называются детьми или сыновьями вершины X. Сыновья упорядочены слева направо. Вершины, у которых нет сыновей, называются терминальными. Дерево обычно изображают перевернутым, корнем вверх.
Деревья в программировании используются значительно чаще, чем графы. Так, на построении деревьев основаны многие алгоритмы сортировки и поиска. Компиляторы в процессе перевода программы с языка высокого уровня на машинный язык представляют фрагменты программы в виде деревьев, которые называются синтаксическими. Деревья естественно применять всюду, где имеются какие-либо иерархические структуры, т.е. структуры, которые могут вкладываться друг в друга. Примером может служить оглавление книги
Пусть книга состоит из частей, части — из глав, главы — из параграфов. Сама книга представляется корнем дерева, из которого выходят ребра к вершинам, соответствующим частям книги. В свою очередь, из каждой вершины-части книги выходят ребра к вершинам-главам, входящим в эту часть, и так далее. Файловую систему компьютера также можно представить в виде дерева. Вершинам соответствуют каталоги (их также называют директориями или папками) и файлы. Из вершины-каталога выходят ребра к вершинам, соответствующим всем каталогам и файлам, которые содержатся в данном каталоге. Файлы представляются терминальными вершинами дерева. Корню дерева соответствует корневой каталог диска. Программы, осуществляющие работу с файлами, такие, как Norton Commander в системе MS DOS или Проводник Windows, могут изображать файловую систему графически в виде дерева.
Вершина дерева представляется в виде объекта, содержащего ссылки на родительскую вершину и на всех сыновей, а также некоторую дополнительную информацию, зависящую от конкретной задачи. Объект, представляющий вершину дерева, занимает область фиксированного размера, которая обычно размещается в динамической памяти. Число сыновей обычно ограничено, исходя из смысла решаемой задачи. Так, очень часто рассматриваются бинарные деревья, в которых число сыновей у произвольной вершины не превышает двух. Если один или несколько сыновей у вершины отсутствуют, то соответствующие ссылки содержат нулевые значения. Таким образом, у терминальных вершин все ссылки на сыновей нулевые.
При работе с деревьями очень часто используются рекурсивные алгоритмы, т.е. алгоритмы, которые могут вызывать сами себя. При вызове алгоритма ему передается в качестве параметра ссылка на вершину дерева, которая рассматривается как корень поддерева, растущего из этой вершины. Если вершина терминальная, т.е. у нее нет сыновей, то алгоритм просто применяется к данной вершине. Если же у вершины есть сыновья, то он рекурсивно вызывается также для каждого из сыновей. Порядок обхода поддеревьев зависит от сути алгоритма.

2.2.2 Реализация бинарного дерева на языке Turbo Pascal
Для примера реализации бинарного дерева, была разработана программа, использующая несколько алгоритмов работы с данным типом дерева. А именно:
Создание и изменение двоичного дерева;
Нахождение длины дерева;
Обход дерева во внутреннем порядке;
Обход дерева в прямом порядке.
Исходный код программы:
uses crt;
type node=record
name: string;
left, right: pointer;
end;
var
n,l,r,dl,max:integer;
pnt_s,current_s,root: pointer;
pnt,current:^node;
s: string;
procedure node_search (pnt_s:pointer; var current_s:pointer);
{Poisk uzla po soderzhimomu}
var
pnt_n:^node;
begin
pnt_n:=pnt_s; writeln(pnt_n^.name);
if not (pnt_n^.name=s) then
begin
if pnt_n^.left <> nil then
node_search (pnt_n^.left,current_s);
if pnt_n^.right <> nil then
node_search (pnt_n^.right,current_s);
end
else current_s:=pnt_n;
end;
procedure node_list (pnt_s:pointer);
{Vyvod spiska vseh uzlov dereva}
var
pnt_n:^node;
begin
pnt_n:=pnt_s; writeln(pnt_n^.name);
if pnt_n^.left <> nil then node_list (pnt_n^.left);
if pnt_n^.right <> nil then node_list (pnt_n^.right);
end;
procedure node_list1 (pnt_s:pointer);
{Vyvod spiska vseh uzlov dereva}
var
pnt_n:^node;
begin
pnt_n:=pnt_s;
if pnt_n<>nil then
begin
node_list1(pnt_n^.left);
write(‘ ‘,pnt_n^.name);
node_list1(pnt_n^.right);
end;
end;
procedure node_list2 (pnt_s:pointer);
{Vyvod spiska vseh uzlov dereva v pryamom poryadke}
var
pnt_n:^node;
begin
pnt_n:=pnt_s; write(‘ ‘,pnt_n^.name);
if pnt_n^.left <> nil then node_list2 (pnt_n^.left);
if pnt_n^.right <> nil then node_list2 (pnt_n^.right);
end;
procedure node_length (pnt_s:pointer);
var pnt_n,l,r:^node;
begin
pnt_n:=pnt_s;
if (pnt_n^.left<>nil) and (pnt_n^.right<>nil) then
begin
l:=pnt_n^.left;
r:=pnt_n^.right;
node_length(l);
node_length(r);
max:=max+1;
end;
if (pnt_n^.left<>nil) and (pnt_n^.right<>nil) then max:=max-1;
if (pnt_n^.left<>nil) or (pnt_n^.right<>nil) then max:=max+1;
end;
procedure node_dispose (pnt_s:pointer);
{Udalenie uzla i vseh ego potomkov v dereve}
var
pnt_n:^node;
begin
if pnt_s <> nil then
begin
pnt_n:=pnt_s; writeln(pnt_n^.name);
if pnt_n^.left <> nil then
node_dispose (pnt_n^.left);
if pnt_n^.right <> nil then
node_dispose (pnt_n^.right);
dispose(pnt_n);
end
end;
begin
clrscr;
new(current);root:=current;
current^.name:=’root’;
current^.left:=nil;
current^.right:=nil;
repeat
writeln(‘tekuwij uzel -’,current^.name);
writeln(’1-prisvoit imja levomu potomoku’);
writeln(’2-prisvoit imja pravomu potomku’);
writeln(’3-sdelat uzel tekuwim’);
writeln(’4-vyvesti spisok vseh uzlov’);
writeln(’5-udalit potomkov tekuwego uzla’);
writeln(’6-vivesti dliny dereva’);
writeln(’7-obhod dereva v vnytrennem poryadke’);
writeln(’8-vyvesti spisok vseh uzlov v pryamom poryadke’);
writeln(’0-vihod’);
read(n);
if n=1 then
begin {Sozdanie levogo potomka}
if current^.left= nil then new(pnt)
else pnt:= current^.left;
writeln(‘left ?’);
readln;
read(s);
pnt^.name:=s;
pnt^.left:=nil;
pnt^.right:=nil;
current^.left:= pnt;
end;
if n=2 then
begin {Sozdanie pravogo potomka}
if current^.right= nil then new(pnt)
else pnt:= current^.right;
writeln(‘right ?’);
readln;
read(s);
pnt^.name:=s;
pnt^.left:=nil;
pnt^.right:=nil;
current^.right:= pnt;
end;
if n=3 then
begin {Poisk uzla}
writeln(‘name ?’);
readln;
read(s);
current_s:=nil; pnt_s:=root;
node_search (pnt_s, current_s);
if current_s <> nil then current:=current_s;
end;
if n=4 then
begin {Vyvod spiska uzlov}
pnt_s:=root;
node_list(pnt_s);
end;
if n=5 then
begin {Udalenie poddereva}
writeln(‘l,r ?’);
readln;
read(s);
if (s=’l’) then
begin {Udalenie levogo poddereva}
pnt_s:=current^.left;
current^.left:=nil;
node_dispose(pnt_s);
end
else
begin {Udalenie pravogo poddereva}
pnt_s:=current^.right;
current^.right:=nil;
node_dispose(pnt_s);
end;
end;
writeln(current^.name);
if n=6 then
begin {poisk dlini}
max:=1;
pnt_s:=current;
node_length(pnt_s);
writeln(‘dlina dereva ‘,max);
end;
if n=7 then
begin {Vyvod spiska uzlov}
writeln(‘obhod dereva v vnytrennem poryadke:’);
pnt_s:=root;
node_list1(pnt_s);
writeln; writeln;
end;
if n=8 then
begin {Vyvod spiska uzlov v pryamom poryadke}
writeln(‘vivod uzlov v pryamom poryadke’);
pnt_s:=root;
node_list2(pnt_s);
writeln;
writeln;
end;
until n=0;
end.

2.3 Множество
Множество — это структура данных, содержащая конечный набор элементов некоторого типа. Каждый элемент содержится только в одном экземпляре, т.е. разные элементы множества не равны между собой. Элементы множества никак не упорядочены. В множество M можно добавить элемент x, из множества M можно удалить элемент x. Если при добавлении элемента x он уже содержится в множестве M, то ничего не происходит. Аналогично, никакие действия не совершаются при удалении элемента x, когда он не содержится в множестве M. Наконец, для заданного элемента x можно определить, содержится ли он в множестве M. Множество — это потенциально неограниченная структура, оно может содержать любое конечное число элементов.
В программировании довольно часто рассматривают структуру чуть более сложную, чем просто множество: нагруженное множество. Пусть каждый элемент множества содержится в нем вместе с дополнительной информацией, которую называют нагрузкой элемента. При добавлении элемента в множество нужно также указывать нагрузку, которую он несет. В разных языках программирования и в различных стандартных библиотеках такие структуры называют Отображением (Map) или Словарем (Dictionary). Действительно, элементы множества как бы отображаются на нагрузку, которую они несут (заметим, что в математике понятие функции или отображения определяется строго как множество пар; первым элементом каждой пары является конкретное значение аргумента функции, вторым — значение, на которое функция отображает аргумент). В интерпретации Словаря элемент множества — это иностранное слово, нагрузка элемента — это перевод слова на русский язык (разумеется, перевод может включать несколько вариантов, но здесь перевод рассматривается как единый текст).
Все элементы содержатся в нагруженном множестве в одном экземпляре, т.е. разные элементы множества не могут быть равны друг другу. В отличие от самих элементов, их нагрузки могут совпадать (так, различные иностранные слова могут иметь одинаковый перевод). Поэтому иногда элементы нагруженного множества называют ключами, их нагрузки — значениями ключей. Каждый ключ уникален. Принято говорить, что ключи отображаются на их значения.
Наиболее часто применяемая операция в нагруженном множестве — это определение нагрузки для заданного элемента x (значения ключа x). Реализация этой операции включает поиск элемента x в множестве, поэтому эффективность любой реализации множества определяется прежде всего быстротой поиска.

Заключение
В данной курсовой работе были рассмотрены основные динамические структы данных и примеры их реализации на языке Тurbo Pascal.
При создании курсовой работы разработан алгоритм решения задачи с несколькими условиями на самую частую разновидность динамических структур данных – бинарного дерева.
После выполнения курсового проекта, я пришел к выводу, что:
разумное использование динамических структур данных приводит к сокращению объёма памяти, необходимого для работы программы;
динамические данные не требуют объявлений их как данных фиксированного размера;
ряд алгоритмов более эффективен при реализации их с использованием динамических структур. Например, вставка элемента в массив на определенное место требует перемещения части элементов массива. При вставке в середину списка достаточно несколько операторов присваивания.
Данные заключения подтверждают, что динамические струкуры данных в программировании – вещь необходимая, и данный раздел должен знать каждый человек, так или иначе связанный с программированием.

Advertisements

3 комментария

  1. Lesbian love is extraordinarily beautiful. Women intended each other entirely tenderly and sensually, and they urge liking merest passionately. Their girl looks so romantically ‘originator it’s thorough of their pure deep feelings and breakable sensations. That’s why lesbian making out is so passionate, ardent and energizing. And watching lesbian sex is an mythical turn-on damn near seeking everybody.
    If you are out of one’s head about spicy rude lesbians, then this is no more than exchange for you.
    Horny lesbian lovers with their vivid pussies can do in bed so many sundry intense things: they can caress, pressurize easygoing kisses, affect cooperate with sex toys, or like vibrators and dildos. They can include vocalized or anal making love or transmit each other a tribadism or fisting. They can talk squally to each other or personate loose their frizzy fantasies. It’s impossible to record that everything but all that looks very tantalizing, maintain me;)
    Extremely intense & thirsty for a cloth fuck are bulky pudgy lesbians. They’re so sexually abused that you just can’t consistent imagine! But I know you’ll apprehend it certainly when you’ll watch the video I’ve got advance in place of you (under the sun), it’s good it.
    Nearby the way, watchin’ these sharp big loaded lesbians licking their colossal nipples and squat yummy asses can be a tremendous turn-on respecting you;) They’re true goddesses of relations!
    These big fat lesbians are entirely fascinating ‘agent of their extra-large ponderous boobs looking so appetizing, and their oleaginous smooth asses are unreal.
    Sexual intercourse between and aggregate the tall fertility lesbians (as a run-of-the-mill lesbian fucking) covers a destiny of district: tribadism, fisting, cunnilingus, analingus, nipples underline, anal discernment, strap-on sex, genderplay, BDSM, and many, numerous other concupiscent & sexual activities. Beautiful oustandingly oleaginous lesbians are completely potty round having it away! They lift exploring their peckish holes with stupendous dildos, strap-ons and erotic tongues.
    Here is a strange video far two oustandingly abundance lesbians dynamic together in an apartment and you fall ill to note one of their fuck meeting with a consequential dildo, I endorse you to look after it.
    Those big cushy lesbians fondness quick their plump wimp pussies so much but they don’t miss guys. They delight in no man making out and they’re in the end happy. No men – means no men’s brutality and roughness. Just licentious and voluptuous women making their hot alluring sex.
    How do they do that? I’ve got an answer. They lick and suck very strongly each other’s great delectable nipples, they crack at licking and fingering their extremely wet horny pussies, and also speak a ample dildo in support of making a greater satisfaction. In set-up to say a dildo, they use loads of water-based lube and a condom seeking easy clean-up. Then be realized each other with fingers in the forefront entering with the dildo (this everything goes double if lesbians deficiency harsh anally too).
    Look after this couple of gorgeous large corpulence lesbians taking turns ramming each other’s strict cunts with big dildos. It’s so staggering to look how they fall ill frolicsome and place their horny sex games.
    I’m established you’ll like them ‘motivate they’re so cuddly that you’ll disappear without a trace deranged with them and wish to be honesty between them.;)


  2. Не подскажите как и где можно зарабатывать 20-30 $ в сети ? пирамиды не предлагать! Есть начальный капитал 100 $ )) Готов вложиться


  3. Курсовая очень хорошо написана, спасибо.



Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: