Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Kursovaya_rabota_Kirillova_Christina_8K21.doc
Скачиваний:
74
Добавлен:
29.05.2015
Размер:
840.19 Кб
Скачать

6.3. Описание сферы практического применения используемого типа данных.

Хеш-функции применяются для защиты паролей (хорошая перемешиваемость данных), быстрых операций со структурами данных, т.к. хеш-таблицы имеют в основном вычислительную сложность О(1).

    1. Результаты работы программы

Рис 7. Пример работы 5-ой части программы

Количество элементов

Коллизии(хэш сложением)

Коллизии(хэш умножением)

Коллизии(хэш пирсона)

5

9

6

7

10

19

18

17

15

35

36

39

20

54

61

59

25

76

86

83

Таблица 3. Зависимость количества элементов от количества коллизий

Рис.8. Зависимость количества элементов от количества коллизий

Литература

  1. А. Ахо, Дж. Э. Хопкрофт, Д. Ульман Структуры данных и алгоритмы. М., Изд-во "Вильямс", 2000 г.

  2. Д. Кнут. Искусство программирования для ЭВМ. Т.1. Основные алгоритмы. М., "Мир", 1976 г., переиздание - М.,Изд-во "Вильямс", 2000г.

  3. Д. Кнут. Искусство программирования для ЭВМ. Т.3. Сортировка и поиск. М., "Мир", 1978 г., переиздание - М.,Изд-во "Вильямс", 2000 г.

  4. Н. Вирт Алгоритмы + структуры данных = программы. М., "Мир", 1985г.

  5. Н. Вирт Алгоритмы и структуры данных. М., Издат-во "Вильямс", 1998г.

  6. У. Топп, У. Форд. Структуры данных в С++. М., Изд-во "Бином", 2000 г.

Приложение А

namespace Nastya_Kurs_01

{

class Program

{

static void Main(string[] args)

{

LinkedList L = new LinkedList();

L.AddListElement(); L.AddListElement();

Stack S = Program.List_Stack(L);

//Console.WriteLine(S.Pop().Value);

L = Program.Stack_List(S);

Console.WriteLine(L.GetListElement(0).Value);

Console.ReadKey();

}

static Stack List_Stack(LinkedList List)

{

Stack Stack = new Stack(List.GetSize());

for (int i = 0; i < List.GetSize(); i++)

{

Stack.Push(new StackElement(List.GetListElement(i).Value));

}

return Stack;

}

static LinkedList Stack_List(Stack Stack)

{

LinkedList LinkedList = new LinkedList();

int n = Stack.GetSize();

for (int i = 0; i < n; i++)

{

LinkedList.AddNode(Stack.Pop().Value);

}

return LinkedList;

}

}

class ListElement

{

public ListElement(int value)

{

this.value = value;

}

private int value;

public int Value

{

get { return this.value; }

set { this.value = value; }

}

private ListElement next;

public ListElement Next

{

get { return next; }

set { next = value; }

}

}

class LinkedList //Класс связного списка

{

public LinkedList()

{

this.size = 0;

this.head = null;

this.tail = null;

this.thisList = this;

}

private int size;

private ListElement head;

private ListElement tail;

private LinkedList thisList;

public int GetSize() { return size; } // метод получить размер

public void AddListElement() // метод добавить

{

ListElement newElement = new ListElement(size);

this.size++;

if (this.head == null)

{

this.head = newElement;

this.tail = newElement;

}

else

{

this.tail.Next = newElement;

this.tail = newElement;

}

}

public void AddNode(int value)

{

ListElement newElement = new ListElement(value);

this.size++;

if (this.head == null)

{

this.head = newElement;

this.tail = newElement;

}

else

{

this.tail.Next = newElement;

this.tail = newElement;

}

}

public ListElement GetListElement(int number)

{

if (number > this.size)

{

Console.WriteLine("Данного элемента не существует");

return null;

}

else

{

ListElement Element = this.head;

for (int i = 0; i < number; i++)

{

Element = Element.Next;

}

return Element;

}

}

public void DeleteList() // метод удалить лист

{

this.thisList = new LinkedList();

}

}

class StackElement{

public StackElement(int value)

{

this.value = value;

}

private int value;

public int Value

{

get { return this.value; }

set { this.value = value; }

}

}

class Stack

{

private StackElement[] This;

private int topIndex;

public Stack(int size)

{

this.This = new StackElement[size];

}

public int GetSize()

{

return this.This.Length;

}

public bool IsEmpty()

{

return This[0] == null;

}

public void Push(StackElement item)

{

if (This[0] == null)

{

This[0] = item;

topIndex = 0;

}

else

{

topIndex = topIndex + 1; This[topIndex] = item;

}

}

public StackElement Pop()

{

if (IsEmpty())

{

Console.WriteLine("Стек пустой");

return null;

}

else

{

StackElement e = This[topIndex];

if (topIndex != 0)

topIndex = topIndex-1;

return e;

}

}

}

}

Приложение Б

Класс main()

import java.util.Dictionary;

import java.util.Hashtable;

public class part2

