Turbo Prolog开发需求:移除列表中所有回文(含交叉回文)
Turbo Prolog:移除列表中所有回文元素(含交叉回文)
需求
编写Turbo Prolog程序,移除列表中所有属于长度大于1的回文子列表的元素,包括交叉回文(如1 2 1 3 1中的[1,2,1]和[1,3,1])。
现有实现问题
当前算法逻辑:
- 生成原列表的所有前缀子列表
- 筛选出长度>1的回文子列表
- 删除原列表中属于这些回文子列表的元素
针对示例列表[1,2,1,3,1,4,5,1],当前代码输出[4,5],但预期应为[4,5,1]。问题出在:直接根据元素值判断是否删除,导致最后一个1因为在其他回文子列表中出现过(如第一个1)被误删,而实际上它不属于任何回文子列表。
教授给出的解决思路:为原列表元素添加唯一索引,通过索引追踪回文子列表的位置,去重后删除对应索引的元素,避免值重复导致的误删。
当前代码
domains int = integer intl = int* intll = intl* predicates read_list(intl) reverse(intl, intl) append(intll, intll, intll) app(intl, intl, intl) length(intl, int) cut(intl, int, intl) subseq(intl, int, int, intl) prefixes(intl, int, intll) all_sublists(intl, intll) is_pal(intl) all_pals(intll, intll) all_palindroms(intl, intll) belongs_to_sublist(int, intll) filter_elements(intll, intl, intl) member(int, intl) clauses read_list([Head|Tail]) :- readint(Head), !, read_list(Tail). read_list([]). reverse([], []). reverse([H|T], X) :- reverse(T, Rt), app(Rt, [H], X). append([], X, X). append([H|T], X, [H|R]) :- append(T, X, R). app([], X, X). app([H|T], X, [H|R]) :- app(T, X, R). length([], 0). length([_|T], N) :- length(T, N1), N = N1 + 1. cut(_, 0, []) :- !. cut([H|T], L, [H|R]) :- L1 = L - 1, cut(T, L1, R). subseq(X, 0, L, R) :- cut(X, L, R), !. subseq([_|X], P, L, R) :- P1 = P - 1, subseq(X, P1, L, R). prefixes(X, L, []) :- length(X, LX), L > LX, !. prefixes(X, L, [R|T]) :- subseq(X, 0, L, R), L1 = L + 1, prefixes(X, L1, T). all_sublists([], []). all_sublists([H|T], Q) :- prefixes([H|T], 1, R), all_sublists(T, Z), append(R, Z, Q). is_pal(X) :- reverse(X, Rx), X = Rx. all_pals([], []). all_pals([H|T], [H|R]) :- length(H, L), L > 1, is_pal(H), all_pals(T, R), !. all_pals([_|T], R) :- all_pals(T, R). all_palindroms(X, U) :- all_sublists(X, Sx), all_pals(Sx, U). belongs_to_sublist(Element, [Sublist|_]) :- member(Element, Sublist). belongs_to_sublist(Element, [_|Sublists]) :- belongs_to_sublist(Element, Sublists). filter_elements(_, [], []). filter_elements(Sublists, [H|T], [H|Filtered]) :- not(belongs_to_sublist(H, Sublists)), filter_elements(Sublists, T, Filtered). filter_elements(Sublists, [H|T], Filtered) :- belongs_to_sublist(H, Sublists), filter_elements(Sublists, T, Filtered). member(X, [X|_]). member(X, [_|Tail]) :- member(X, Tail). goal write("Elements of list:"), nl, read_list(List), write("list:"), write(List), nl, all_palindroms(List, Q), write("all palindromes in list: "), write(Q), nl, filter_elements(Q, List, Res), write("without palindromes: "), write(Res).
修正后的代码(基于索引追踪)
domains int = integer int_pair = (int, int) % (索引, 元素值) intl = int* pair_list = int_pair* intll = intl* index_set = int* predicates read_list(intl) add_indices(intl, int, pair_list) reverse(intl, intl) append(intll, intll, intll) app(intl, intl, intl) length(intl, int) cut(intl, int, intl) subseq(intl, int, int, intl) prefixes(intl, int, intll) all_sublists(intl, intll) is_pal(intl) all_pals(intll, intll) all_palindroms(intl, intll) get_pal_indices(pair_list, intl, index_set) collect_delete_indices(pair_list, intll, index_set) merge_and_dedup(index_set, index_set, index_set) filter_by_indices(pair_list, index_set, intl) member(int, intl) clauses % 读取用户输入的列表 read_list([Head|Tail]) :- readint(Head), !, read_list(Tail). read_list([]). % 为列表元素添加从1开始的索引 add_indices([], _, []). add_indices([H|T], Index, [(Index, H)|Rest]) :- NextIndex = Index + 1, add_indices(T, NextIndex, Rest). % 反转列表,用于判断回文 reverse([], []). reverse([H|T], X) :- reverse(T, Rt), app(Rt, [H], X). % 拼接子列表集合 append([], X, X). append([H|T], X, [H|R]) :- append(T, X, R). % 拼接普通列表 app([], X, X). app([H|T], X, [H|R]) :- app(T, X, R). % 计算列表长度 length([], 0). length([_|T], N) :- length(T, N1), N = N1 + 1. % 截取列表前L个元素 cut(_, 0, []) :- !. cut([H|T], L, [H|R]) :- L1 = L - 1, cut(T, L1, R). % 截取从位置P开始、长度为L的子列表 subseq(X, 0, L, R) :- cut(X, L, R), !. subseq([_|X], P, L, R) :- P1 = P - 1, subseq(X, P1, L, R). % 生成列表的所有前缀子列表(长度从L开始递增) prefixes(X, L, []) :- length(X, LX), L > LX, !. prefixes(X, L, [R|T]) :- subseq(X, 0, L, R), L1 = L + 1, prefixes(X, L1, T). % 生成列表的所有子列表 all_sublists([], []). all_sublists([H|T], Q) :- prefixes([H|T], 1, R), all_sublists(T, Z), append(R, Z, Q). % 判断是否为回文子列表 is_pal(X) :- reverse(X, Rx), X = Rx. % 筛选出所有长度大于1的回文子列表 all_pals([], []). all_pals([H|T], [H|R]) :- length(H, L), L > 1, is_pal(H), all_pals(T, R), !. all_pals([_|T], R) :- all_pals(T, R). % 获取列表中所有符合条件的回文子列表 all_palindroms(X, U) :- all_sublists(X, Sx), all_pals(Sx, U). % 根据回文子列表的元素值,找到对应的原列表索引 get_pal_indices(PairList, SubList, Indices) :- get_pal_indices_helper(PairList, SubList, [], Indices). get_pal_indices_helper(_, [], Acc, Acc). get_pal_indices_helper([(Idx, Val)|Rest], [Val|SubRest], Acc, Final) :- get_pal_indices_helper(Rest, SubRest, [Idx|Acc], Final), !. get_pal_indices_helper([_|Rest], SubList, Acc, Final) :- get_pal_indices_helper(Rest, SubList, Acc, Final). % 收集所有回文子列表对应的索引,并去重 collect_delete_indices(_, [], []). collect_delete_indices(PairList, [Pal|Rest], AllIndices) :- get_pal_indices(PairList, Pal, PalIndices), collect_delete_indices(PairList, Rest, RestIndices), merge_and_dedup(PalIndices, RestIndices, AllIndices). % 合并两个索引列表并去重 merge_and_dedup([], List, List). merge_and_dedup([H|T], List, Result) :- member(H, List), !, merge_and_dedup(T, List, Result). merge_and_dedup([H|T], List, [H|Result]) :- merge_and_dedup(T, List, Result). % 过滤元素:保留不在删除索引集合中的元素 filter_by_indices([], _, []). filter_by_indices([(Idx, Val)|Rest], DeleteIndices, [Val|Filtered]) :- not(member(Idx, DeleteIndices)), !, filter_by_indices(Rest, DeleteIndices, Filtered). filter_by_indices([_|Rest], DeleteIndices, Filtered) :- filter_by_indices(Rest, DeleteIndices, Filtered). % 元素成员判断 member(X, [X|_]). member(X, [_|Tail]) :- member(X, Tail). % 主目标逻辑 goal write("输入列表元素(回车结束输入):"), nl, read_list(OriginalList), write("原列表:"), write(OriginalList), nl, add_indices(OriginalList, 1, IndexedList), all_palindroms(OriginalList, Palindromes), write("所有长度>1的回文子列表:"), write(Palindromes), nl, collect_delete_indices(IndexedList, Palindromes, DeleteIndices), filter_by_indices(IndexedList, DeleteIndices, Result), write("移除回文元素后的列表:"), write(Result), nl.
关键修正点
- 索引化元素:通过
add_indices为每个元素绑定唯一索引,避免值重复导致的误判。 - 索引追踪回文:
get_pal_indices根据回文子列表的元素值,匹配原列表中对应的索引,确保只标记真正属于回文子列表的元素位置。 - 去重删除索引:
merge_and_dedup避免同一索引被多次标记,确保每个元素只被判断一次。 - 按索引过滤:
filter_by_indices根据索引保留元素,最终得到符合预期的结果。
对于示例列表[1,2,1,3,1,4,5,1],修正后的代码会正确保留最后一个1,输出[4,5,1]。
内容的提问来源于stack exchange,提问作者Seryozhka
相关产品推荐
相关产品推荐

