Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Бинарный поиск, Бинарный поиск 
V
    Опции темы
Agarwaen
Дата 4.1.2007, 14:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 4.1.2007

Репутация: нет
Всего: нет



Задача: реализовать поиск в строке методом деления пополам. Строка состоит из символов и вводится пользователем. Ключ для поиска - символ. Необходимо определить порядковые номера его вхождений в искомую строку.

Добавлено @ 14:28 
Общая идея такая. Разбиваем строку на отдельные символы. Создаём список в котором каждому символу присваиваем список с номерами его позиций в строке. Затем сортируем список по порядку расположения символов в таблице ASCII (напимер методом пузырька). Затем операция поиска. В этом списке сравниваем элемент в центре с ключём. Если равен, то ответ найден. Если больше продолжаем поиск в списке справа. Если меньше - слева.
PM MAIL   Вверх
Agarwaen
Дата 4.1.2007, 22:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 4.1.2007

Репутация: нет
Всего: нет



Чёто я не понял, есть в Lisp способ сравнить два символа (например: а и b) кроме как на равенство? < и > не работают. 
PM MAIL   Вверх
linuxfan
Дата 5.1.2007, 00:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 11.10.2006

Репутация: 1
Всего: 1



А как насчет char> или char< ? smile
PM MAIL   Вверх
Agarwaen
Дата 5.1.2007, 00:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 4.1.2007

Репутация: нет
Всего: нет



 Действительно работает. Странно, сколько в книгах не рылся не видел такого предикаты. Эх, где бы найти список встроенных функций. Большое спасибо. А то я уже в Visual Lisp полез.
PM MAIL   Вверх
adejneka
Дата 5.1.2007, 08:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 8.7.2005
Где: Москва, Россия

Репутация: 9
Всего: 11



Что Вы называете "символом"? Если CHARACTER, то CHAR< или CHAR-LESSP, если SYMBOL, то STRING< или STRING-LESSP.
Ссылка на стандарт ANSI Common Lisp, переведенный в формат HTML: http://www.lispworks.com/documentation/HyperSpec/index.html
PM MAIL   Вверх
Agarwaen
Дата 5.1.2007, 16:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 4.1.2007

Репутация: нет
Всего: нет



  Первую часть сделал: построение и сортировка ассоциированного списка. 
Код

(defun INSERT (n list)
  (cond
   ((null list) (cons n nil))
   ((CHAR> (car n) (car (car list))) (cons (car list) (INSERT n (cdr list))))
   (T (cons n list))))

(defun SORTING (list)
  (if list
   (INSERT (car list) (SORTING (cdr list))))) 