{

public static void main (String[] args)

{

String KEY="Интернет магазин"; //ключ, по которому будем искать в тексте

Dictionary<Integer, String> dict=new Hashtable <Integer, String>(); //создаем словарь

String S=new String ("Интернет магазин - это специализированный сайт, пред­лагающий посетителям возможности по приобретению тех или иных товаров или услуг. Идея продавать что-то через Интернет по возрасту сравнима с самим Интернетом. Однако период интенсивного развития онлайновых магазинов связан с появлением веба. Интернет-магазин может быть создан и торговой фирмой, уже имеющей большой опыт продаж в офлайне, и коллективом энтузиастов, решивших сразу начать с онлайна. Онлайновая торговля имеет целый ряд отличительных осо­бенностей, требующих особенного подхода.");

//текст, в котором будет реализован поиск

try

{

file.WriteObject(S);

dict.put(4, "Интернет магазин"); //ключ 4

System.out.println (file.ReadObject().length()+" символов"); //длина текста (=7710)

long t1=System.currentTimeMillis(); //засекаем время начала поиска по ключу

KMP.KnuthMorrisPratt(file.ReadObject(), KEY); //используя чтение из файла, находим по ключу KEY

long t2=System.currentTimeMillis(); //окончание времени поиска по ключу

long t3=System.currentTimeMillis(); //засекаем время начала поиска по ключу

int key=4; //ищем подстроку Интернет магазин

KMP.KnuthMorrisPratt(file.ReadObject(), dict.get(key)); //используя чтение из файла, находим строки по ключам из словаря

long t4=System.currentTimeMillis(); //окончание времени поиска по ключу

System.out.println ("Время поиска по ключу: "+(t2-t1) +" мс"); // вывод результата

System.out.println ("Время поиска со словарем: "+(t4-t3) +" мс"); // вывод результата

}

catch (Exception e) //если файл не найден, бросаем исключение

{

e.getMessage();

}

}

}

Класс KMP, в котором описан алгоритм поиска ключа

public class KMP

{

public static int KnuthMorrisPratt (String where, String what)

{

int n=where.length(); //длина строки, в которой происходит поиск

int m=what.length(); //длина подстроки

//формирование таблицы сдвигов

int[] table=new int [m]; //таблица сдвигов (массив)

table[0]=0; //значение первого элемента =0

int shift=0; //сдвиг равен 0

for (int q=1; q<m; q++)//проходим по количеству букв, которое находится в ключе (подстроке)

{

while (shift > 0 && (what.charAt(shift) != what.charAt(q))) //ищем совпадающее начало кусочка текста и подстроки

shift = table[shift-1]; //меняем сдвиг

if (what.charAt(shift)==what.charAt(q)) shift++; //считаем количество вхождений символов

table[q]=shift; //записываем значения в таблицу - создаем префиксную функцию

}

//поиск с использованием таблицы сдвигов

shift=0; //сдвиг равен 0

for (int i=0; i<n; i++) //прохождение по всему тексту

{

while (shift>0 && what.charAt(shift)!=where.charAt(i)) //если первые символы не совпали, то

shift=table[shift-1]; //двигаем текст на максимально возможное знаечение

if (what.charAt(shift)==where.charAt(i)) //если символы совпадают, то

shift++; //увеличиваем количество совпавших символов

if (shift==m) //если длина совпадения равна длине подстроки

return i-m+1; //подстрока найдена

}

return -1; //если ничего не найдено, возвращаем некорректное значение

}

}

Класс file, позволяющий создать и использовать файл

import java.io.*;

public class file //создание - чтение файла

{

public static void WriteObject (String S) throws IOException //создание файла, на вход идет строканашем случае текст)

{

FileOutputStream fileOutput=new FileOutputStream ("file.dat"); //открываем файловый поток

ObjectOutputStream objectOutput=new ObjectOutputStream (fileOutput); //открываем поток, в который будем записывать объектнашем случае текст)

objectOutput.writeObject(S); //записываем в файл строку

fileOutput.close(); //закрываем поток

objectOutput.close(); //закрываем поток

}

public static String ReadObject() throws IOException, ClassNotFoundException //извлечение файла

{

FileInputStream fileInput=new FileInputStream ("file.dat"); //открываем файловый поток

ObjectInputStream objectInput=new ObjectInputStream(fileInput); //открываем поток, из которого будем читать объектнашем слкчае текст)

String s=(String) objectInput.readObject(); //создаем переменную, в которую записываем текст

fileInput.close(); //закрываем поток

objectInput.close(); //закрываем поток

return s; //возвращаем строку (текст)

}

}

Приложение В

using System;

