数据结构---散列表与字符串

文章目录

    • 一、散列表(哈希表)
        • 1.1 实现一个基于链表法解决冲突问题的散列表
        • 1.2 实现一个 LRU 缓存淘汰算法
        • 1.3 对应的 LeetCode 练习题
    • 二、字符串
        • 2.1 实现一个字符集,只包含 a~z 这 26 个英文字母的 Trie 树
        • 2.2 实现朴素的字符串匹配算法
        • 2.3 对应的 LeetCode 练习题

一、散列表(哈希表)

1.1 实现一个基于链表法解决冲突问题的散列表

(i) 拉链法解决冲突的做法是:将所有关键字为同义词的结点链接在同一个单链表中。若选定的散列表长度为m,则可将散列表定义为一个由m个头指针组成的指针数组T[0…m-1]。凡是散列地址为i的结点,均插入到以T[i]为头指针的单链表中。T中各分量的初值均应为空指针。在拉链法中,装填因子α可以大于 1,但一般均取α≤1.

#define SIZE 10                 //哈希表大小为10
//定义哈希表数据结构
typedef struct hashNode
{
    int data;
    struct hashNode *next;
}hashNode;
struct hashNode HashLink[SIZE];         
int m;                                 //大小为全局变量

//初始化哈希表
void initHashTable()
{
    int i;
    m=SIZE;
    for(i=0;idata=key;
    
    while(hashFunc(key) != hashLink[i].data)     //查找位置
        i++;
    //将p结点插入到位置i的哈希链表中,头插
    p->next=hashLink[i].next;
    hashLink[i].next=p;
    return i;
}


//查找
int findHash(int key)
{
    int addr=hashFunc(key);
    int i=0;
    hashNode *p;          //p指向哈希表首地址
    
    if(!hashLink[addr].next)    //若开始哈希表无元素,直接返回
    {
        printf("元素%d不在哈希表中\n",key);
        return 0;
    }
    
    p=hashLink[addr].next;
    while(p!=NULL && (p->data!=key))
    {
        p=p->next;
        i++;
    }
    if(p->data==key)
    {
        printf("元素%d不在哈希表中,地址为%d \n",key,addr);
        return 0;
    }
    else
    {
        printf("元素%d不在哈希表中\n",key);
        return 0;
    }
    
    return 0;
}

1.2 实现一个 LRU 缓存淘汰算法

LRU是一种应用在操作系统上的缓存替换策略,和我们常见的FIFO算法一样,都是用于操作系统中内存管理中的页面替换,其全称叫做Least Recently Used(近期最少使用算法),算法主要是根据数据的历史访问记录来进行数据的淘汰,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。

LeetCode 146
代码参考

#include 
#include 
#include 
#include 
using namespace std;
using namespace stdext;

class LRUCache{
public:
    LRUCache(int capacity) {
        m_capacity = capacity ;
    }
    int get(int key) {
        int retValue = -1 ;
        hash_map > :: iterator> ::iterator it = cachesMap.find(key) ;
        //如果在Cashe中,将记录移动到链表的最前端
        if (it != cachesMap.end())
        {
            retValue = it ->second->second ;
            //移动到最前端
            list > :: iterator ptrPair = it -> second ;
            pair tmpPair = *ptrPair ;
            caches.erase(ptrPair) ;
            caches.push_front(tmpPair) ;
            //修改map中的值
            cachesMap[key] = caches.begin() ;
        }
        return retValue ;
    }
    void set(int key, int value) {
        hash_map > :: iterator> ::iterator it = cachesMap.find(key) ;
        if (it != cachesMap.end()) //已经存在其中
        {
            list > :: iterator ptrPait = it ->second ;
            ptrPait->second = value ;
            //移动到最前面
            pair tmpPair = *ptrPait ;
            caches.erase(ptrPait) ;
            caches.push_front(tmpPair) ;
            //更新map
            cachesMap[key] = caches.begin() ;
        }
        else //不存在其中
        {
            pair tmpPair = make_pair(key, value) ;


            if (m_capacity == caches.size()) //已经满
            {
                int delKey = caches.back().first ;
                caches.pop_back() ; //删除最后一个


                //删除在map中的相应项
                hash_map > :: iterator> ::iterator delIt = cachesMap.find(delKey) ;
                cachesMap.erase(delIt) ;
            }


            caches.push_front(tmpPair) ;
            cachesMap[key] = caches.begin() ; //更新map
        }
    }


private:
    int m_capacity ;                                               //cashe的大小
    list > caches ;                                 //用一个双链表存储cashe的内容
    hash_map< int, list > :: iterator> cachesMap ;  //使用map加快查找的速度
};

1.3 对应的 LeetCode 练习题

LeetCode 1 两数之和

//哈希思想实现
class Solution {
public:
    vector twoSum(vector& nums, int target) {
        unordered_map map;          //unordered_map关联容器
        int n=(int) nums.size();
        for(int i=0;isecond,i};
            }
            map[nums[i]]=i;
        }
    }
};