(defun READSTRING()
   (let ((listс nil) (listi nil)) 
   (setq listc (coerce (string (read)) 'list))
   (do ((index 1 (+ 1 index)))
       ((= index (length listc)) (setq listi (cons index listi)))
       (setq listi (cons index listi))
   )
   (pairlis (reverse listc) listi)
   )
)

(defun demo()
    (terpri)
    (princ "============Binary search==============")
    (terpri)
    (princ "Enter the string:")
         (setq l (READSTRING))
    (terpri)
    (princ "===============Search====================")
    (terpri)
    (princ  (SORTING l))
    (terpri)
    (print "===Press any key and Enter to continue===")
    (print (read))
)

(demo)



У кого есть замечания прошу говорить. Я пока поиск буду делать.
PM MAIL   Вверх
adejneka
Дата 5.1.2007, 18:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 8.7.2005
Где: Москва, Россия

Репутация: 9
Всего: 11



У (STRING (READ)) будут большие проблемы со скобками во входном потоке. Лучше написать (READ-LINE).
Вычислять на каждой итерации заново длину списка - это несколько неоптимально. Я бы использовал DOTIMES или LOOP:
Код
(dotimes (index (length listc))
  (push (1+ index) listi))

(setq listi (loop for i from 1 to (length listc)
                  collect i))

(loop for char across (read-line)
      and index from 1
      collect (cons char index))

Для сортировки существует встроенная функция SORT, нужно только правильно задать предикат или ключ:
Код
(sort list (lambda (x y) (char< (car x) (car y))))
(sort list #'char< :key #'car)

PM MAIL   Вверх
linuxfan
Дата 5.1.2007, 19:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 11.10.2006

Репутация: 1
Всего: 1



А тебе надо различать регистр символов? Если нет,  то надо юзать char-greaterp вместо char>
И раз у тебя в задачу входит только бинарный поиск, то я бы сортировку и остальные вспомогательные действия возложил на уже имеющиеся возможности lisp'а.
Код
(defun make-char-hash (string)
  (let ((char-hash (make-hash-table)))
    (labels
      ((push-char-position (char pos)
        (setf (gethash char char-hash)
              (cons pos (gethash char char-hash)))))
      (dotimes (i (length string) char-hash)
        (push-char-position (aref string i) i)))))

(defun hash-keys-list (hash)
  (let ((c-list nil))
    (maphash #'(lambda (key value)
                 (setq c-list (cons key c-list))) hash)
    c-list))

make-char-hash делает хэш-таблицу, ключами которой являются символы (для регистронезависимости надо дополнительно указать :test 'equalp), а значениями -- позиции, в которых встречаются эти символы.
has-keys-list делает список из ключей хэш-таблицы.
Соответственно, вся подготовка к бинарному поиску сведется к созданию хэша символов, списка символов из него и его сортировке встроенной функцией sort, после чего можно непосредственно реализовывать бинарный поиск.
PM MAIL   Вверх
VH_
Дата 5.1.2007, 21:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 182
Регистрация: 31.10.2006

Репутация: 10
Всего: 11



Уважаемый Agarwaen, прочитав Ваше "задание" и "общую идею" (сообщение №1), остаемся в полном недоумении по следующим основаниям:
Задача - "...необходимо определить порядковые номера его (знака) вхождений в искомую строку"
Общая идея - "...каждому символу (то есть знаку) присваиваем список с номерами его позиций в строке. Затем..."
Если уже есть в наличии список номеров позиций, тогда зачем все действия после слова "затем"? Однако зачем таковой список для каждого знака, если заранее известен искомый знак?
PM MAIL   Вверх
Agarwaen
Дата 5.1.2007, 21:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 4.1.2007

Репутация: нет
Всего: нет



 Это же учебная задача. Ясно что в реальной жизни никто такой геморой устраивать ради поиска в строке не будет. Реальное применение бинарного поиска мне видится только в поиске по таблице-справочнику, в которой ключи уже отсортированы.

Это сообщение отредактировал(а) Agarwaen - 5.1.2007, 21:34
PM MAIL   Вверх
VH_
Дата 5.1.2007, 21:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 182
Регистрация: 31.10.2006

Репутация: 10
Всего: 11



Такая учебная задача успешно может привить только отвращение к учению. Извините, а Вы часом не преподаватель подобных задач?
Опрос Интернета по поводу "бинарного (двоичного) поиска" позволил составить отчетливое представление о том, что сей алгоритм эффективен при поиске (1) определенного, (2) присутствующего в одном экземпляре элемента в (3) упорядоченном массиве подобных элементов. Согласитесь, что произвольная строка, в которой может присутствовать таких элементов от нуля до числа знаков в строке весьма далека от упорядоченного массива.
PM MAIL   Вверх
Agarwaen
Дата 5.1.2007, 22:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 4.1.2007

Репутация: нет
Всего: нет



 Да я всё это понимаю, и сам уже на пределе. Такую задачу мне пришлось сделать на 3 языках: на С++, Prolog и Lisp. Просто наш препод первый семестр преродаёт этот предмет. Я думаю он эти задания придумал за пару часов чтоб просто выдать, а вспомнить уже на защите.  
PM MAIL   Вверх
VH_
Дата 5.1.2007, 22:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 182
Регистрация: 31.10.2006

Репутация: 10
Всего: 11



Я конечно приношу Вам свои извинения, а преподов таких - в (gc)
PM MAIL   Вверх
Agarwaen
Дата 6.1.2007, 16:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 4.1.2007

Репутация: нет
Всего: нет



 Сделал функцию поиска, но она выдаёт только одну позицию символа.
Код

(defun INSERT (n list)
  (cond
   ((null list) (cons n nil))
   ((CHAR> (car n) (car (car list))) (cons (car list) (INSERT n (cdr list))))
   (T (cons n list))))

(defun SORTING (list)
  (if list
   (INSERT (car list) (SORTING (cdr list))))) 

(defun READSTRING()
   (let ((listс nil) (listi nil)) 
   (setq listc (coerce (read-line) 'list))
   (setq size (length listc))
   (do ((index size (- index 1)))
       ((= index 1) (setq listi (cons index listi)))
       (setq listi (cons index listi))
   )
   (pairlis listc listi)
   )
)

(defun BISEARCH(key list)
  (setq r (- (length list) 1))
  (let ((l 0) (m 0) (listq nil))
   (loop
     (cond ((> l r) (return listq)))
     (setq m (ceiling (/ (+ l r) 2)))
     (cond ((char= (car (nth  m  list)) key) (return (cons (cdr (nth m list)) listq))))
     (cond ((char< (car (nth m list)) key) (setq l (+ m 1))))
     (cond ((char> (car (nth m list)) key) (setq r (- m 1))))
   )
  )         
)

(defun demo()
    (terpri)
    (princ "============Binary search================")
    (terpri)
    (princ "Enter the string:")
        (setq l (SORTING (READSTRING)))
    (terpri)
        (princ "Enter the key:")
        (setq key (read-char))
        (terpri)
    (princ "===============Search====================")
    (terpri)
        (PRINC L)
        (princ "Position of key in the string:")
        (princ (BISEARCH key l))
    (terpri)
    (print "===Press any key and Enter to continue===")
    (print (read))
)

(demo)

 Чтобы выдавала все позиции нужно наверно или изменить функцию, или переделать список. У кого есть замечания? Предыдущие были очень полезны, только времени переделывать уже нет особо.

Это сообщение отредактировал(а) Agarwaen - 6.1.2007, 17:18
PM MAIL   Вверх
Agarwaen
Дата 6.1.2007, 17:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 4.1.2007

Репутация: нет
Всего: нет



 Хм, я посмотрел вариант с хэш-таблицей очень хорош. Вот только нужно наверно саму хеш-таблицу переделать в список и его отсортировать, в нём же искать. Вопрос: как это сделать?



PM MAIL   Вверх
adejneka
Дата 6.1.2007, 17:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 8.7.2005
Где: Москва, Россия

Репутация: 9
Всего: 11



После сортировки списка пробежаться по нему и объединить последовательные записи с одинаковым ключом:
((a . 1) (b. 2) (b . 4) (c . 3)) => ((a . (1)) (b . (2 4)) (c . (3)))
Пара замечаний по стилю.
- Нехорошо присваивать значения неописанным глобальным переменным (типа R в BISEARCH и L в DEMO). В Вашем случае лучше воспользоваться LET.
- COND нужен специально для разбора нескольких случаев:
Код
(cond ((char= (car (nth  m  list)) key)
       (return (cons (cdr (nth m list)) listq)))
      ((char< (car (nth m list)) key)
       (setq l (+ m 1)))
      (t
       (setq r (- m 1))))

В READSTRING проверку (= INDEX 1) можно заменить проверкой (= INDEX 0). Тогда функция будет работать со строками нулевой длины и можно будет убрать копию SETQ.
PM MAIL   Вверх
Agarwaen
Дата 6.1.2007, 18:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 20
Регистрация: 4.1.2007

Репутация: нет
Всего: нет



Вот вариант с хеш-таблицей всё работает как надо. Если есть замечания, пишите.
Код
 
(defun make-char-hash (string)
  (let ((char-hash (make-hash-table)))
    (labels
      ((push-char-position (char pos)
        (setf (gethash char char-hash)
              (cons pos (gethash char char-hash)))))
      (dotimes (i (length string) char-hash)
        (push-char-position (aref string i) i)))))

(defun hash-to-list (hash)
  (let ((c-list nil))
    (maphash #'(lambda (key value)
                 (setq c-list (cons (list key value) c-list))) hash)
    c-list))

(defun READSTRING()
   (setq table (make-char-hash (read-line)))
   (setq list (hash-to-list table))
   (sort list #'char< :key #'car)
)

(defun BISEARCH(key list)
  (setq r (- (length list) 1))
  (let ((l 0) (m 0) (listq nil))
   (loop
     (cond ((> l r) (return listq)))
     (setq m (ceiling (/ (+ l r) 2)))
     (cond ((char= (car (nth  m  list)) key) (return (cons (cdr (nth m list)) listq))))
     (cond ((char< (car (nth m list)) key) (setq l (+ m 1))))
     (cond ((char> (car (nth m list)) key) (setq r (- m 1))))
   )
  )         
)

(defun demo()
    (terpri)
    (princ "============Binary search================")
    (terpri)
    (princ "Enter the string:")
        (setq L (READSTRING))
    (terpri)
        (princ "Enter the key:")
        (setq key (read-char))
        (terpri)
    (princ "===============Search====================")
    (terpri)
        (PRINC L)
        (terpri)
        (princ "Position of key in the string:")
        (princ (BISEARCH key L))
    (terpri)
    (print "===Press any key and Enter to continue===")
    (print (read))
)

(demo)

PM MAIL   Вверх
adejneka
Дата 6.1.2007, 18:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 8.7.2005
Где: Москва, Россия

Репутация: 9
Всего: 11



Забыл сразу написать: поиск элемента с заданным номером в списке - операция медленная. Лучше было перед поиском (или перед сортировкой) перевести список в вектор.
PM MAIL   Вверх
linuxfan
Дата 6.1.2007, 21:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 11.10.2006

Репутация: 1
Всего: 1



Цитата(Agarwaen @  6.1.2007,  17:50 Найти цитируемый пост)
Вот только нужно наверно саму хеш-таблицу переделать в список и его отсортировать, в нём же искать. Вопрос: как это сделать?

Ну тебе надо только получить список изо всех ключей хэш-таблицы. Для этого maphash придуман.
PM MAIL   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума LISP
Void
  • Пожалуйста, создавайте темы с содержательными названиями.
  • Lisp — это целое семейство языков. Всегда указывайте в теме используемый диалект (Common Lisp, Scheme и т.д.).
  • Уважаемые учащиеся, здесь всегда рады помочь Вам, но не делать за Вас вашу работу. У вас гораздо больше шансов получить помощь, если Вы приложите усилия и поделитесь с нами проблемами и результатами. В противном случае добро пожаловать в раздел Центр Помощи.
  • Получив ответ на интересующий Вас вопрос, не забудьте пометить его как решённый.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Void.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | LISP | Следующая тема »


 




[ Время генерации скрипта: 0.0854 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.