質問編集履歴

7

もう少し情報を追加しました

2020/05/18 02:14

投稿

aardvark
aardvark

スコア17

test CHANGED
File without changes
test CHANGED
@@ -1031,3 +1031,13 @@
1031
1031
  ```
1032
1032
 
1033
1033
  が延々と続いてしまうのです!!!!!
1034
+
1035
+
1036
+
1037
+ 編集2:
1038
+
1039
+ ごめんなさい、よく考えたらr=hash_search(H, s);→slist_insert_tail(L, r);のときは次のリストの要素を指すポインタもそのままコピーされるのですから、そりゃ無限ループになりますよね、、、
1040
+
1041
+
1042
+
1043
+ もう少し考えます

6

質問文に説明を追加

2020/05/18 02:14

投稿

aardvark
aardvark

スコア17

test CHANGED
File without changes
test CHANGED
@@ -986,7 +986,7 @@
986
986
 
987
987
  ```
988
988
 
989
- 例えば、
989
+ 例えば、ハッシュ関数が常に1を出力するよう変更し、
990
990
 
991
991
  ```
992
992
 

5

コードにコメントした

2020/05/18 02:08

投稿

aardvark
aardvark

スコア17

test CHANGED
File without changes
test CHANGED
@@ -840,7 +840,7 @@
840
840
 
841
841
  while(p!=NULL){
842
842
 
843
- if(string_compare(p->key, key)==0){
843
+ if(string_compare(p->key, key)==0){ //keyと一致するような要素を同じスロットにあるリストから探索していきます
844
844
 
845
845
  return p;
846
846
 

4

コードを書き直しましたが、やはりうまくいきません

2020/05/18 02:06

投稿

aardvark
aardvark

スコア17

test CHANGED
File without changes
test CHANGED
@@ -521,3 +521,513 @@
521
521
 
522
522
 
523
523
   どこを改良するべきか、アドバイスいただけるでしょうか。宜しくお願いします。
524
+
525
+
526
+
527
+ 編集:
528
+
529
+ 衝突が起きる場合を想定して書き直しましたが、今度は同じスロットの要素を出力するときにおかしくなります。
530
+
531
+ ```C
532
+
533
+ #include <stdio.h>
534
+
535
+ #include <string.h>
536
+
537
+ #include <stdlib.h>
538
+
539
+ #include <math.h>
540
+
541
+
542
+
543
+ #define NEW(p, n){p = malloc((n)*sizeof(p[0]));}
544
+
545
+
546
+
547
+ typedef char* String;
548
+
549
+ //後々使いやすくするため、ここでStringタイプを定義しちゃいます
550
+
551
+
552
+
553
+ //英和辞書用のオブジェクトです(英語の見出しと日本語の意味のペア)
554
+
555
+ typedef struct slobj_{
556
+
557
+ struct slobj_* next;
558
+
559
+ String key;
560
+
561
+ String jpn;
562
+
563
+ }* slobj;
564
+
565
+
566
+
567
+ //連結リスト
568
+
569
+ typedef struct{
570
+
571
+ slobj head;
572
+
573
+ slobj tail;
574
+
575
+ }* slist;
576
+
577
+
578
+
579
+ typedef struct{
580
+
581
+ int n; //ハッシュに格納されている要素数
582
+
583
+ int m; //ハッシュ表のサイズ
584
+
585
+ slist* T; //リストの配列
586
+
587
+ } hash;
588
+
589
+
590
+
591
+ ハッシュ関数
592
+
593
+ int hfunc(hash H, String key){
594
+
595
+ int h=0, i=0;
596
+
597
+ while (key[i] != 0){
598
+
599
+ h = h*3659+key[i]; //ハッシュ値を計算
600
+
601
+ i++;
602
+
603
+ }
604
+
605
+ return abs(h) % H.m; //非負の値にして、表のサイズで割った余り
606
+
607
+ //return 1; //ハッシュ関数が全て同じ値を出す場合で実験してみました。
608
+
609
+ }
610
+
611
+
612
+
613
+ //文字列の長さを求める
614
+
615
+ int string_len(String str){
616
+
617
+ int len=0;
618
+
619
+ while(str[len]!=0){
620
+
621
+ len++;
622
+
623
+ }
624
+
625
+ return len;
626
+
627
+ }
628
+
629
+
630
+
631
+ //文字列を標準入力から読む
632
+
633
+ String string_input(void){
634
+
635
+ int i, len;
636
+
637
+ char buf[1000];
638
+
639
+ String str;
640
+
641
+ scanf("%999s", buf);
642
+
643
+
644
+
645
+ len = string_len(buf);
646
+
647
+
648
+
649
+ NEW(str, len+1);
650
+
651
+ for(i=0; i<len; i++){
652
+
653
+ str[i]=buf[i];
654
+
655
+ }
656
+
657
+ str[len] = 0;
658
+
659
+ return str;
660
+
661
+ }
662
+
663
+
664
+
665
+ //文字列が同じかどうかを判定する関数
666
+
667
+ int string_compare(String p, String q){
668
+
669
+ int c1, c2;
670
+
671
+ int i=0;
672
+
673
+ while(1){
674
+
675
+ c1=p[i]; c2=q[i];
676
+
677
+ if(c1<c2) return -1;
678
+
679
+ if(c1>c2) return 1;
680
+
681
+ if(c1==0) break;
682
+
683
+ i++;
684
+
685
+ }
686
+
687
+ return 0;
688
+
689
+ }
690
+
691
+
692
+
693
+ //新しい連結リストを作成
694
+
695
+ slist slist_new(void){
696
+
697
+ slist L;
698
+
699
+ NEW(L, 1);
700
+
701
+ L -> head = NULL;
702
+
703
+ L -> tail = NULL;
704
+
705
+ return L;
706
+
707
+ }
708
+
709
+
710
+
711
+ //新しいリスト要素(つまり英和辞典における英語の見出しと対応する日本語のペア)
712
+
713
+ slobj slobj_new(String x, String y){
714
+
715
+ slobj p;
716
+
717
+ NEW(p, 1);
718
+
719
+ p -> key = x;
720
+
721
+ p -> jpn = y;
722
+
723
+ p -> next = NULL;
724
+
725
+ return p;
726
+
727
+ }
728
+
729
+
730
+
731
+ //連結リストの先頭に挿入
732
+
733
+ void slist_insert_head(slist L, slobj p){
734
+
735
+ p -> next = L -> head;
736
+
737
+ L -> head = p;
738
+
739
+ }
740
+
741
+
742
+
743
+ //連結リストの末尾に挿入
744
+
745
+ void slist_insert_tail(slist L, slobj p){
746
+
747
+ if(L -> head == NULL){
748
+
749
+ L -> tail = p;
750
+
751
+ L -> head = p;
752
+
753
+ }
754
+
755
+ else if(L -> head == L -> tail){
756
+
757
+ L -> tail = p;
758
+
759
+ L -> head -> next = p;
760
+
761
+ }
762
+
763
+ else{
764
+
765
+ L -> tail -> next = p;
766
+
767
+ L -> tail = p;
768
+
769
+ }
770
+
771
+ }
772
+
773
+
774
+
775
+ //連結リストをプリント
776
+
777
+ void slist_print(slist L)
778
+
779
+ {
780
+
781
+ slobj p;
782
+
783
+ p = L->head;
784
+
785
+ while (p != NULL){
786
+
787
+ if(string_compare(p->jpn, "NO")==0){
788
+
789
+ printf("%s\n", p->jpn);
790
+
791
+ }
792
+
793
+ else{
794
+
795
+ printf("%s %s\n", p -> key, p -> jpn);
796
+
797
+ }
798
+
799
+ p = p-> next;
800
+
801
+ }
802
+
803
+ }
804
+
805
+
806
+
807
+ //表のサイズがmのハッシュ表を作る
808
+
809
+ hash hash_new(int m){
810
+
811
+ hash H;
812
+
813
+ int i;
814
+
815
+ NEW(H.T, m);
816
+
817
+ H.m = m;
818
+
819
+ for(i=0; i<= m-1; i++){
820
+
821
+ H.T[i]=slist_new();
822
+
823
+ }
824
+
825
+ return H;
826
+
827
+ }
828
+
829
+
830
+
831
+ //キーがkeyである要素を返す
832
+
833
+ slobj hash_search(hash H, String key){
834
+
835
+ slobj p;
836
+
837
+ int h=hfunc(H, key);
838
+
839
+ p = H.T[h]->head;
840
+
841
+ while(p!=NULL){
842
+
843
+ if(string_compare(p->key, key)==0){
844
+
845
+ return p;
846
+
847
+ }
848
+
849
+ p = p->next;
850
+
851
+ }
852
+
853
+ return p;
854
+
855
+ }
856
+
857
+
858
+
859
+ //ハッシュに入力する関数。同じスロットにハッシュされたすべての要素が連結リストに格納されるようにします。
860
+
861
+ void hash_insert(hash H, slobj obj){
862
+
863
+ int h=hfunc(H, obj->key);
864
+
865
+ slist_insert_head(H.T[h], obj);
866
+
867
+ }
868
+
869
+
870
+
871
+ void slist_free(slist L){
872
+
873
+ slobj p, q, r;
874
+
875
+ p = L->head;
876
+
877
+ q = p->next;
878
+
879
+ while (q != NULL){
880
+
881
+ r = q;
882
+
883
+ q = q-> next;
884
+
885
+ free(p);
886
+
887
+ p = r;
888
+
889
+ }
890
+
891
+ free(p);
892
+
893
+ free(L);
894
+
895
+ }
896
+
897
+
898
+
899
+ void hash_free(hash H){
900
+
901
+ int i;
902
+
903
+ for(i = 0; i <= H.m-1; i++){
904
+
905
+ if(H.T[i] -> head != NULL){
906
+
907
+ slist_free(H.T[i]);
908
+
909
+ }
910
+
911
+ }
912
+
913
+ free(H.T);
914
+
915
+ }
916
+
917
+
918
+
919
+ int main(){
920
+
921
+ int i, j, k, n;
922
+
923
+ String eng, jpn, s;
924
+
925
+ double v;
926
+
927
+ slobj p, r;
928
+
929
+ hash H;
930
+
931
+ slist L=slist_new(); //ここに出力する実数を格納していく
932
+
933
+ int m=81239; //数千から数万程度の素数がいいらしい
934
+
935
+ //ここから英和辞典を作成します。
936
+
937
+ scanf("%d", &n); //英和辞典に記録していく英語日本語ペアの数
938
+
939
+ H=hash_new(m);
940
+
941
+ H.n = n;
942
+
943
+ //英語日本語ペアを順次入れていく
944
+
945
+ for(i=1; i<=n; i++){
946
+
947
+ eng=string_input();
948
+
949
+ jpn=string_input();
950
+
951
+ p=slobj_new(eng, jpn);
952
+
953
+ hash_insert(H, p);
954
+
955
+ }
956
+
957
+ //ここからはkeyを入力していきます。各keyに対応する英和辞典の見出しがある場合はそのkeyおよびそれに対応する日本語を、ない場合は-1と出力します
958
+
959
+ scanf("%d", &k);//以後の問い合わせの数
960
+
961
+ for(j=1; j<=k; j++){
962
+
963
+ s=string_input();
964
+
965
+ r=hash_search(H, s);
966
+
967
+ if(r==NULL){
968
+
969
+ r=slobj_new(NULL, "NO");
970
+
971
+ }
972
+
973
+ slist_insert_tail(L, r);
974
+
975
+ }
976
+
977
+ slist_print(L);
978
+
979
+ //slist_free(L);
980
+
981
+ //hash_free(H);
982
+
983
+ return 0;
984
+
985
+ }
986
+
987
+ ```
988
+
989
+ 例えば、
990
+
991
+ ```
992
+
993
+ 3
994
+
995
+ coffee コーヒー
996
+
997
+ milk 牛乳
998
+
999
+ water 水
1000
+
1001
+ 2
1002
+
1003
+ milk
1004
+
1005
+ coffee
1006
+
1007
+ ```
1008
+
1009
+ という入力にした場合、
1010
+
1011
+ ```
1012
+
1013
+ milk 牛乳
1014
+
1015
+ coffee コーヒー
1016
+
1017
+ milk 牛乳
1018
+
1019
+ coffee コーヒー
1020
+
1021
+ milk 牛乳
1022
+
1023
+ coffee コーヒー
1024
+
1025
+
1026
+
1027
+
1028
+
1029
+
1030
+
1031
+ ```
1032
+
1033
+ が延々と続いてしまうのです!!!!!

3

文章を追加

2020/05/18 02:04

投稿

aardvark
aardvark

スコア17

test CHANGED
File without changes
test CHANGED
@@ -512,7 +512,7 @@
512
512
 
513
513
  ```
514
514
 
515
- のような長いインプット正しく動作しないようです。
515
+ のような長いインプットだと、間違ったkeyに対応する見出しが何個か出力されてしまい、正しく動作しないようです。
516
516
 
517
517
 
518
518
 

2

コードの修正

2020/05/18 00:14

投稿

aardvark
aardvark

スコア17

test CHANGED
File without changes
test CHANGED
@@ -70,14 +70,12 @@
70
70
 
71
71
  while (key[i] != 0){
72
72
 
73
- h = h*3659+key[i]; //ハッシュ値を計算
73
+ h = h*101+key[i]; //ハッシュ値を計算
74
74
 
75
75
  i++;
76
76
 
77
77
  }
78
78
 
79
- h = h*1000;
80
-
81
79
  return abs(h) % H.m; //非負の値にして、表のサイズで割った余り
82
80
 
83
81
  }

1

タイトルの変更

2020/05/18 00:10

投稿

aardvark
aardvark

スコア17

test CHANGED
@@ -1 +1 @@
1
- ハッシュ関数の選び方についてアドバイスを頂きたいです。
1
+ 英和辞書を作成しているのですが、ハッシュ関数の選び方についてアドバイスを頂きたいです。
test CHANGED
File without changes