using System.Diagnostics;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace PersonnelDepartmentApp {

public class Sorting {

public void swap(int[] arr, int i, int j) {

int t = arr[i];

arr[i] = arr[j];

arr[j] = t;

}

public void swap(int[] arr, int i) {

int temp;

temp = arr[i];

arr[i] = arr[i - 1];

arr[i - 1] = temp;

}

public int maxValue(int[] arr) {

int maxValue = int.MinValue;

for (int i = 0; i < arr.Length; i++) {

if (arr[i] > maxValue) {

maxValue = arr[i];

}

}

return maxValue;

}

public int[] selectionSort(int[] mass) {

int[] a = (int[]) mass.Clone();

int len = a.Length;

for (int i = 0; i < len - 1; i++) {

int min = i;

for(int j = i + 1; j < len; j++) {

if(a[j] < a[min]) {

min = j;

}

}

if(min != i) {

int t = a[i];

a[i] = a[min];

a[min] = t;

}

}

return a;

}

public int[] bubbleSort(int[] mass){

int[] arr = (int[]) mass.Clone();

for(int i = arr.Length-1 ; i > 0 ; i--){

for(int j = 0 ; j < i ; j++){

if( arr[j] > arr[j+1] )

swap(arr, j, j+1);

}

}

return arr;

}

public int[] gnomeSort(int[] mass) {

int[] a = (int[]) mass.Clone();

int size = a.Length, i = 1,j = 2;

while (i < size) {

//для сортировки по убыванию поменяйте знак сравнения на <

if (a[i - 1] > a[i]) {

i = j;

j = j + 1;

} else {

swap(a, i);

i = i - 1;

if (i == 0) {

i = j;

j = j + 1;

}

}

}

return a;

}

public int[] insertionSort (int[] mass) {

int[] m = (int[]) mass.Clone();

int t, i, j;

for (i = 0; i < m.Length; i++) {

t = m[i];

for ( j=i-1; j>=0 && m[j] > t; j--)

m[j+1] = m[j];

m[j+1] = t;

}

return m;

}

public void merge(int[] Mas, int left, int right, int medium) {

int j = left;

int k = medium + 1;

int count = right - left + 1;

if (count <= 1)

return;

int[] TmpMas = new int[count];

for (int i = 0; i < count; i++) {

if (j <= medium && k <= right) {

if (Mas[j] < Mas[k])

TmpMas[i] = Mas[j++];

else

TmpMas[i] = Mas[k++];

} else {

if (j <= medium)

TmpMas[i] = Mas[j++];

else

TmpMas[i] = Mas[k++];

}

}

j = 0;

for (int i = left; i <= right; i++) {

Mas[i] = TmpMas[j++];

}

}

public void mergeSort(int[] a, int l, int r) {

int m;

// Условие выхода из рекурсии

if(l >= r)

return;

m = (l + r) / 2;

// Рекурсивная сортировка полученных массивов

mergeSort(a, l, m);

mergeSort(a, m + 1, r);

merge(a, l, r, m);

}

public int[] bucketSort(int[] mass) {

int[] items = new int[mass.Length];

// Предварительная проверка элементов исходного массива

if (items == null || items.Length < 2) {

return mass;

}

int maxValue = items[0];

int minValue = items[0];

for (int i = 1; i < items.Length; i++) {

if (items[i] > maxValue)

maxValue = items[i];

if (items[i] < minValue)

minValue = items[i];

}

List<int>[] bucket = new List<int>[maxValue - minValue + 1];

for (int i = 0; i < bucket.Length; i++) {

bucket[i] = new List<int>();

}

// Занесение значений в пакеты

for (int i = 0; i < items.Length; i++) {

bucket[items[i] - minValue].Add(items[i]);

}

int position = 0;

for (int i = 0; i < bucket.Length; i++)

{

if (bucket[i].Count > 0)

{

for (int j = 0; j < bucket[i].Count; j++)

{

items[position] = (int) bucket[i][j];

position++;

}

}

}

return items;

}

public int[] shellSort(int[] mass) {

int[] a = (int[]) mass.Clone();

int i, j, k, h, m=0, b=a.Length;

int[] d = { 1, 4, 10, 23, 57, 145, 356, 911, 1968, 4711, 11969, 27901,

84801, 213331, 543749, 1355339, 3501671, 8810089, 21521774,

58548857, 157840433, 410151271, 1131376761, 2147483647 };

while (d[m] < b) {

++m;

}

while (--m >= 0) {

k = d[m];

for (i=k; i<b; i++) { // k-сортировка

j=i;

h=a[i];

while ((j >= k) && (a[j-k] > h)) {

a[j]=a[j-k];

j = j-k;

}

a[j] = h;

}

}

return a;

}

public int[] heapSort(int[] mass) {

int[] a = (int[]) mass.Clone();

int n = a.Length, i, sh = 0, b = 0;

while (true) {

b = 0;

for (i = 0; i < n; ++i) {

if (i*2 + 2 + sh < n) {

if (a[i+sh] > a[i*2 + 1 + sh] || a[i + sh] > a[i*2 + 2 + sh]) {

if (a[i*2+1+sh] < a[i*2+2+sh]) {

int t = a[i+sh];

a[i+sh] = a[i*2+1+sh];

a[i*2+1+sh] = t;

b = 1;

} else if (a[i*2+2+sh] < a[i*2+1+sh]) {

int t = a[i+sh];

a[i+sh] = a[i*2+2+sh];

a[i*2+2+sh] = t;

b = 1;

}

}

} else if (i * 2 + 1 + sh < n) {

if (a[i+sh] > a[i*2+1+sh]) {

int t = a[i+sh];

a[i+sh] = a[i*2+1+sh];

a[i*2+1+sh] = t;

b=1;

}

}

}

if (b == 0) {

sh++;

}

if (sh+2==n)

break;

}

return a;

}

public int partition (int[] array, int start, int end) {

int marker = start;

for ( int i = start; i <= end; i++ ) {

if ( array[i] <= array[end] ) {

int temp = array[marker];

array[marker] = array[i];

array[i] = temp;

marker += 1;

}

}

return marker - 1;

}

public void quickSort (int[] array, int start, int end) {

int pivot;

if ( start >= end ) {

return;

}

pivot = partition (array, start, end);

quickSort (array, start, pivot-1);

quickSort (array, pivot+1, end);

}

public void stoogeSort(int[] item, int left,int right) {

int tmp, k;

if(item[left] > item[right]) {

tmp=item[left];

item[left]=item[right];

item[right]=tmp;

}

if((left+1)>=right)

return;

k = (int) ((right - left + 1) / 3);

stoogeSort(item,left, right-k);

stoogeSort(item, left+k, right);

stoogeSort(item, left, right-k);

}

public void executeTest(int[] quantity) {

Random random = new Random();

Sorting sorter = new Sorting();

for (int i = 0; i < quantity.Length; i++) {

Console.WriteLine("Отчёт по массиву из " + quantity[i] + " элементов:");

int[] mass = new int[quantity[i]];

for (int j = 0; j < quantity[i]; j++) {

mass[j] = random.Next(10000);

}

long start = 0, end = 0;

Console.Write("Сортировка выбором:");

try {

start = Stopwatch.GetTimestamp();

sorter.selectionSort(mass);

end = Stopwatch.GetTimestamp();

Console.Write((end - start) + " нс\n");

} catch (Exception e) {

Console.Write(e.Message + "\n");

Console.WriteLine(e.StackTrace);

}

Console.Write("Сортировка простыми обменами, сортировка пузырькa:");

try {

start = Stopwatch.GetTimestamp();

sorter.bubbleSort(mass);

end = Stopwatch.GetTimestamp();

Console.Write((end - start) + " нс\n");

} catch (Exception e) {

Console.Write(e.Message + "\n");

Console.WriteLine(e.StackTrace);

}

Console.Write("Гномья сортировка:");

try {

start = Stopwatch.GetTimestamp();

sorter.gnomeSort(mass);

end = Stopwatch.GetTimestamp();

Console.Write((end - start) + " нс\n");

} catch (Exception e) {

Console.Write(e.Message + "\n");

Console.WriteLine(e.StackTrace);

}

Console.Write("Сортировка вставками:");

try {

start = Stopwatch.GetTimestamp();

sorter.insertionSort(mass);

end = Stopwatch.GetTimestamp();

Console.Write((end - start) + " нс\n");

} catch (Exception e) {

Console.Write(e.Message + "\n");

Console.WriteLine(e.StackTrace);

}

Console.Write("Сортировка слиянием:");

try {

start = Stopwatch.GetTimestamp();

sorter.mergeSort((int[]) mass.Clone(), 0, mass.Length - 1);

end = Stopwatch.GetTimestamp();

Console.Write((end - start) + " нс\n");

} catch (Exception e) {

Console.Write(e.Message + "\n");

Console.WriteLine(e.StackTrace);

}

Console.Write("Блочная сортировка:");

try {

start = Stopwatch.GetTimestamp();

sorter.bucketSort(mass);

end = Stopwatch.GetTimestamp();

Console.Write((end - start) + " нс\n");

} catch (Exception e) {

Console.Write(e.Message + "\n");

Console.WriteLine(e.StackTrace);

}

Console.Write("Сортировка Шелла:");

try {

start = Stopwatch.GetTimestamp();

sorter.shellSort(mass);

end = Stopwatch.GetTimestamp();

Console.Write((end - start) + " нс\n");

} catch (Exception e) {

Console.Write(e.Message + "\n");

Console.WriteLine(e.StackTrace);

}

Console.Write("Пирамидальная сортировка:");

try {

start = Stopwatch.GetTimestamp();

sorter.heapSort(mass);

end = Stopwatch.GetTimestamp();

Console.Write((end - start) + " нс\n");

} catch (Exception e) {

Console.Write(e.Message + "\n");

Console.WriteLine(e.StackTrace);

}

Console.Write("Быстрая сортировка:");

try {

start = Stopwatch.GetTimestamp();

sorter.quickSort((int[]) mass.Clone(), 0, mass.Length - 1);

end = Stopwatch.GetTimestamp();

Console.Write((end - start) + " нс\n");

} catch (Exception e) {

Console.Write(e.Message + "\n");

Console.WriteLine(e.StackTrace);

}

Console.Write("Stooge Sort:");

try {

start = Stopwatch.GetTimestamp();

sorter.stoogeSort((int[]) mass.Clone(), 0, mass.Length - 1);

end = Stopwatch.GetTimestamp();

Console.Write((end - start) + " нс\n");

} catch (Exception e) {

Console.Write(e.Message + "\n");

Console.WriteLine(e.StackTrace);

}

}

}

}

}

