(创建的class 里面 一定要有构造函数,且构造函数不能有返回值)前缀树 Leetcode93

23 篇文章 0 订阅

题目

注意本题,即使word是一个是一个完整的路径,不是任何字符串的前缀,用前缀判断函数 startWith 也要返回true
在这里插入图片描述# 代码以及注意点

class Trie {


    class Node{
        Node[] child;
        boolean isend;

        // 没有构造函数怎么能行呢

        public Node(){
            child = new Node[26];
            isend = false;
        }

    }
    Node p;
    public Trie() {
        p = new Node();
        p.child = new Node[26];
    }
    
    public void insert(String word) {
        int len = word.length();
        Node tem = p;

        for(int  i =0; i< len; i++){
            int index = word.charAt(i) - 'a';

            if(tem.child[index] == null){
                tem.child[index] = new Node();
            }

            tem = tem.child[index];
        }

        tem.isend = true;

    }
    
    public boolean search(String word) {

        int len = word.length();
        Node tem = p;
        for(int i = 0;i< len; i++){
            int index = word.charAt(i) - 'a';
            if(tem.child[index] == null){
                return false;
            }

            tem = tem.child[index];
        }

        return tem.isend;
    }
    
    public boolean startsWith(String prefix) {
        int len = prefix.length();
        Node tem = p;
        for(int i = 0;i< len; i++){
            int index = prefix.charAt(i) - 'a';
            if(tem.child[index] == null){
                return false;
            }

            tem = tem.child[index];
        }

        return true;
    }
}


自己以前写的更复杂的前缀树

#include<iostream>
#include<string>
using namespace std;



struct TrieNode
{
	struct TrieNode* child[36];//用来链接后面可能的36个子节点。。。。与二叉树不同的是:“二叉树只有两个子节点,而这里的字典树有36个”
	bool isend;//用来标记此节点是不是单词表里某个单词的左后一个字母,如果是的话,bool置为true,否则置为false

	int pl;      //在每个单词的结尾结点,将该单词的频率存储在它的最后一个结点里
	string zword;//在每个单词的结尾结点,将该单词存储在它的最后一个结点里
	
	int cg;
	string B[21];//用来存储查过一次之后该前缀的查询结果
	int bflag;//作为B[]数组里面实际存了多少个元素的标记


};

struct TrieNode* pz=NULL;

struct TrieNode* pg=NULL;


struct Temp   //为了创建一个结构体数组,将来
{
	long p;
	string w;

};
struct Temp A[10002];



typedef struct TrieNode* Trie;



int main()
{

	Trie init();
	void insert(Trie root, string key, int pl);
	int search(Trie root, string key);
	void quicksort(int left, int right);

	void maosort(int n, int soulen);

	Trie root = init();

	int n, m, k;
	cin >> n;
	cin >> m;
	cin >> k;


	int inputpl;
	string inputword;
	for (int i = 0; i < n; i++)
	{
		cin >> inputpl;
		cin >> inputword;


		insert(root, inputword, inputpl);

	}


	string sou;


	for (int i = 1; i <= m; i++)
	{
		cin >> sou;


		int count = search(root, sou);

		if (count == -2)
		{
			for (int i = 1; i <= pg->bflag; i++)
			{

				cout << pg->B[i] << endl;





			}

			if (i < m)
			{
				printf("\n");
			}


			continue;


		}






		if (count == 0)
		{
			cout << "no suggestion" << endl;

			pz->cg = 1;
			pz->B[1] = "no suggestion";

			pz->bflag = pz->bflag + 1;


			if (i < m)
			{
				printf("\n");
			}

		}
		else
		{
			pz->cg = 1;
			quicksort(1, count);
			int soulen = sou.length();
			//cout << "搜索词的长度为" << soulen << endl;
			int h;
			if (k > count)
			{
				h = count;
			}
			else
			{
				h = k;
			}
			//maosort(h, soulen);
			for (int y = 1; y <= h; y++)
			{
				cout << A[y].w << endl;

				pz->B[y] = A[y].w;

				pz->bflag = pz->bflag + 1;


			}

			if (i < m)
			{
				printf("\n");
			}


		}




















	}



	return 0;
}









Trie init()//创建一个结点并且将它初始化
{
	struct TrieNode* pNode = NULL;//为什么还要加一个“=NULL”?难道我的段错误是因为pz,pz没有“=NULL”
	int i;
	pNode = new struct TrieNode;//new不能换成malloc,因为malloc不能将结点里的pNode->zword给初始化,但是new就可以。
	if (pNode)
	{
		pNode->isend = false;


		pNode->pl = 0;
		
		pNode->cg = 0;

		pNode->bflag = 0;

		for (i = 0; i < 36; i++)
		{
			pNode->child[i] = NULL;
		}


	}

	return pNode;
}


