zoukankan      html  css  js  c++  java
  • 数据结构学习第二十三天

    19:04:41 2019-09-17

    已知的查找方式

      顺序查找        $O(N)$

      二分查找(静态查找)  $O(LogN)$

      二叉搜索树       $O(h)$  h为二叉查找树的高度

      平衡二叉树       $O(LogN)

    查找的本质:已知对象找位置

        有序安排对象:全序(二分查找) 半序(二叉搜索树)

        直接“算出”对象位置:散列

    散列查找法的两项基本工作:

      计算位置:构造散列函数 确定关键词存储位置

      解决冲突:引用某种策略 解决多个关键词位置相同的问题

     时间复杂度几乎是常量:$O(1)$,及查找时间与问题规模无关

    散列表(哈希表)

    类型名称:符号表(SymbolTable)

    数据对象集:符号表是"名字(Name)-属性(Attribute)"的集合

    如果没有溢出 $T_查询=T_插入=T_删除=O(1)$

    ”散列(Hashing)"的基本思想是:

      (1)以关键字Key为自变量,通过一个确定的函数h(散列函数) 计算出对应的函数值h(Key),作为数据对象的存储地址

      (2)可能不同的关键字会映射到同一个散列地址上,

      即$h(key_1)=h(key_2) 当(key_1 ot=key_2)$,称为“冲突(Collision)”---------需要某种冲突解决策略

    散列函数的构造方法

    一个好的散列函数一般应考虑下列两个因素:

      1.计算简单,以便提高转换速度

      2.关键词对应的 地址空间分布均匀,以尽量减少冲突

    数字关键词的散列函数构造

      1.直接定址法

        取关键词的某个线性函数值为散列地址,即$h(key)=a*key+b (a、b为常数)$

      2.除留余数法

        散列函数为 $h(key)=key mod p$

        这里 $p=TableSize$

                   一般,$p$取素数

      3.数字分析法

      4.折叠法

        把关键词分割成位数相同的几个部分,然后叠加

      5.平方取中法

    字符关键词的散列函数构造

      1.一个简单的散列函数-----ASCII码加和法

        对字符型关键词key定义散列函数如下:

         $h(key)=(sum key[i]) mod  TableSize$

      2.简单的改进------前3个字符移位法

         $h(key)=(key[0]*27^2+key[1]*27+key[2])mod  TableSize$

      3.好的散列函数------移位法

         涉及关键词所有n个字符,并且分布得很好:

         $h(key)=Big (sum_{i=0}^{n-1} key[n-i-1]*32^i Big) mod TableSize

         

     冲突处理方法

      常用的思路

         换个位置:开放地址法

         同一位置的冲突对象组织在一起:链地址法

     开放地址法(Open Addressing)

      一旦产生了冲突(该地址已有其它元素),就按某种规则取寻找另一空地址

      若发生了第i次冲突,试探的下一个地址将增加$d_i$,基本公式是

      $h_i(key)=(h(key)+d_i)mod TableSize (1leq i les TableSize)$

      $d_i$决定了不同的解决冲突方案:线性探测、平方探测、双散列

      线性探测:$d_i=i$

      平方探测:$d_i=pm i^2$

      双散列:$d_i=i*h_2(key)$

     1.线性探测法(Linear Probing)

      以增量序列$1,2,3,4,.......,(TableSize-1)$循环试探下一个存储地址  (线性探测很容易聚集)

    2.平方探测法(Quadratic Probing) ----二次探测

      平方探测法:以增量序列$1^2,-1^2,2^2,-2^2,......,q^2,-q^2$且$qleq TableSize/2$循环试探下一个存储地址

      有定理显示:如果散列表长度TabLeSize是某个$4k+3$(k是正整数)形式的素数时,平方探测法就可以探查到整个散列表空间

    在开发地址散列表中,删除操作要很小心,通常只能懒惰删除,即需要增加一个"删除标记(Deleted)“,而并不是真正删除它,以便查找时不会"断链",其空间可以在下次插入时重用

    3.双散列探测法(Double Hashing)

       双散列探测法:$d_i为i*h_2(key),h_2(key)是另一个散列函数$

      探测序列成$h_2(key),2h_2(key),3h_2(key),.......$

      $对任意的key,h_2(key) ot=0$

      探测序列还应该保证所有的散列存储单元都应该能被探测到

      选择以下形式

          $h_2(key)=p-(key mod p)$

      其中 $p<TableSize,p、TableSize 都是素数$

    4.再散列(Rehashing)

      当散列表元素太多(即装填因子 $alpha A$太大)时,查找效率会下降

        实用最大装填因子一般取$ 0.5leq alpha A leq0.85$

      散列表扩大时,原有元素需要重新计算放置到新表中

    分离链接法(Separate Chainig)

      将相应位置上冲突的所有关键词存储在同一个单链表中

    开放地址法的实现

     1 //创建开放定址法的散列表实现
     2 #include<stdio.h>
     3 #include<math.h>
     4 #include<malloc.h>
     5 #define MAXTABLESIZE 100000 //允许开辟的最大散列表长度
     6 typedef int ElementType;    //关键词类型使用整型
     7 typedef int Index;            //散列地址类型
     8 typedef Index Position;        //数据所在位置与散列地址是同一类型
     9 /*散列单元状态类型,分别对象:有合法元素、空单元、有已删除元素*/
    10 typedef enum{Legitimate,Empty,Deleted}EntryType;
    11 typedef struct HashEntry Cell; //散列表单元类型
    12 struct HashEntry
    13 {
    14     ElementType Data;    //存放元素
    15     EntryType Info;        //单元状态
    16 };
    17 
    18 typedef struct TblNode* HashTable;  //散列表类型
    19 struct TblNode        //散列表节点定义
    20 {
    21     int TableSize;        //表的最大长度
    22     Cell* Cells;        //存放散列单元数据的数组
    23 };
    24 
    25 int NextPrime(int N)
    26 {//返回大于N且不超过MAXTABLESIZE的最小素数
    27     int i, p = (N % 2) ? N + 2 : N + 1;  //从大于N的下一个奇数开始
    28     while (p<=MAXTABLESIZE)
    29     {
    30         for (i = (int)sqrt(p); i > 2; i--)
    31             if (p % i == 0)break; //p不是素数
    32         if (i == 2)break; //p是素数 结束循环
    33         else
    34             p += 2;  //试探下一个素数
    35     }
    36     return p;
    37 }
    38 
    39 HashTable CreateTable(int TableSize)
    40 {
    41     HashTable H;
    42     int i;
    43     H = (HashTable)malloc(sizeof(struct TblNode));
    44     //保证散列表最大长度是素数
    45     H->TableSize = NextPrime(TableSize);
    46     //声明单元数组
    47     H->Cells = (Cell*)malloc(sizeof(ElementType) * H->TableSize);
    48     //初始化单元状态为"空单元"
    49     for (i = 0; i < H->TableSize; i++)
    50         H->Cells[i].Info = Empty;
    51     return H;
    52 }
    53 
    54 int Hash(ElementType Key, int TableSize)
    55 {
    56     return Key % TableSize;
    57 }
    58 //平方探测法的查找与插入
    59 Position Find(HashTable H, ElementType Key)
    60 {
    61     Position CurrentPos, NewPos;
    62     int CNum = 0;
    63     NewPos = CurrentPos = Hash(Key, H->TableSize);
    64     while (H->Cells[NewPos].Info!=Empty&&H->Cells[NewPos].Data!=Key)
    65     {
    66         //统计冲突次数 并且判断奇偶次
    67         if (++CNum % 2)
    68         {//奇数次
    69             NewPos = CurrentPos + (CNum / 2) * (CNum / 2);
    70             while (NewPos >= H->TableSize)
    71                 NewPos -= H->TableSize;    //调整为合法地址
    72         }
    73         else
    74         {//偶数次
    75             NewPos = CurrentPos - (CNum / 2) * (CNum / 2);
    76             while (NewPos < 0)
    77                 NewPos += H->TableSize; //调整为合法地址
    78         }
    79     }
    80     return NewPos;
    81 }
    82 
    83 void Insert(HashTable H, ElementType Key)
    84 {
    85     Position Pos = Find(H, Key);
    86     if (H->Cells[Pos].Info != Legitimate)
    87     {
    88         H->Cells[Pos].Data = Key;
    89         H->Cells[Pos].Info = Legitimate;
    90     }
    91 }
    View Code

    链地址法的实现

      1 #include<stdio.h>
      2 #include<malloc.h>
      3 #include<math.h>
      4 #include<string.h>
      5 #define KEYLENGTH 15        //关键词字符串最大长度
      6 #define MAXTABLESIZE 10000
      7 
      8 typedef char ElementType[KEYLENGTH + 1];    //关键词类型用字符串
      9 typedef int Index;                        //散列地址类型
     10 
     11 typedef struct LNode* PtrToLNode;
     12 struct LNode
     13 {
     14     ElementType Data;
     15     PtrToLNode Next;
     16 };
     17 typedef PtrToLNode Position;
     18 typedef PtrToLNode List;
     19 
     20 typedef struct TblNode* HashTable;    //散列表类型
     21 struct TblNode        //散列表节点定义
     22 {
     23     int TableSize;    //表的最大长度
     24     List Heads;        //指向链表头节点的数组
     25 };
     26 
     27 int NextPrime(int N)
     28 {
     29     int i;
     30     int p = (N % 2)?N + 2:N + 1;
     31     while (p<MAXTABLESIZE)
     32     {
     33         for (i = (int)sqrt(p); i > 2; i--)
     34             if (p % i)break;
     35         if (i == 2)break;
     36         else
     37             p += 2;
     38     }
     39     return p;
     40 }
     41 int Hash(ElementType Key, int TableSize)
     42 {
     43 
     44 }
     45 HashTable CreateTable(int TableSize)
     46 {
     47     HashTable H;
     48     int i;
     49     
     50     H = (HashTable)malloc(sizeof(struct TblNode));
     51     //保证散列表的最大长度是素数
     52     H->TableSize = NextPrime(TableSize);
     53 
     54     //分配链表头节点数组
     55     H->Heads = (List)malloc(H->TableSize * (struct LNode));
     56     //初始化表头节点
     57     for (i = 0; i < H->TableSize; i++)
     58     {
     59         H->Heads[i].Data[0] = '';
     60         H->Heads[i].Next = NULL;
     61     }
     62     return H;
     63 }
     64 
     65 Position Find(HashTable H, ElementType Key)
     66 {
     67     Position P;
     68     Index Pos;
     69 
     70     Pos = Hash(Key, H->TableSize);
     71     P = H->Heads[Pos].Next; //从链表的第一个节点开始
     72     while (P && P->Data != Key)
     73         P = P->Next;
     74     return P;
     75 }
     76 
     77 void Insert(HashTable H, ElementType Key)
     78 {
     79     Position P, NewCell;
     80     Index Pos;
     81     P = Find(H, Key);
     82     if (!P)        //关键词未找到 可以插入
     83     {
     84         NewCell = (Position)malloc(sizeof(struct LNode));
     85         strcpy(NewCell->Data, Key);
     86         Pos = Hash(Key, H->TableSize);    //初始散列位置
     87         NewCell->Next = H->Heads[Pos].Next;//将NewCell插入为H->Heads[Pos]链表的第一个节点
     88         H->Heads[Pos].Next = NewCell;
     89     }
     90 }
     91 
     92 void DestroyTable(HashTable H)
     93 {
     94     int i;
     95     Position P, Tmp;
     96     for (int i = 0; i < H->TableSize; i++)
     97     {
     98         P = Tmp = H->Heads[i].Next;
     99         while (Tmp)
    100         {
    101             free(P);
    102             P = Tmp->Next;
    103             Tmp = P;
    104         }
    105     }
    106     free(H->Heads);
    107     free(H);
    108 }
    View Code

    串:线性存储的一组数据(默认是字符)

    特殊操作集合

      求串的长度

      比较两串是否相等

      两串相接

      求子串

      插入子串

      匹配子串

      删除子串

    串的模式匹配(KMP算法)

      给定一段文本,从中找出某个指定的关键字

    目标

      给定一段文本:$ string=s_0s_1.....s_{n-1}$

      给定一个模式:$ pattern=p_0p_1......p_{m-1}$

      求$pattern$在$string$中出现的位置

    简单实现

      方法1:c的库函数 strstr

    简单改进

      方法2:从末尾开始比

     大师改进

      方法3:KMP(Knuth、Morris、Pratt)算法

      将时间复杂度从$T=O(nm) 改进到 T=O(n+m)$

    $ match(j)=egin{cases}  满足p_0.....p_i=p_{j-i}....p_j的最大i(<j) \ -1 如果这样的i不存在 end{cases} $

     KMP算法 (这算法惊艳到我了)

    总的来说,在每次比较失败时 下一次到可以匹配的时候是将已经匹配成功的序列中 从头开始的与从尾开始子列中可以匹配的最大部分 将头部移动到尾部 再进行比较 这样的话 对于给定的string文本的指针 不会向后移动 使得这个算法高效

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<stdlib.h>
     4 #define NotFound -1
     5 
     6 typedef int Position;
     7 
     8 void BuildMatch(char* pattern, int* match)
     9 {
    10     Position i, j;
    11     int m = strlen(pattern);
    12     match[0] = -1;
    13     for (j = 1; j < m; j++)
    14     {
    15         i = match[j - 1];
    16         while (i >= 0 && pattern[i + 1] != pattern[j])
    17             i = match[i];
    18         if (pattern[i + 1] == pattern[j])
    19             match[j] = i + 1;
    20         else
    21             match[j] = -1;
    22     }
    23 }
    24 
    25 Position KMP(char* string, char* pattern)
    26 {
    27     int n = strlen(string);
    28     int m = strlen(pattern);
    29     Position s, p, * match;
    30 
    31     if (n < m)return NotFound;
    32     match = (Position*)malloc(sizeof(Position) * m);
    33     BuildMatch(pattern, match);
    34     s = p = 0;
    35     while (s<n&&p<m)
    36     {
    37         if (string[s] == pattern[p])
    38         {
    39             s++; p++;
    40         }
    41         else if (p > 0)
    42             p = match[p - 1] + 1;
    43         else
    44             s++;
    45     }
    46     return (p == m) ? (s - m) : NotFound;
    47 }
    48 
    49 int main()
    50 {
    51     char string[] = "This is a simple example";
    52     char pattern[] = "simple";
    53     Position p = KMP(string, pattern);
    54     if (p == NotFound)printf("Not Found.
    ");
    55     else printf("%s
    ", string + p);
    56     return 0;
    57 }
    View Code

    PTA第34题 简单的利用KMP算法的一道题

     1 #define _CRT_SECURE_NO_WARNINGS  
     2 #include<stdio.h>
     3 #include<stdlib.h>
     4 #include<string.h>
     5 #define NotFount -1
     6 
     7 typedef int Position;
     8 
     9 void BuildMatch(char* pattern, int* match)
    10 {
    11     Position i, j;
    12     int m = strlen(pattern);
    13     match[0] = -1;
    14     for (int j = 1; j < m; j++)
    15     {
    16         i = match[j - 1];
    17         while (i >= 0 && pattern[i + 1] != pattern[j])
    18             i = match[i];
    19         if (pattern[i + 1] == pattern[j])
    20             match[j] = i + 1;
    21         else
    22             match[j] = -1;
    23     }
    24 }
    25 
    26 Position KMP(char* string, char* pattern)
    27 {
    28     int n = strlen(string);
    29     int m = strlen(pattern);
    30     Position s, p;
    31     Position* match;
    32     match = (Position*)malloc(sizeof(Position) * m);
    33     BuildMatch(pattern, match);
    34     s = p = 0;
    35     while (s<n&&p<m)
    36     {
    37         if (string[s] == pattern[p])
    38         {
    39             s++;
    40             p++;
    41         }
    42         else if (p > 0)
    43             p = match[p - 1] + 1;
    44         else
    45             s++;
    46     }
    47     return (p == m) ? (s - m) : NotFount;
    48 }
    49 
    50 int main()
    51 {
    52     char* string = (char*)malloc(sizeof(char) * 1000000);
    53     int n;
    54     scanf("%s%d", string,&n);
    55     while (n--)
    56     {
    57         char* pattern = (char*)malloc(sizeof(char) * 100000);
    58         scanf("%s", pattern);
    59         Position p;
    60         p = KMP(string, pattern);
    61         if (p == NotFount)
    62             printf("P----Not Found
    ");
    63         else
    64             printf("P----%s
    ", string + p);
    65     }
    66     return 0;
    67 }
    View Code

    PTA 第29题 表排序思想的应用

    代码1 有一个测试点运行超时

     1 #define _CRT_SECURE_NO_WARNINGS  
     2 #include<stdio.h>
     3 
     4 int A[100000] = { 0 };
     5 int Position[100000] = { 0 };
     6 int IsRight[100000] = { 0 };
     7 void Swap(int i, int j)
     8 {
     9     int tmp = A[i];
    10     A[i] = A[j];
    11     A[j] = tmp;    
    12 }
    13 int SwapTimes=0;
    14 int IsOk(int N)
    15 {
    16     for (int i = 1; i < N; i++)
    17         if (IsRight[i] != 1)
    18             return i;
    19     return 0;
    20 }
    21 void Charge(int N)
    22 {
    23     int t;
    24     while (1)
    25     {
    26 
    27         if (/*A[0] == 0*/Position[0]==0)
    28         {
    29             t = IsOk(N);
    30             if (!t)
    31                 break;
    32             //Swap(Position[0], Position[i]);   //可以不用交换  作好标记即可
    33             int temp = Position[0];    //交换这两个元素的位置
    34             Position[0] = Position[t];
    35             Position[t] = temp;
    36             SwapTimes++;
    37         }
    38         //Swap(Position[0], Position[Position[0]]);
    39         IsRight[Position[0]] = 1;
    40         Position[0] = Position[Position[0]];
    41         SwapTimes++;
    42     }
    43 }
    44 int main()
    45 {
    46     int N;
    47     scanf("%d", &N);
    48     for (int i = 0; i < N; i++)
    49     {
    50         int num;
    51         scanf("%d", &num);
    52         A[i] = num;
    53         Position[num] = i;
    54         if (A[i] == i)
    55             IsRight[i] = 1;
    56     }
    57     Charge(N);
    58     printf("%d", SwapTimes);
    59     return 0;
    60 }
    View Code

    代码2  这个正确

    是利用表的物理排序时 N个数字的排列由若干个独立的环组成

    对于含有0元素的 环来说  交换次数 为 环内元素减一

    对于不含有0元素的 环来说 交换次数 为  环内元素加一(0元素)减一(公式)再加一(将0元素添加到环中)

     1 #define _CRT_SECURE_NO_WARNINGS  
     2 #include<stdio.h>
     3 
     4 int A[100000] = { 0 };
     5 int Position[100000] = { 0 };
     6 int IsRight[100000] = { 0 };
     7 void Swap(int i, int j)
     8 {
     9     int tmp = A[i];
    10     A[i] = A[j];
    11     A[j] = tmp;    
    12 }
    13 int SwapTimes=0;
    14 int FindElements(int Pos)
    15 {
    16     int num=1;
    17     while (Position[Pos]!=Pos)
    18     {
    19         num++;
    20         IsRight[Position[Pos]] = 1;
    21         Position[Pos] = Position[Position[Pos]];
    22     }
    23     return num;  //返回元素的个数
    24 }
    25 void Charge(int N)
    26 {
    27     int num;
    28     //从零开始计算
    29     SwapTimes += FindElements(0)-1;            //交换次数比元素个数少一
    30     for (int i = 1; i < N; i++)
    31     {
    32         if (!IsRight[i])
    33             SwapTimes += FindElements(i)+1;        //虽然交换次数比元素个数少一 但是要利用0来进行交换 所以时 这个环的元素加一
    34     }                                            //而把0元素添加到 环中先进行一次交换 所以 最后结果为  元素+1-1+1
    35 }
    36 int main()
    37 {
    38     int N;
    39     scanf("%d", &N);
    40     for (int i = 0; i < N; i++)
    41     {
    42         int num;
    43         scanf("%d", &num);
    44         A[i] = num;
    45         Position[num] = i;
    46         if (A[i] == i)
    47             IsRight[i] = 1;
    48     }
    49     Charge(N);
    50     printf("%d", SwapTimes);
    51     return 0;
    52 }
    View Code

     PTA第28题 表排序的应用 有几个测试点死活过不了

     1 #define _CRT_SECURE_NO_WARNINGS  
     2 #include<stdio.h>
     3 struct User
     4 {
     5     int Score[6];
     6     int TotalScore;
     7     int PrefectProblems;
     8     int IsSubmit[6];
     9 }Users[10000];
    10 int Problem_Full_Score[6];
    11 int Table[10000];
    12 void Print(int N,int K)
    13 {
    14     int issubmit = 0;
    15     int j = 1;
    16     int x = 1;
    17     for (int i = 1; i <= N; i++)
    18     {
    19         if (Users[Table[i]].TotalScore == 0)
    20             break;
    21         /*for (int k = 1; k <= K; k++)
    22         {
    23             if (Users[Table[i]].IsSubmit[k])
    24                 issubmit = 1;
    25         }
    26         if (!issubmit)
    27             continue;*/
    28         if (Users[Table[i]].TotalScore == Users[Table[i - 1]].TotalScore)
    29             printf("%d %05d %d", j, Table[i], Users[Table[i]].TotalScore);
    30         else
    31         {
    32             j = x;
    33             printf("%d %05d %d", i, Table[i], Users[Table[i]].TotalScore);
    34             x++;
    35         }
    36         for (int m = 1; m <= K; m++)
    37         {
    38             if (Users[Table[i]].Score[m])
    39                 printf(" %d", Users[Table[i]].Score[m]);
    40             else if (!Users[Table[i]].IsSubmit[m])
    41                 printf(" -");
    42             else
    43                 printf(" 0");
    44         }
    45         printf("
    ");
    46     }
    47 }
    48 void InitializeTable(int N)
    49 {
    50     for (int i = 1; i <= N; i++)
    51         Table[i] = i;
    52 }
    53 void Table_Sort(int N)
    54 {
    55     for (int i = 2; i <= N; i++)
    56     {
    57         int p=i;
    58         int Temp = Users[Table[p]].TotalScore;
    59         int Prefect = Users[Table[p]].PrefectProblems;
    60         for (; p > 1 &&(Users[Table[p - 1]].TotalScore < Temp||(Users[Table[p-1]].TotalScore==Temp&&Users[Table[p-1]].PrefectProblems<Prefect)|| (Users[Table[p - 1]].TotalScore == Temp && Users[Table[p - 1]].PrefectProblems==Prefect&&Table[p]>i)); p--)
    61         {
    62             Table[p] = Table[p - 1];
    63         }
    64         Table[p] = i;
    65     }
    66 }
    67 int main()
    68 {
    69     int N, K, M;
    70     scanf("%d %d %d", &N, &K, &M);
    71     for (int i = 1; i <= K; i++)
    72     {
    73         int Score = 0;
    74         scanf("%d", &Score);
    75         Problem_Full_Score[i] = Score;
    76     }
    77     for (int i = 0; i < M; i++)
    78     {
    79         int Use_id, Problem_id, Partial_Score_Obtained;
    80         scanf("%d %d %d", &Use_id, &Problem_id, &Partial_Score_Obtained);
    81         Users[Use_id].IsSubmit[Problem_id] = 1;
    82         if (Users[Use_id].Score[Problem_id] < Partial_Score_Obtained)
    83         {
    84             Users[Use_id].TotalScore += Partial_Score_Obtained - Users[Use_id].Score[Problem_id];
    85             Users[Use_id].Score[Problem_id] = Partial_Score_Obtained;
    86             if (Partial_Score_Obtained == Problem_Full_Score[Problem_id])
    87                 Users[Use_id].PrefectProblems++;
    88         }
    89     }
    90     InitializeTable(N);
    91     Table_Sort(N);
    92     Print(N,K);
    93     return 0;
    94 }
    View Code

    PTA第30题 一道直白的利用散列的题 

    把情况考虑清除后就没什么要注意的点

      1 #define _CRT_SECURE_NO_WARNINGS  
      2 #include<stdio.h>
      3 #include<malloc.h>
      4 #include<math.h>
      5 #include<stdlib.h>
      6 #include<string.h>
      7 #define KEYLENGTH 11  //关键词类型长度
      8 #define MAXTABLESIZE 200000 
      9 
     10 typedef char ElementType[KEYLENGTH+1];
     11 typedef struct LNode* PtrToNode;
     12 int Persons;
     13 struct  LNode
     14 {
     15     ElementType Data;
     16     PtrToNode Next;
     17     int Times;
     18 };
     19 typedef PtrToNode List;
     20 typedef PtrToNode Position;
     21 
     22 typedef struct HblNode* HashTable;
     23 struct  HblNode
     24 {
     25     int TableSize;
     26     List Heads;
     27 };
     28 int NextPrime(int N)
     29 {
     30     int i;
     31     int p = (N % 2) ? N + 2 : N + 1;    //检测奇数
     32     while (p<MAXTABLESIZE)
     33     {
     34         for (i = (int)sqrt(p); i > 2; i--)
     35             if (p % i == 0)
     36                 break;
     37         if (i == 2)break;
     38         else
     39             p += 2;
     40     }
     41     return p;
     42 }
     43 int Hash(ElementType Key, int TableSize)
     44 {
     45     return atoi(Key + 7) % TableSize;
     46 }
     47 long Atoi(ElementType S, int N)
     48 {
     49     long num=0;
     50     for (int i = 0; i < N; i++)
     51     {
     52         num += num * 10 + S[i] - '0';
     53     }
     54     return num;
     55 }
     56 HashTable CreateHashTable(int TableSize)
     57 {
     58     HashTable H;
     59     H = (HashTable)malloc(sizeof(struct HblNode));
     60     H->TableSize = NextPrime(TableSize);
     61     H->Heads = (List)malloc(H->TableSize * sizeof(struct LNode));
     62     for (int i = 0; i < H->TableSize; i++)
     63     {
     64         H->Heads[i].Data[0] ='';
     65         H->Heads[i].Next = NULL;
     66         H->Heads[i].Times = 0;
     67     }
     68     return H;
     69 }
     70 Position Find(HashTable H, ElementType Key)
     71 {
     72     int Pos;
     73     Position P;
     74     Pos= Hash(Key, H->TableSize);
     75     P = H->Heads[Pos].Next;
     76     while (P && strcmp(P->Data, Key))
     77         P = P->Next;
     78     return P;
     79 }
     80 void Insert(HashTable H, ElementType Key)
     81 {
     82     Position P = Find(H, Key);
     83     PtrToNode NewCell;
     84     if (!P)
     85     {
     86         int Pos = Hash(Key, H->TableSize);
     87         NewCell = (PtrToNode)malloc(sizeof(struct LNode));
     88         NewCell->Next = H->Heads[Pos].Next;
     89         H->Heads[Pos].Next = NewCell;
     90         strcpy(NewCell->Data, Key);
     91         NewCell->Times = 1;
     92     }
     93     else
     94         P->Times++;
     95 }
     96 void JudgeAndPrint(HashTable H)
     97 {
     98     Position MaxP=(Position)malloc(sizeof(struct LNode));
     99     MaxP->Times =0;
    100     Position P=NULL;
    101     for (int i = 0; i < H->TableSize; i++)
    102     {
    103         P = H->Heads[i].Next;
    104         while (P)
    105         {
    106             if (P->Times > MaxP->Times)
    107             {
    108                 Persons = 1;
    109                 MaxP = P;
    110             }
    111             else if (P->Times == MaxP->Times)
    112             {
    113                 Persons++;
    114                 if (Atoi(P->Data,11) <Atoi(MaxP->Data,11))
    115                     MaxP = P;
    116             }
    117             P = P->Next;
    118         }
    119     }
    120     if(Persons==1)
    121         printf("%s %d", MaxP->Data, MaxP->Times);
    122     else if(Persons>1)
    123         printf("%s %d %d", MaxP->Data, MaxP->Times,Persons);
    124 }
    125 int main()
    126 {
    127     int N;
    128     scanf("%d", &N);
    129     HashTable H = CreateHashTable(N);
    130     for (int i = 0; i < N; i++)
    131     {
    132         char s1[12] = { 0 }, s2[12] = { 0 };
    133         scanf("%s %s", s1, s2);
    134         Insert(H, s1);
    135         Insert(H, s2);
    136     }
    137     JudgeAndPrint(H);
    138     return 0;
    139 }
    View Code

    PTA第31题 也是一道直白的利用散列的题

    主要要考虑的是什么时候停止检测 

    因为是利用正向的二次探测 即增量为$1^2,2^2,3^2,.......,{TableSize}^2,.............$

    经过分析可知 对于大于$TableSize$的增量来说

    $(TableSize+CNum)^2={TableSize}^2+2*{CNum}*{TableSize}+{CNum}^2$ 

    在调整之后 又变成了${CNum}^2$为增量来检测 那么之后的就是前面的重复了

    故只需检测到${CNum}={TableSize-1}$即可

      1 #define _CRT_SECURE_NO_WARNINGS  
      2 #include<stdio.h>
      3 #include<malloc.h>
      4 #include<math.h>
      5 #define MAXTABLESIZE 20000
      6 
      7 typedef int ElementType;
      8 typedef enum { Legitimate, Empty, Deleted } EntryType;
      9 typedef struct HashEntry Cell;
     10 struct HashEntry
     11 {
     12     ElementType Data;
     13     EntryType Info;
     14 };
     15 
     16 typedef struct HblNode* HashTable;
     17 struct  HblNode
     18 {
     19     int TableSize;
     20     Cell* Cells;
     21 };
     22 
     23 int NextPrime(int N)
     24 {
     25     if (N == 1)
     26         return 2;
     27     int p = (N % 2) ? N + 2 : N + 1;
     28     int i;
     29     while (p<=MAXTABLESIZE)
     30     {
     31         for (i = (int)sqrt(p); i > 2; i--)
     32             if (p % i == 0)
     33                 break;
     34         if (i == 2)break;
     35         else
     36             p += 2;
     37     }
     38     return p;
     39 }
     40 int Hash(int Key, int TableSize)
     41 {
     42     return Key % TableSize;
     43 }
     44 HashTable CreateHashTable(int TableSize)
     45 {
     46     HashTable H;
     47     H = (HashTable)malloc(sizeof(struct HblNode));
     48     H->TableSize = NextPrime(TableSize);
     49     H->Cells = (Cell*)malloc(H->TableSize * sizeof(Cell));
     50     for (int i = 0; i < H->TableSize; i++)
     51         H->Cells[i].Info = Empty;
     52     return H;
     53 }
     54 
     55 int Find(HashTable H, ElementType Key)
     56 {
     57     int NewPos, CurPos;
     58     int CNum = 0;
     59     NewPos = CurPos = Hash(Key, H->TableSize);
     60     while (H->Cells[NewPos].Info!=Empty&&H->Cells[NewPos].Data!=Key)
     61     {
     62         ++CNum;
     63         int Flag = 0;
     64         NewPos = CurPos+CNum * CNum;
     65         if (CNum>H->TableSize)
     66             return -1;
     67         while (NewPos >= H->TableSize)
     68             NewPos -= H->TableSize;
     69     }
     70     return NewPos;
     71 }
     72 
     73 int Insert(HashTable H, ElementType Key)
     74 {
     75     int Pos = Find(H, Key);
     76     if (Pos ==-1)
     77         return -1;
     78     if (H->Cells[Pos].Info != Legitimate)
     79     {
     80         H->Cells[Pos].Data = Key;
     81         H->Cells[Pos].Info = Legitimate;
     82     }
     83     return Pos;
     84 }
     85 
     86 int main()
     87 {
     88     int M, N;
     89     scanf("%d %d", &M, &N);
     90     HashTable H = CreateHashTable(M);
     91     int i;
     92     for (i = 0; i < N-1; i++)
     93     {
     94         int num;
     95         scanf("%d", &num);
     96         int Pos = Insert(H,num);
     97         if (Pos != -1)
     98             printf("%d ", Pos);
     99         else
    100             printf("- ");
    101     }
    102     int num;
    103     scanf("%d", &num);
    104     int Pos = Insert(H, num);
    105     if (Pos != -1)
    106         printf("%d", Pos);
    107     else
    108         printf("-");
    109     return 0;
    110 }
    View Code

     PTA第32题

    直白的利用散列的题 直接暴力就可以做 哈希函数可以不做处理

      1 #define _CRT_SECURE_NO_WARNINGS  
      2 #include<stdio.h>
      3 #include<malloc.h>
      4 #include<math.h>
      5 #include<stdlib.h>
      6 #include<string.h>
      7 #define KEYLENGTH 16  //关键词类型长度
      8 #define MAXTABLESIZE 200000 
      9 
     10 typedef char ElementType[KEYLENGTH + 1];
     11 typedef int Pos;
     12 
     13 typedef struct LNode* PtrToNode;
     14 struct LNode
     15 {
     16     ElementType QAccount;
     17     ElementType QPassWord;
     18     PtrToNode Next;
     19 };
     20 typedef PtrToNode List;
     21 typedef PtrToNode Position;
     22 
     23 typedef struct HblNode* HashTable;
     24 struct  HblNode
     25 {
     26     int TableSize;
     27     List Heads;
     28 };
     29 
     30 int NextPrime(int N)
     31 {
     32     int p = (N % 2)?N + 2:N + 1;
     33     int i;
     34     for (i = (int)sqrt(p); i > 2; i--)
     35     {
     36         if (p % i == 0)
     37             break;
     38         if (i == 2)break;
     39         else
     40             p += 2;
     41     }
     42     return p;
     43 }
     44 long Atoi(ElementType Key, int TableSize)
     45 {
     46     long sum = 0;
     47     int length = strlen(Key);
     48     for (int i = 0; i < length; i++)
     49         sum += sum * 10 + Key[i] - '0';
     50     return sum;
     51 }
     52 int Hash(ElementType Key,int TableSize)
     53 {
     54     return atoi(Key) % TableSize;
     55 }
     56 HashTable CreateHashTable(int TableSize)
     57 {
     58     HashTable H;
     59     H = (HashTable)malloc(sizeof(struct HblNode));
     60     H->TableSize = NextPrime(TableSize);
     61     H->Heads = (List)malloc(H->TableSize * sizeof(struct LNode));
     62     for (int i = 0; i < H->TableSize; i++)
     63     {
     64         H->Heads[i].QAccount[0] = '';
     65         H->Heads[i].QPassWord[0] = '';
     66         H->Heads[i].Next = NULL;
     67     }
     68     return H;
     69 }
     70 Position Find(HashTable H, ElementType Key)
     71 {
     72     Position P;
     73     Pos pos = Hash(Key, H->TableSize);
     74     P = H->Heads[pos].Next;
     75     while (P && strcmp(P->QAccount, Key))
     76         P = P->Next;
     77     return P;
     78 }
     79 int Insert(HashTable H, ElementType Key, ElementType QPassWord)
     80 {
     81     Position Tmp;
     82     Position P = Find(H, Key);
     83     if (!P)
     84     {
     85         Pos pos = Hash(Key, H->TableSize);
     86         Tmp = (Position)malloc(sizeof(struct LNode));
     87         strcpy(Tmp->QAccount, Key);
     88         strcpy(Tmp->QPassWord, QPassWord);
     89         Tmp->Next = H->Heads[pos].Next;
     90         H->Heads[pos].Next = Tmp;
     91         return 1;
     92     }
     93     return 0;
     94 }
     95 
     96 void Order_N(HashTable H,char* QAccount,char* QPassWord)
     97 {
     98     if (Insert(H, QAccount, QPassWord))
     99         printf("New: OK
    ");
    100     else
    101         printf("ERROR: Exist
    ");
    102 
    103 }
    104 void Order_L(HashTable H,char* QAccount, char* QPassWord)
    105 {
    106     Position P=Find(H,QAccount);
    107     if (P)
    108     {
    109         if (!strcmp(P->QPassWord, QPassWord))
    110             printf("Login: OK
    ");
    111         else
    112             printf("ERROR: Wrong PW
    ");
    113     }
    114     else
    115         printf("ERROR: Not Exist
    ");
    116 
    117 }
    118 int main()
    119 {
    120     int N;
    121     scanf("%d", &N);
    122     HashTable H = CreateHashTable(N);
    123     for (int i = 0; i < N; i++)
    124     {
    125         char Choice[2];
    126         char QAccount[11];
    127         char QPassWorld[17];
    128         scanf("
    %s %s %s", Choice, QAccount, QPassWorld);
    129         switch (Choice[0])
    130         {
    131         case 'N':Order_N(H, QAccount, QPassWorld); break;
    132         case 'L':Order_L(H, QAccount, QPassWorld); break;
    133         }
    134     }
    135     return 0;
    136 }
    View Code

    至此 数据结构算是入了门(说是如此 但前面学的没复习又忘了 现在至少知道数据结构在讲什么了) 以后要经常刷题 不然根本学不会。。。

    (os:一个月前立下的flag算是完成了一半吧 还行)

  • 相关阅读:
    迭代器
    LinkedList存储一副扑克牌,实现洗牌功能。
    线程
    堆栈、队列
    路由-第7集
    javascript中split字符串分割函数
    this的用法
    什么是AOP面向切面编程
    Servlet与JSP的区别
    堆(heap)、栈(stack)、方法区(method)
  • 原文地址:https://www.cnblogs.com/57one/p/11536647.html
Copyright © 2011-2022 走看看