\

Приложение Г

Класс main()

import java.util.Random;

public class main

{

public static void main(String[] args)

{

Random r=new Random(); //для случайных значений ключей и значений ключей

RedBlackBST<Integer, Integer> st = new RedBlackBST<Integer, Integer>(); //создание экземпляра дерева

for (int i=0; i<10; i++) //10 узлов дерева (пример)

st.put(r.nextInt(100), r.nextInt(100)); //добавление узлов в дерево

for (Integer s : st.keys()) //среди всех ключей

System.out.println("Ключ: "+s + "; значение: " + st.get(s)); //вывести информацию по ключу (ключ-значение)

System.out.println("Содержит ключ 34: "+st.contains(34));

System.out.println("Размер дерева: "+st.size());

System.out.println("Высота дерева: "+st.height());

System.out.println("Получить значение ключа 56: "+st.get(56));

System.out.println("Максимальный ключ: "+st.max());

}

}

Класс RedBlackBST (Red-Black Binary Search Tree)

import java.util.LinkedList;

import java.util.NoSuchElementException;

import java.util.Queue;

public class RedBlackBST<Key extends Comparable<Key>, Value> //класс красно-черного дерева

{

private static final boolean RED = true; //красный узел - true

private static final boolean BLACK = false;//черный узел - false

private Node root; // корень дерева

private class Node //класс узлов дерева

{

private Key key; // ключ узла

private Value val; // значение ключа

private Node left, right; // ссылки на левый и правый элементы

private boolean color; // атрибут цвет

private int N; // счетчик

public Node(Key key, Value val, boolean color, int N) //конструктор

{

this.key = key;

this.val = val;

this.color = color;

this.N = N;

}

}

private boolean isRed(Node x) //является ли узел красным

{

if (x == null) //если в дереве ничего нет

return false; //возвращаем false

return (x.color == RED); //является ли узел красным

}

private int size(Node x) //число узлов в дереве

{

if (x == null) //если корень пустой,

return 0; //то вернуть 0

return x.N; //вернуть число узлов

}

public int size() //число узлов (ключ-значение)

{

return size(root); //вызов метода, начиная с корня

}

public Key search (Key key)

{

return search(root, key);

}

private Key search (Node current, Key key)

{

if (current == null)

return null;

if (current.key == key)

return current.key;

return search(key < current.key ? current.left : current.right, key);

}

public boolean isEmpty() //является ли дерево пустым

{

return root == null; //вернуть true или false

}

public Value get(Key key) //вернуть значение по ключу

{

return get(root, key); //вызов метода с передачей дерева в нем

}

private Value get(Node x, Key key) //получение значение

{

while (x != null) //пока узел не будет пустым,

{

int cmp = key.compareTo(x.key); //сравниваем значение ключа с текущим узлом

if (cmp < 0) x = x.left; //если значение меньше, идем влево

else

if (cmp > 0) x = x.right; //иначе если значение больше, идем вправо

else return x.val; //иначе вернуть искомое значение

}

return null; //если ничего не найдено, вернуть null

}

public boolean contains(Key key) //содержит ли дерево такой ключ

{

return (get(key) != null); //вернуть результат через метод get (Key key)

}

public void put(Key key, Value val) //вставка узла с ключом и значением

{

root = put(root, key, val); //создание узла с передачей в другой метод (private)

root.color = BLACK; //окрашивание корня в черный цвет (для того, чтобы мы могли далее добавлять узлы любого цвета)

}

private Node put(Node h, Key key, Value val)

{

if (h == null) //если узел пустой,

return new Node(key, val, RED, 1); //то окрашиваем его в красный

int cmp = key.compareTo(h.key); //сравниваем вставляемый узел с текущим

if (cmp < 0) h.left = put(h.left, key, val); //если меньше, то вызываем этот метод рекурсивно для вставки слева

else

if (cmp > 0) h.right = put(h.right, key, val); //иначе вызываем метод рекурсивно для вставки справа

else h.val = val; //иначе перезаписываем это значение

if (isRed(h.right) && !isRed(h.left)) h = rotateLeft(h); //если узел справа красный и узел слева черный, то вызываем левое вращение узла

if (isRed(h.left) && isRed(h.left.left)) h = rotateRight(h); //если узел А слева красный и левый узел В узла А красный, то вызываем правое вращение

if (isRed(h.left) && isRed(h.right)) flipColors(h); //если узел слева красный и узел справа красный, то меняем их цвета на черные (красные узлы имеют только черные дочерние узлы)

h.N = size(h.left) + size(h.right) + 1; //считаем общее количество узлов

return h; //возвращаем узел

}

public void deleteMin() //удаление минимального элемента

{

if (isEmpty()) throw new NoSuchElementException("BST underflow"); //если дерево пустое, выбросить exception

if (!isRed(root.left) && !isRed(root.right)) //если оба дочерних узла корня черные,

root.color = RED; //то перекрасить корень в красный

root = deleteMin(root); //вызов метода для корня

if (!isEmpty()) root.color = BLACK; //если дерево не пустое, то перекрасить корень в черный

}

private Node deleteMin(Node h) //удаление минимального элемента, начиная с корня h

{

if (h.left == null)//если элемента, меньшего корня нет, то

return null; //возвратить null

if (!isRed(h.left) && !isRed(h.left.left)) //если узел слева черный и его дочерний узел слева черный, то

h = moveRedLeft(h); //перекрасить в красный цвет дочерний узел слева

h.left = deleteMin(h.left); //вызываем этот метод рекурсивно для узла слева

return balance(h); //вернуть узел в сбалансированном дереве

}

public void delete(Key key) //удаление по ключу

{

if (!contains(key)) //если такого ключа не существует, то

{

System.err.println("symbol table does not contain " + key); //написать сообщение пользователю

return; //вернуть

}

if (!isRed(root.left) && !isRed(root.right)) //если оба дочерних узла корня черные, то

root.color = RED; //перекрасить корень в красный

root = delete(root, key); //вызов метода удаления, начиная с корня

if (!isEmpty()) root.color = BLACK; //если дерево не пустое, покрасить корень в черный

}

private Node delete(Node h, Key key) //удаление узла с ключом key, начиная с корня h

{

if (key.compareTo(h.key) < 0) //если ключ этого узла меньше ключа корня, то

{

if (!isRed(h.left) && !isRed(h.left.left)) //если узел А слева черный и левый узел В узла А черный,

h = moveRedLeft(h); //то перекрашиваем в красный цвет дочерний узел слева

h.left = delete(h.left, key); //вызываем рекурсивно этот метод для узла слева

}

else

{

if (isRed(h.left)) //если узел слева красный, то

h = rotateRight(h); //вызываем правое вращение

if (key.compareTo(h.key) == 0 && (h.right == null)) //если значение ключа искомого узла равно значению ключа текущего узла и правый узел пустой, то

return null; //ничего не возвращать

if (!isRed(h.right) && !isRed(h.right.left)) //если узел А справа и левый узел узла А черные, то

h = moveRedRight(h); //перекрасить в красный цвет дочерний узел справа

if (key.compareTo(h.key) == 0) //если значение ключа искомого узла равно значению ключа текущего узла, то

{

Node x = min(h.right); //находим минимальный узел справа

h.key = x.key; //переприсваиваем удаленному узлу ключ минимального

h.val = x.val; //переприсваиваем удаленному узлу значение минимального

h.right = deleteMin(h.right); //удаляем минимальный узел

}

else h.right = delete(h.right, key); //иначе сделать то же самое для узла справа

}

return balance(h); //вернуть сбалансированное дерево

}

private Node rotateRight(Node h) //правое вращение узла h

{

Node x = h.left; //текущему узлу присваиваем левый узел узла h

h.left = x.right; //левому узлу h присваиваем правый узел текущего узла

x.right = h; //правому узлу текущего узла присваиваем узел h

x.color = x.right.color; //перекрашиваем текущий узел в цвет узла справа

x.right.color = RED; //узлу справа текущего узла х присваиваем красный цвет

x.N = h.N; //переприсваиваем значение числа узлов

h.N = size(h.left) + size(h.right) + 1; //считаем количество узлов, начиная с h

return x; //возвращаем текущий узел

}

private Node rotateLeft(Node h) //левое вращение

{

Node x = h.right; //текущему узлу присваиваем правый узел узла h

h.right = x.left; //правому узлу h присваиваем левый узел текущего узла

x.left = h; //левому узлу текущего узла присваиваем узел h

x.color = x.left.color; //перекрашиваем текущий узел в цвет узла слева

x.left.color = RED; //узлу слева текущего узла х присваиваем красный цвет

x.N = h.N; //переприсваиваем значение числа узлов

h.N = size(h.left) + size(h.right) + 1; //считаем количество узлов, начиная с h

return x; //возвращаем текущий узел

}

private void flipColors(Node h) //перекрашивание узлов

{

h.color = !h.color; //меняем цвет текущего узла на противоположный

h.left.color = !h.left.color; //меняем цвет левого узла на противоположный

h.right.color = !h.right.color; //меняем цвет правого узла на противоположный

}

private Node moveRedLeft(Node h) //перекрасить в красный цвет дочерний узел слева

{

flipColors(h); //перекрасить узел h и его дочерние узлы

if (isRed(h.right.left)) //если левый узел правого узла h красный, то

{

h.right = rotateRight(h.right); //правый узел - результат правого вращения

h = rotateLeft(h); //узел - результат левого вращения

}

return h; //вернуть узел

}

// Предполагая, что узел h красный и правый узел и левый узел правого узла черные, сделать правый узел h или один из дочерних узлов красным

private Node moveRedRight(Node h) //перекрасить в красный цвет дочерний узел справа

{

flipColors(h); //перекрасить узел h и его дочерние узлы

if (isRed(h.left.left)) //если левый узел левого узла h красный, то

h = rotateRight(h); //узел - результат правого вращения

return h; //вернуть узел

}

private Node balance(Node h) //восстановление красно-черного дерева

{

if (isRed(h.right)) h = rotateLeft(h); //если узел справа красный, то левое вращение

if (isRed(h.left) && isRed(h.left.left)) h = rotateRight(h); //если узел А слева и левый узел В узла А красные, то правое вращение

if (isRed(h.left) && isRed(h.right)) flipColors(h); //если оба дочерних узла красные, то перекрасить узлы

h.N = size(h.left) + size(h.right) + 1; //посчитать количество узлов

return h; //вернуть узел

}

public int height() //высота дерева

{

return height(root); //вызов метода с ссылкой на корень дерева

}

private int height(Node x) //метод вычисления высоты дерева

{

if (x == null) //если корень пустой, то

return -1; //вернуть -1

return 1 + Math.max(height(x.left), height(x.right)); //вернуть 1 + (максимальная высота из левого и правого поддеревьев)

}

public Key min() //минимальное значение ключа

{

if (isEmpty()) //если дерево пустое, вернуть

return null; //null

return min(root).key; //вызвать метод поиска минимального ключа

}

private Node min(Node x) //поиск минимального ключа

{

if (x.left == null) //если узла слева нет, то

return x; //вернуть текущий узел

else //иначе

return min(x.left); //вызываем рекурсивно метод для узла слева

}

public Key max() //максимальное значение ключа

{

if (isEmpty()) return null; //если дерево пустое, вернуть null

return max(root).key; //вызвать метод поиска максимального ключа

}

private Node max(Node x) //поиск максимального ключа

{

if (x.right == null) return x; //если узла справа нет, то вернуть текущий узел

else return max(x.right); //иначе вызвать рекурсивно этот метод для узла справа

}

public int rank(Key key) //количество ключей, меньших или = заданному

{

return rank(key, root); //вызов метода

}

private int rank(Key key, Node x) //количество ключей, меньших или = заданному, начиная с х

{

if (x == null) return 0; //если узел пустой, вернуть 0

int cmp = key.compareTo(x.key); //сравнение ключа текущего узла и заданного ключа

if (cmp < 0) return rank(key, x.left); //если заданный меньше, то вызываем рекурсивно метод для левого узла

else if (cmp > 0) return 1 + size(x.left) + rank(key, x.right); //иначе если заданный больше, то вызываем рекурсивно метод для правого узла

else return size(x.left); //иначе возвращаем количество

}

public Iterable<Key> keys() //все ключи

{

return keys(min(), max()); //вернуть все ключи

}

public Iterable<Key> keys(Key lo, Key hi) //все ключи

{

Queue<Key> queue = new LinkedList <Key>(); //очередь для добавления ключей в порядке возрастания

keys(root, queue, lo, hi); //добавление ключей в очередь

return queue; //вернуть очередь

}

public void keys(Node x, Queue<Key> queue, Key lo, Key hi) //добавление ключей в очередь, начиная с узла х, между минимальным и максимальным

{

if (x == null) return; //если узел пустой, выйти из метода

int cmplo = lo.compareTo(x.key); //сравнение с меньшим

int cmphi = hi.compareTo(x.key); //сравнение с большим

if (cmplo < 0) keys(x.left, queue, lo, hi); //если меньше меньшего, выполнить рекурсивно метод для левого узла

if (cmplo <= 0 && cmphi >= 0) queue.add(x.key); //если меньше или = меньшему или больше или = большему, то просто добавить в очередь

if (cmphi > 0) keys(x.right, queue, lo, hi); //если больше большего, то выполнить рекурсивно метод для правого узла

}

public int size(Key lo, Key hi) //количество ключей между меньшим и большим ключами

{

if (lo.compareTo(hi) > 0) return 0; //если разница между наименьшим и наибольшим больше 0, то вернуть 0

if (contains(hi)) return rank(hi) - rank(lo) + 1; //если дерево содержит наибольший, то вернуть количество ключей между наибольшим и наименьшим +1

else return rank(hi) - rank(lo); //иначе вернуть количество ключей между наибольшим и наименьшим

}

private boolean isBalanced(Node x, int black) //сбалансированно ли дерево

{

if (x == null) return black == 0; //если текущая узел пустой, вернуть 0 черных узлов

if (!isRed(x)) black++; //если узел черный, пересчитать черные узлы

return isBalanced(x.left, black) && isBalanced(x.right, black); //вернуть, сбалансированно ли дерево справа и слева

}

}