LeetCode 202 Happy Number

//哈希思想实现
class Solution {
public:
    bool isHappy(int n) {
        unordered_set v;
        while(v.find(n)==v.end()){
            v.insert(n);
            int temp=0;
            while(n){
                tmp+=(n%10)*(n%10);
                n/=10;
            }
            
            n=tmp;
            if(n==1)
                return true;
        }
        return false;
    }
};

二、字符串

2.1 实现一个字符集,只包含 a~z 这 26 个英文字母的 Trie 树

字典树(Trie树)
字典树,又称单词查找树,Trie树,是一种树形结构,典型应用是用于统计,排序和保存大量的字符串,所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度的减少无谓的字符串比较,查询效率比哈希表高。

//结点
class Node{
public:
    Node* next[26];
    int num;
    Node(){
        num=0;
        for(int i=0;i<26;i++)
            next[i] = NULL;
    }
};
class Trie {
public:
    Node* root;
    
    /** Initialize your data structure here. */
    Trie() {
        root=new Node();
    }
    
    /** Inserts a word into the trie. */
    void insert(string word) {
        Node* p=root;
        for(int i=0;inext[word[i]-'a']==NULL){
                p->next[word[i]-'a']==new Node();
            }
            p=p->next[word[i]-'a'];
        }
        p->num++;
    }
    
    /** Returns if the word is in the trie. */
    bool search(string word) {
        Node* p=root;
        for(int i=0;inext[word[i]-'a']==NULL){
                return false;
            }
            p=p->next[word[i]-'a'];
        }
        if(p->num!=0){
            return true;
        }else{
            return false;
        }
    }
    
    /** Returns if there is any word in the trie that starts with the given prefix. */
    bool startsWith(string prefix) {
        Node* p=root;
        for(int i=0;inext[prefix[i]-'a']==NULL) 
                return false;
            p=p->next[prefix[i]-'a'];
        }
        return true;
    }
};
 

2.2 实现朴素的字符串匹配算法

BF算法基本思想:
从主串M的第一个字符开始分别与子串从开头进行比较,当发现不匹配时,主串回到这一轮的下一个字符,子串从头开始比较,直到子串所有字符都匹配,返回所在主串中的下标。

#include
#include
using namespace std;

int BF(char s[],char t[])
{
    int i=0,j=0;
    while((s[i]!='\0') && (t[j]!='\0')){
        if(s[i]==t[j])
        {
            i++;
            j++;
        }
        else{
            i=i-j+1;
            j=0;
        }
    }
    if(t[j] == '\0'){
        return i-j+1;
    }else{
        return 0;
    }
}

int main()
{
    char s[7]={'a','a','a','d','a','b','c'};
    char t[3]={'b','c'};
    int a=BF(s,t);
    cout<

2.3 对应的 LeetCode 练习题

2.3.1 Reverse String (反转字符串)
LeetCode 344

class Solution {
public:
    void reverseString(vector& s) {
        int left = 0,right = s.size()-1;
        while(left < right){
            char t = s[left];
            s[left] = s[right]; 
            s[right] = t;
            ++left;
            --right;
        }
        
    }
};

2.3.2 Reverse Words in a String(翻转字符串里的单词)
LeetCode 151

class Solution{
public :
        string reverseWords(string s){
            s +=" ";
            vector v;
            string ins=" ";
            for(int i=0;i=0;i--){
            ins +=v[i]+" ";
        }
        ins.erase(ins.end()-1);
        swap(ins,s);
        return s;
}
};

2.3.3 String to Integer (atoi)(字符串转换整数 (atoi))
LeetCode 8

class Solution {
public:
    int myAtoi(string str) 
    {
        int i = 0;
        int sign = 1;
        long num = 0;
        while(isspace(str[i])) i++;         //删除前面的空格
        if(str[i]=='-' || str[i]=='+') 
            if(str[i++] == '-') sign *= -1;    //负数变号
        while(str[i]=='0') i++;
        while(isdigit(str[i]))             //是否是数字
        {
            num = 10*num + str[i++]-'0';      //转换为数字
            if(num > fabs(long(INT_MIN))) break;      //超过int表示范围  
        }
        num *= sign;                                //数值正负
        if(num < INT_MIN) return INT_MIN;
        if(num > INT_MAX) return INT_MAX;
        return num;
    }
}

The end~

你可能感兴趣的:(C++,数据结构,LeetCode)