2012-12-02 36 views
5

Tôi có quy trình sau đây có nghĩa là phát hiện các chu kỳ trong đồ thị vô hướng lấy cạnh (cạnh đơn) và bộ cạnh (cạnh). Có hai đối số nữa, left_set (có nghĩa là lưu trữ các cạnh cần thiết để được chuyển vào các cuộc truy tìm) và tuần hoàn (là giá trị boolean cuối cùng xác định xem biểu đồ có theo chu kỳ hay không)Quy trình phát hiện chu trình đệ quy MySQL

Vì lý do nào đó không hoạt động quá khứ đệ quy đầu đây là mã với ý kiến ​​giải thích chi tiết:.

các chức năng sau được thực hiện bởi ME IN MYSQL (để tránh nhầm lẫn):

-concat_set(): trả về ghép hai bộ kế toán cho vị trí không đúng chỗ ',' trong trường hợp tập hợp trống

-remove_first(): loại bỏ các thành viên đầu tiên từ thiết

-get_left_node()/get_right_node: trả về các nút của các cạnh, các dấu phân cách giữa các cạnh là ':' nên một cạnh trông như thế này '12: 15'

CREATE PROCEDURE `is_cyclic`(
IN `singleedge` VARCHAR(15), 
IN `edgeset` VARCHAR(1024), 
IN 'left_set' VARCHAR(512), 
OUT `cyclic` BOOLEAN) 

BEGIN 
DECLARE se_left VARCHAR(5); 
DECLARE es_left VARCHAR(5); 
DECLARE se_right VARCHAR(5); 
DECLARE es_right VARCHAR(5); 
Call get_left_node(singleedge, se_left); 
Call get_left_node(SUBSTRING_INDEX(edgeset, ',', 1), es_left); 
Call get_right_node(singleedge, se_right); 
Call get_right_node(SUBSTRING_INDEX(edgeset, ',', 1), es_right); 



--is edgeset emptY? 
    IF LENGTH(edgeset)= 0 AND LENGTH(left_set) = 0 THEN 
     BEGIN 

      SET cyclic= false; 

     END;  

--are singeeledge and first edge in edgeset the same?   
    ELSEIF ((se_left = es_left 
     OR se_left= es_right) 
     AND(se_right = es_left 
     OR se_right = es_right)) THEN 
        BEGIN 
      set cyclic= true; 
         END; 


--do singleedge and first edge in edgeset share any vertices?  
    ELSEIF se_left = es_left 
     OR se_left= es_right 
     OR se_right = es_left 
     OR se_right = es_right 
     THEN 
     --check for all possiblities 
      BEGIN 

       --if left vertex of singleedge and left vertex of current edge in front of edgeset are the same    
       IF se_left=es_left THEN 
            BEGIN 
            --test if the edge of combined uncommon vertices (forming concat(se_right,':',es_right)) exists in the remaining edgeset concatanated with the left_set 
            CALL is_cyclic(concat(se_right,':',es_right),concat_set(left_set,remove_first(edgeset)), '', cyclic); 
            --if the recursion returns cyclic=false, then remove the considered edge from edgeset and continue trying to match the original singleedge with the rest of edgeset 
            IF cyclic=false THEN 
             CALL is_cyclic(singleedge, remove_first(edgeset), left_set, cyclic); 
             END IF; 
            END; 
       ELSEIF se_left= es_right THEN 
            BEGIN 
            CALL is_cyclic(concat(se_right,':',es_left), concat_set(left_set, remove_first(edgeset)), '', cyclic); 
            IF cyclic=false THEN 
             CALL is_cyclic(singleedge, remove_first(edgeset), left_set, cyclic); 
            END IF; 
            END; 
       ELSEIF se_right=es_left THEN 
            BEGIN 
            CALL is_cyclic(concat(se_left,':',es_right), concat_set(left_set, remove_first(edgeset)), '', cyclic); 
            IF cyclic=false THEN 
             CALL is_cyclic(singleedge, remove_first(edgeset), left_set, cyclic); 
            END IF; 
            END; 
       ELSE 
            BEGIN 
            CALL is_cyclic(concat(se_left,':',es_left), concat_set(left_set, remove_first(edgeset)), '', cyclic); 
            IF cyclic=false THEN 
             CALL is_cyclic(singleedge, remove_first(edgeset), left_set, cyclic); 
            END IF; 
             END; 
           END IF; 


      END;  


     ELSE 
      BEGIN 
       --if the current edge being considered from the edgeset does not contain any vertex in common with singleedge, set it aside into left_set and call is_cyclic recurisvely with the edge removed 
       SET left_set = concat_set(left_set, SUBSTRING_INDEX(edgeset, ',', 1)); 
       CALL is_cyclic(singleedge, remove_first(edgeset), left_set, cyclic); 
       END; 

    END IF; 
END 
+1

Tôi sẽ chỉ xả bỏ sự đệ quy vào vòng lặp. Nó có thể làm cho mã một chút xấu xí hơn, nhưng nó đã khá xấu xí. – siride

Trả lời

2

Cố gắng thiết lập lại biến mysql này: max_sp_recursion_depth, thread_stack

SET SESSION max_sp_recursion_depth = 10; 
SET SESSION thread_stack = 250000; 

Sau khi thực hiện trên lệnh gọi thủ tục của bạn. Thực hiện cả hai câu lệnh serially. Tăng kích thước của thread_stack biến theo yêu cầu của bạn.

+0

Điều này thực sự làm việc, tôi đã thiết lập độ sâu đệ quy như thế này trước đây: 'SET GLOBAL max_sp_recursion_depth = 150; 'Có sự khác biệt nào giữa hai người không? Tôi cũng nhận được lỗi sau khi kiểm tra các chu kỳ trên các tập lớn hơn: '# 1436 - Ngăn xếp ngăn xếp luồng' Tôi có nên chỉ định ngăn xếp lớn hơn theo cách thủ công hay không tốt hơn để sửa mã và ngăn không? – Mike

+0

Từ khóa toàn cầu đặt lại biến toàn cầu nghĩa là nó đặt lại 150 cho đến khi khởi động lại dịch vụ mysql. Và nó không cần thiết mà bạn có toreset biến này trên toàn cầu, do đó, thay vì điều này bạn có thể thiết lập lại biến đó mỗi phiên. –

+0

Tôi chưa bao giờ nhận được mã mà tôi đã đăng hoạt động mà không có lỗi ném 'Lỗi ngăn xếp chủ đề'. – Mike