Приложение Д

Класс main()

import java.util.Scanner;

public class main

{

public static void main (String args[])

{

Scanner scan = new Scanner(System.in); //создание объекта для ввода с клавиатуры

System.out.println("Тестирование хеш-таблицы\n\n");

System.out.println("Введите размер таблицы");

HashTable ht = new HashTable(scan.nextInt()); //создание экземпляра таблицы

char ch; //символ при вводе "n" или "у"

do //действия при нажатии "y" (да)

{

System.out.println("\nОперации хеш-таблицы\n");

System.out.println("1. Вставка ");

System.out.println("2. Удаление");

System.out.println("3. Найти по ключу");

int choice = scan.nextInt(); //считывание номера операции

switch (choice) //варианты:

{

case 1 : //при нажатии "1"

System.out.println("Введите ключ и значение");

ht.insert(scan.next(), scan.nextInt()); //считывание ключа и значения

break; //прерывание действия

case 2 : //при нажатии "2"

System.out.println("Введите ключ");

ht.remove(scan.next()); //удаление по ключу

break; //прерывание

case 3 : //при нажатии "3"

System.out.println("Введите ключ");

System.out.println("Значение искомого ключа = "+ ht.get(scan.next())); //вывод значения ключа

break; //прерывание

default : //при вводе некорректного символа

System.out.println("Ошибка \n ");

break; //прерывание

}

ht.printHashTable(); //отображение хеш-таблицы

System.out.println("\nХотите продолжить? (Введите y или n)\n");

ch = scan.next().charAt(0); //чтение символа у или n

}

while (ch == 'Y'|| ch == 'y'); //условие при выполнении действий с хеш-таблицей

}

}