void insert(Trie root, string key, int pl)
{
	int level;
	int length = key.length();
	//cout << "输入字典字符的长度为" << length << endl;
	//cout << "输入字典字符的首字母为" << key[0] << endl;

	int index;
	struct TrieNode* p = root;//同样没有把p置为空,所以说置不置为孔都行
	for (level = 0; level < length; level++)
	{
		int b = key[level] - 'a';

		if (b < 0)
		{
			//printf("第%d个字母是%c", level, key[level]);
			//cout << "b=" << b << endl;
			index = b + 75;
		}
		else
		{
			index = b;
		}

		if (!p->child[index])//若不存在该字母的结点,则初始化一个结点,即将本来是NULL的结点new出来一片内存,这才算给他分配了一片空间,即初始化
		{	
			p->child[index] = init();
								//这是从init()函数里复制过来的代码片段struct TrieNode* pNode = NULL;//为什么还要加一个“=NULL”?难道我的段错误是因为pz,pz没有“=NULL”
																		//int i;
																		//pNode = new struct TrieNode;
			   
		}
		
		p = p->child[index];
	}



	p->isend = true;//这是一个单词插入完了,将最后一个结点进行存储字符串,并且标记
	p->zword = key;




	if (pl < p->pl) {}   //如果字典中有多个相同的单词,则可以将频率更新为最大的那个
	else
	{
		p->pl = pl;
	}

}


int search(Trie root, string key)
{
	void Traver(struct TrieNode* p, int* count, int fla);//因为要用到这个遍历函数,所以先声明一下。免得报错

	int leve;//先初始化一个int变量,随后在for循环中用的时候可以直接将它赋值为0或1;
	int lengt = key.length();



	int index;
	struct TrieNode* p = root;//创建一个变量来接受参数里的root,为了方便以后操作
	for (leve = 0; leve < lengt; leve++)
	{
		int b = key[leve] - 'a';

		if (b < 0)
		{
			//printf("第%d个字母是%c", leve, key[leve]);
			//cout << "b=" << b << endl;
			index = b + 75;
		}
		else
		{
			index = b;
		}



		if (!p->child[index])
			return 0;
		p = p->child[index];

	}

	if (p->cg == 1)
	{

		pg = p;

		return -2;

	}

	pz = p;//为了在打印结果的时候往这个结点里存储这个前缀的全部查询结果,并且标记为查过

	if (p != NULL)
	{
		int count = 0;
		int fla = 0;//用来避免当该前缀就是字典中的一个单词时,避免把这个前缀也当成结果打印出来了
		Traver(p, &count, fla);
		


		return count;

	}

}






void Traver(struct TrieNode* p, int* count, int fla)
{
	if (p->isend == true && fla != 0)//为了避免打印该前缀
	{

		*count = *count + 1;//count是一个地址,只有将count解引用才能对count的值进行操作
		A[*count].p = p->pl;
		A[*count].w = p->zword;

		//不能在这个地方加return,不能就不会查找p->isend为true的结点之后的所有子节点了

	}

	//不能把for循环放到else语句里面,这样就没法遍历p->isend为true的结点之后的所有子节点了

	for (int j = 0; j < 36; j++)
	{
		if (p->child[j])
		{
			fla++;
			Traver(p->child[j], count, fla);
		}

	}





}



void quicksort(int left, int right)
{
	int i, j;
	struct Temp t;
	struct Temp temp;
	if (left > right)
		return;

	temp = A[left];
	i = left;
	j = right;
	while (i != j)
	{
		//顺序很重要,要先从右边开始找
		while (A[j].p <= A[left].p && i < j)
			j--;
		//再找右边的
		while (A[i].p >= A[left].p && i < j)
			i++;
		//交换两个数在数组中的位置
		if (i < j)
		{
			t = A[i];
			A[i] = A[j];
			A[j] = t;
		}
	}
	//最终将基准数归位
	temp = A[left];
	A[left] = A[i];
	A[i] = temp;

	quicksort(left, i - 1);//继续处理左边的,这里是一个递归的过程
	quicksort(i + 1, right);//继续处理右边的 ,这里是一个递归的过程
}
//不行就用冒泡




void maosort(int n, int soulen)
{
	int i, j;

	struct Temp temp;

	for (i = 0; i < n - 1; ++i)  //比较n-1轮
	{
		for (j = 0; j < n - 1 - i; ++j)  //每轮比较n-1-i次,
		{

			if (A[j].p > A[j + 1].p)
			{
			}

			else
			{
				//正常Flag==-1
				int flag = A[j].w.compare(A[j + 1].w);
				if (flag == -1)
				{
				}
				else
				{
					temp = A[j];
					A[j] = A[j + 1];
					A[j + 1] = temp;
				}
			}
		}
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雄狮少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值