Класс HashTable

public class HashTable //класс хеш-таблицы

{

private int TABLE_SIZE; //размер таблицы для создания объекта HashEntry

private int size; //размер таблицы

private HashEntry[] table; //таблица

private int primeSize; //размер таблицы (для вычисления хеш-функции)

public HashTable(int ts) //конструктор

{

size = 0;

TABLE_SIZE = ts;

table = new HashEntry[TABLE_SIZE];

for (int i = 0; i < TABLE_SIZE; i++)

table[i] = null;

primeSize = getPrime();

}

public int size()

{

return this.size;

}

public int getPrime() //получить число, меньшее, чем размер таблицы для вычисления функции myhash2

{

for (int i = TABLE_SIZE - 1; i >= 1; i--) //рассматриваем весь размер таблицы

{

int fact = 0; //счетчик

for (int j = 2; j <= (int) Math.sqrt(i); j++) //рассматриваем числа от 2 до корень(i)

if (i % j == 0)//если от деления нет остатка, то

fact++; //прибавляем 1

if (fact == 0) //если в счетчике ничего не было,

return i; //вернуть размер таблицы-1

}

return 3; //вернуть 3

}

public int get(String key) //получить значение по ключу

{

int hash1 = myhash1( key ); //вычисление функции myhash1

int hash2 = myhash2( key ); //вычисление функции myhash2

while (table[hash1] != null) //пока просмотр таблицы не окончится

{

if (table[hash1].key.equals(key)) //если значение ключа равно искомому,

return table[hash1].value; //возвратить значение найденного ключа

hash1 += hash2; //вычисляем хеш-функцию

hash1 %= TABLE_SIZE; //вычисляем хеш-значение

}

return -1; //ключ не найден

}

public void insert(String key, int value) //добавление в таблицу пары ключ-значение

{

if (size == TABLE_SIZE) //если размер таблицы равен уже заданному размеру, то

{

System.out.println("Таблица заполнена");

return;

}

int hash1 = myhash1( key ); //вычисление функции myhash1

int hash2 = myhash2( key ); //вычисление функции myhash2

while (table[hash1] != null) //пока просмотр таблицы не окончится

{

hash1 += hash2; //вычисляем хеш-функцию

hash1 %= TABLE_SIZE; //вычисляем хеш-значение

}

table[hash1] = new HashEntry(key, value); //создаем новое значение таблицы

size++; //увеличиваем размер на 1

}

public void remove(String key) //удаление по ключу

{

int hash1 = myhash1( key ); //вычисление функции myhash1

int hash2 = myhash2( key ); //вычисление функции myhash2

while (table[hash1] != null && !table[hash1].key.equals(key)) //пока просмотр таблицы не окончится и значение ключа не равно искомому,

{

hash1 += hash2; //вычисляем хеш-функцию

hash1 %= TABLE_SIZE; //вычисляем хеш-значение

}

table[hash1] = null; //очищаем значение таблицы

size--; //уменьшаем размер таблицы на 1

}

private int myhash1(String x ) //хеш-функция, которая дает хеш-значение для ключа (String)

{

int hashVal = x.hashCode( ); //получение хеш-кода

hashVal %= TABLE_SIZE; //хеш-значение

if (hashVal < 0) //если хеш-значение меньше нуля, то

hashVal += TABLE_SIZE; //прибавим к нему размер таблицы

return hashVal; //вернуть хеш-значение

}

private int myhash2(String x ) //хеш-функция для двойного хеширования

{

int hashVal = x.hashCode( ); //получение хеш-кода

hashVal %= TABLE_SIZE; //хеш-значение

if (hashVal < 0) //если хеш-значение меньше нуля, то

hashVal += TABLE_SIZE; //прибавим к нему размер таблицы

return primeSize - hashVal % primeSize; //вернуть хеш-значение (размер таблицы - остаток от деления хеш-значения на размер таблицы)

}

private int hashFunc2 (String key) //хеш-функция умножением

{

float f; //индекс в таблице (массиве)

float A=(float) 0.6180339887499; //любое число в диапазоне 0..1

int sss=key.length(); //получение длины ключа

f = sss * A; //умножить ключ на константу А=(sqrt(5)-1)/2

f = f - (int) f; // взять дробную часть

return (int) (size*f); // возвратить число в диапазоне 0...size-1

}

private int hashFunc3 (String key) //хеш-функция делением с остатком

{

int len=key.length(); //получение длины ключа

int j=len%TABLE_SIZE; //остаток от деления на размер таблицы

return j; //вернуть значение

}

public void printHashTable() //вывод хеш-таблицы

{

System.out.println("\nХеш-таблица");

for (int i = 0; i < TABLE_SIZE; i++) //рассматриваем весь размер таблицы

if (table[i] != null) //если таблица не пуста, то

System.out.println(table[i].key +" "+table[i].value); // вывести ключ и значение ключа

}

}

Класс HashEntry

public class HashEntry //класс для создания таблицы

{

String key; //ключ

int value; //значение ключа

public HashEntry(String key, int value) //конструктор при создании таблицы

{

this.key = key;

this.value = value;

}

}

49

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]