CUMTOJ数据结构实验一

CUMTOJ数据结构实验一

问题 A: 子网掩码

题目描述

子网掩码是用来判断任意两台计算机的IP地址是否属于同一子网络的根据。
最为简单的理解就是两台计算机各自的IP地址与子网掩码进行AND运算后,如果得出的结果是相同的,则说明这两台计算机是处于同一个子网络上的,可以进行直接的通讯。就这么简单。

请看以下示例:

运算演示之一:
IP地址  192.168.0.1
子网掩码  255.255.255.0

转化为二进制进行运算:
IP地址  11010000.10101000.00000000.00000001
子网掩码 11111111.11111111.11111111.00000000

AND运算:
     11010000.10101000.00000000.00000000

转化为十进制后为:
      192.168.0.0

运算演示之二:
IP地址  192.168.0.254
子网掩码  255.255.255.0

转化为二进制进行运算:
IP地址  11010000.10101000.00000000.11111110
子网掩码 11111111.11111111.11111111.00000000

AND运算:
     11010000.10101000.00000000.00000000

转化为十进制后为:
      192.168.0.0

运算演示之三:
IP地址  192.168.0.4
子网掩码  255.255.255.0

转化为二进制进行运算:
IP地址  11010000.10101000.00000000.00000100
子网掩码 11111111.11111111.11111111.00000000

AND运算:
     11010000.10101000.00000000.00000000

转化为十进制后为:
      192.168.0.0

通过以上对三组计算机IP地址与子网掩码的AND运算后,我们可以看到它运算结果是一样的,均为192.168.0.0,所以计算机就会把这三台计算机视为在同一子网络。

输入

输入的第一行是本机IP地址;
第二行是子网掩码;
第三行是一个整数N,表示后面有N个IP地址;
接下来N行:
第1个IP地址


第N个IP地址

输出

计算并输出N个IP地址是否与本机在同一子网内。对于在同一子网的输出“INNER”,对于在不同子网的输出“OUTER”。

样例输入

192.168.0.1
255.255.255.0
3
192.168.0.2
192.168.0.254
192.168.1.2

样例输出

INNER
INNER
OUTER

思路

首先,利用scanf的特殊输入方式去除小数点,将输入的ip地址存储在数组中,然后,利用&进行与操作,最后进行比较即可

代码
#include<iostream>
using namespace std;
int main() {
	int local_ip[4] , subnet_mask[4] , test_ip[4];
	int local_ip_subnet_mask[4] , test_ip_subnet_mask[4];
	scanf("%d.%d.%d.%d" , &local_ip[0] , &local_ip[1] , &local_ip[2] , &local_ip[3]);
	scanf("%d.%d.%d.%d" , &subnet_mask[0] , &subnet_mask[1] , &subnet_mask[2] , &subnet_mask[3]);
	int i = 0;
	while(i < 4) {
		local_ip_subnet_mask[i] = local_ip[i] & subnet_mask[i];
		i++;
	}
	int N;
	cin >> N;
	for(int j = 0;j < N;j++) {
		scanf("%d.%d.%d.%d" , &test_ip[0] , &test_ip[1] , &test_ip[2] , &test_ip[3]);
		i = 0;
		while(i < 4) {
			test_ip_subnet_mask[i] = subnet_mask[i] & test_ip[i];
			i++;
		}
		int k = 0;
		for(i = 0; i < 4; i++) {
			if(test_ip_subnet_mask[i] != local_ip_subnet_mask[i]) {
				k = 1;
				cout << "OUTER" << endl;
				break;
			}
		}
		if(!k)
			cout << "INNER" << endl;
	}
	return 0;
}

问题 B: 快来秒杀我

题目描述

根据前几次竞赛的情况,这次为了给新手们一点信心,特提供这道秒杀题来让大家杀。
ASCII码大家应该都学过了,现在给你一个很简单的任务,输入数字,表示ASCII码,输出对应的文本内容。

输入

输入的第一行是一个整数T(1<=T<=100)。
接下来输入T个正整数,这些数之间用空格、换行或Tab键来分隔。
测试数据保证输入的整数都在ASCII码范围内,并且不小于32。

输出

在一行中输出对应的文本内容。

样例输入

13
72 101 108 108 111 44
32 119 111 114 108 100 33

样例输出

Hello, world!

思路

首先,用source_num存储刚刚输入的数字,然后,立即强制将其转化成字符形式即可

代码
#include<iostream>
using namespace std;
int main() {
	int T = 0 , source_num;
	cin >> T;
	int tmp = 0;
	for(; tmp < T; tmp++) {
		cin >> source_num;
		cout << (char)(source_num);
	}
	return 0;
}

问题 C: 最短路径1

题目描述

有n个城市m条道路(n<1000, m<10000),每条道路有个长度,请找到从起点s到终点t的最短距离和经过的城市名。

输入

输入包含多组测试数据。

每组第一行输入四个数,分别为n,m,s,t。

接下来m行,每行三个数,分别为两个城市名和距离。

输出

每组输出占两行。

第一行输出起点到终点的最短距离。

第二行输出最短路径上经过的城市名,如果有多条最短路径,输出字典序最小的那条。若不存在从起点到终点的路径,则输出“can’t arrive”。

样例输入

3 3 1 3
1 3 3
1 2 1
2 3 1

样例输出

2
1 2 3

思路

首先,利用while循环输入n m s t,然后,利用一个队列存储城市名及其间距,最后利用Dijkstra算法求出最短路径

代码
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
#include <cfloat>
#include <map>
const int INF = 1000000;
const int max_num = 1010;
using namespace std;
struct node {
    int w;
    int v;
    node(int a , int b) : v(a) , w(b) {  };
};
int des[max_num] , pre[max_num];
vector<node> G[max_num];
bool visited[max_num];
int N;
void Dijkstra(int s) {
    fill(des , des + N + 1 , INF);
    for (int i = 0; i < N; i++)
		pre[i] = i;
    memset(visited , 0 , N + 1);
    des[s] = 0;
    for (int i = 1 , Min , u; i <= N; i++) {
        Min = INF;
		u = -1;
        for (int k = 1; k <= N; k++) {
            if (!visited[k] && Min > des[k]) {
                Min = des[k];
                u = k;
            }
        }
        if (u == -1)
			return;
        visited[u] = true;
        for (int k = 0; k < G[u].size(); k++) {
            int v = G[u][k].v;
            if(!visited[v]) {
                if (des[v] > des[u] + G[u][k].w) {
                    des[v] = des[u] + G[u][k].w;
                    pre[v] = u;
                }
                else if (des[v] == des[u] + G[u][k].w && pre[v] > u)
                    pre[v] = u;
            }
        }
    }
}
void DFS(int s , int e) {
    if (s == e) {
        cout << e << " ";
        return;
    }
    DFS(s , pre[e]);
    cout << e << " ";
}
int main() {
    #ifdef _DEBUG
    freopen("data.txt", "r+", stdin);
	#endif // _DEBUG
    std::ios::sync_with_stdio(false);
    int M , s , t;
    while(cin >> N >> M >> s >> t) {
        for (int i = 1; i <= N; i++)
            G[i].clear();
        for (int i = 0, d = 1; i < M; i++ , d *= 2) {
            int u , v , w;
            cin >> u >> v >> w;
            G[u].push_back(node(v , w));
            G[v].push_back(node(u , w));
        }
        Dijkstra(s);
        if (des[t] != INF) {
            cout << des[t] << endl;
            DFS(s, t);
        }
        else
            cout << "can't arrive";
       cout << endl;
    }
    return 0;
}

问题 D: 二叉排序树

题目描述

输入一系列整数,建立二叉排序数,并进行前序,中序,后序遍历。

输入

输入第一行包括一个整数n(1<=n<=100)。接下来的一行包括n个整数。

输出

可能有多组测试数据,对于每组数据,将题目所给数据建立一个二叉排序树,并对二叉排序树进行前序、中序和后序遍历。每种遍历结果输出一行。每行最后一个数据之后有一个空格。

样例输入

1
2
2
8 15
4
21 10 5 39

样例输出

2
2
2
8 15
8 15
15 8
21 10 5 39
5 10 21 39
5 10 39 21

思路

首先,将输入的数据建立一棵二叉排序树,然后,进行前序、中序、后序遍历即可

代码
#include<iostream>
using namespace std;
struct node {
	int data;
	node *left , *right;
};
void insert(node* &root , int x) {
	if (root == NULL) {
		root = new node;
		root->data = x;
		root->left = root->right = NULL;
	}
	else if (x == root->data) 
		return;
	else if (x < root->data)
		insert(root->left , x);
	else
		insert(root->right , x);
}
void preorder(node* root) {
	if (root == NULL)
		return;
	cout << root->data << " ";
	preorder(root->left);
	preorder(root->right);
}
void inorder(node* root) {
	if (root == NULL)
		return;
	inorder(root->left);
	cout << root->data << " ";
	inorder(root->right);
}
void postorder(node* root) {
	if (root == NULL)
		return;
	postorder(root->left);
	postorder(root->right);
	cout << root->data << " ";
}
int main() {
	int n , x;
	while (cin >> n) {
		node *root = NULL;
		for (int i = 0; i < n; i++) {
			cin >> x;
			insert(root , x);
		}
		preorder(root);
		cout << endl;
		inorder(root);
		cout << endl;
		postorder(root);
		cout << endl;
	}
	return 0;
}
知识延伸
  1. 二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
    (1)若左子树不空,则左子树上所有节点的值均小于它的根节点的值;
    (2)若右子树不空,则右子树上所有节点的值均大于它的根节点的值;
    (3)左、右子树也分别为二叉排序树;
    (4)没有键值相等的节点。
  2. 前序、中序、后序
  • 前序遍历(根–>左–>右)

      (1) 访问根节点 
    
      (2) 前序遍历左子树 
    
      (3) 前序遍历右子树
    
  • 中序遍历(根–>左–>右)

      (1)中序遍历左子树
    
      (2) 访问根节点
    
      (3) 中序遍历右子树
    
  • 后序遍历(根–>左–>右)

      (1) 后序遍历左子树
    
      (2) 后序遍历右子树
    
      (3) 访问根节点
    

问题 E: 密码锁

题目描述

玛雅人有一种密码,如果字符串中出现连续的2012四个数字就能解开密码。给一个长度为N的字符串,(2=<N<=13)该字符串中只含有0,1,2三种数字,问这个字符串要移位几次才能解开密码,每次只能移动相邻的两个数字。例如02120经过一次移位,可以得到20120,01220,02210,02102,其中20120符合要求,因此输出为1.如果无论移位多少次都解不开密码,输出-1。

输入

第一行输入N,第二行输入N个数字,只包含0,1,2

输出
样例输入

5
02120

样例输出

1

思路

首先,利用一个双端队列record记录输入的输入的012字符串,然后,比较即可

代码
#include <iostream>
#include <stdio.h>
#include <string>
#include <math.h>
#include <deque>
#include <memory.h>
using namespace std;
string str;
int N;
bool visited[1600000];
int main() {
	bool match(const string &str1);
	int hash_func(string cur);
    while(scanf("%d" , &N) != EOF) {
        cin >> str;
        memset(visited , 0 , sizeof(visited));
        deque<string> record;
        record.push_back(str);
        int cur_lel = 1 , nxt_lel = 0 , ret = 0;
        bool found = false;
        while(!record.empty()) {
            string cur = record.front();
            record.pop_front();
            cur_lel --;
            if(match(cur)) {
                found = true;
                cout << ret << endl;
                break;
            }
            for(int i = 0; i < N - 1; i ++) {
                swap(cur[i] , cur[i+1]);
                int hash_val = hash_func(cur);
                if(!visited[hash_val]) {
                    visited[hash_val] = true;
                    record.push_back(cur);
                    nxt_lel ++;
                }
                swap(cur[i] , cur[i+1]);
            }
            if(cur_lel == 0) {
                cur_lel = nxt_lel;
                nxt_lel = 0;
                ret ++;
            }
        }
        if(!found)
            cout << -1 << endl;
    }
    return 0;
}
bool match(const string &str1) {
    for(int i = 0; i <= N - 4; i ++) {
        if(str1.substr(i, 4) == "2012")
            return true;
    }
    return false;
}
int hash_func(string cur) {
    int res = 0;
    for(int i = 0; i < N; i ++)
        res = res * 3 + cur[i] - '0';
    return res;
}
知识延伸
  1. string类的使用
    string的子串:
    string substr(int pos = 0,int n = npos) const;//返回pos开始的n个字符组成的字符串
    string的交换:
    void swap(string &s2); //交换当前字符串与s2的值
  2. memset的使用
    函数原型:void *memset(void *s , int ch , size_t n )
    函数解释:将s中的前n个字节用ch替换并且返回s
    函数作用:在一段内存块中填充某一个给定的值,常用于较大的对结构体和数组的清零操作。
  3. deque
    void push_front(const T& x):双端队列头部增加一个元素x
    void push_back(const T& x):双端队列尾部增加一个元素x
    void pop_front():删除双端队列中最前一个元素
    void pop_back():删除双端队列中最后一个元素
    void clear():清空双端队列中最后一个元素
    void swap(deque&):交换两个同类型向量的数据

问题 F: 算法10-6~10-8:快速排序

题目描述

快速排序是对起泡排序的一种改进。它的基本思想是,通过一趟排序将待排序的记录分割成两个独立的部分,其中一部分记录的关键字均比另一部分的关键字小,在分成两个部分之后则可以分别对这两个部分继续进行排序,从而使整个序列有序。
快速排序的算法可以描述如下:
在这里插入图片描述
在本题中,读入一串整数,将其使用以上描述的快速排序的方法从小到大排序,并输出。

输入

输入的第一行包含1个正整数n,表示共有n个整数需要参与排序。其中n不超过100000。
第二行包含n个用空格隔开的正整数,表示n个需要排序的整数。

输出

只有1行,包含n个整数,表示从小到大排序完毕的所有整数。
请在每个整数后输出一个空格,并请注意行尾输出换行。

样例输入

10
2 8 4 6 1 10 7 3 5 9

样例输出

1 2 3 4 5 6 7 8 9 10

提示

在本题中,需要按照题目描述中的算法完成快速排序的算法。

快速排序是一种十分常用的排序算法,其平均时间复杂度为O(knlnn),其中n为待排序序列中记录的个数,k为常数。大量的实际应用证明,在所有同数量级的此类排序算法中,快速排序的常数因子k是最小的,因此,就平均时间而言,快速排序是目前被认为最好的一种内部排序方法。

而在C语言的常用编译器中,qsort函数是一个非常常用的快速排序函数。

思路

首先,利用一个大数组存储输入的待排序数字,然后,利用qsort函数进行处理,最后,输出即可。

代码
#include <stdlib.h>
int main() {
	int cmp(const void *a , const void *b);
	int arr[100000];
	int n;
	scanf("%d" , &n);
	int tmp;
	for(tmp = 0; tmp < n; tmp++)
		scanf("%d" , &arr[tmp]);
	qsort(arr , n , sizeof(arr[0]) , cmp);
	for(tmp = 0; tmp < n - 1; tmp++)
		printf("%d " , arr[tmp]);
	printf("%d\n" , arr[tmp]);
    return 0;
}
int cmp(const void *a , const void *b) {
  return *(int *)a - *(int *)b; 
} 
知识延伸

qsort函数包含在<stdlib.h>中

qsort函数声明如下:

void qsort(void * base,size_t nmemb,size_t size ,int(*compar)(const void *,const void *));

参数说明:
base,要排序的数组
nmemb,数组中元素的数目
size,每个数组元素占用的内存空间,可使用sizeof函数获得

问题 G: 算法10-2:折半插入排序

题目描述

折半插入排序同样是一种非常简单的排序方法,它的基本操作是在一个已经排好序的有序表中进行查找和插入。不难发现这个查找的过程可以十分自然的修改成折半查找的方式进行实现。
折半插入排序的算法可以描述如下:
在这里插入图片描述
在本题中,读入一串整数,将其使用以上描述的折半插入排序的方法从小到大排序,并输出。

输入

输入的第一行包含1个正整数n,表示共有n个整数需要参与排序。其中n不超过1000。
第二行包含n个用空格隔开的正整数,表示n个需要排序的整数。

输出

只有1行,包含n个整数,表示从小到大排序完毕的所有整数。
请在每个整数后输出一个空格,并请注意行尾输出换行。

样例输入

10
2 8 4 6 1 10 7 3 5 9

样例输出

1 2 3 4 5 6 7 8 9 10

提示

在本题中,需要按照题目描述中的算法完成折半插入排序的算法。与直接插入排序算法不同,折半插入排序算法在查找插入位置时采用了折半查找的方案,减少了关键字之间的比较次数,但是记录的移动次数并没有发生改变,因此折半插入排序的时间复杂度依旧为O(n2),同样不是一种非常高效的排序方法。

思路

首先,利用一个大数组arr存储输入的待排序数字,然后,调用BInsertSort函数进行处理,最后,输出即可。

代码
#include<iostream>
using namespace std;
int arr[1000] , n;
int main() {
	void BInsertSort();
 	while(cin >> n) {
 		for(int i = 0; i < n; i++)
 			cin >> arr[i];
 		BInsertSort();
 		for(int i = 0; i < n; i++)
 			cout<< arr[i] <<" ";
 		cout << endl;
 	}
 	return 0;
}
void BInsertSort() {
	for(int i = 1; i < n; i++) {
 		int low = 0 , high = i - 1 , mid;
 		while(low <= high) {
 			mid = (low + high) / 2;
	 		if(arr[mid] >= arr[i])
	  			high = mid - 1;
	 		else
	  			low = mid + 1;	
		}
		int temp = arr[i];
		for(int j = i; j > low; j--)
	 		arr[j] = arr[j - 1];
		arr[low] = temp;
 	}
}

问题 H: 算法7-9:最小生成树

题目描述

最小生成树问题是实际生产生活中十分重要的一类问题。假设需要在n个城市之间建立通信联络网,则连通n个城市只需要n-1条线路。这时,自然需要考虑这样一个问题,即如何在最节省经费的前提下建立这个通信网。
可以用连通网来表示n个城市以及n个城市之间可能设置的通信线路,其中网的顶点表示城市,边表示两个城市之间的线路,赋于边的权值表示相应的代价。对于n个顶点的连通网可以建立许多不同的生成树,每一棵生成树都可以是一个通信网。现在,需要选择一棵生成树,使总的耗费最小。这个问题就是构造连通网的最小代价生成树,简称最小生成树。一棵生成树的代价就是树上各边的代价之和。
而在常用的最小生成树构造算法中,普里姆(Prim)算法是一种非常常用的算法。以下是其算法的大致结构:
在这里插入图片描述
在本题中,读入一个无向图的邻接矩阵(即数组表示),建立无向图并按照以上描述中的算法建立最小生成树,并输出最小生成树的代价。

输入

输入的第一行包含一个正整数n,表示图中共有n个顶点。其中n不超过50。
以后的n行中每行有n个用空格隔开的整数,对于第i行的第j个整数,如果不为0,则表示第i个顶点和第j个顶点有直接连接且代价为相应的值,0表示没有直接连接。当i和j相等的时候,保证对应的整数为0。
输入保证邻接矩阵为对称矩阵,即输入的图一定是无向图,且保证图中只有一个连通分量。

输出

只有一个整数,即最小生成树的总代价。请注意行尾输出换行。

样例输入

4
0 2 4 0
2 0 3 5
4 3 0 1
0 5 1 0

样例输出

6

提示

在本题中,需要掌握图的深度优先遍历的方法,并需要掌握无向图的连通性问题的本质。通过求出无向图的连通分量和对应的生成树,应该能够对图的连通性建立更加直观和清晰的概念。

思路

首先,利用GetM()函数将邻接矩阵输入并存储在Arrow结构体中,然后,调用MiniSpanTree()函数生成最小生成树,最后,运算并输出最小生成树的代价。

代码
#include <iostream>
#include <cstdio>
using namespace std;
#define MAXLEN 100
int Flag[MAXLEN] = {0};
int flag;
int N;
int Count;
typedef struct {
    int len;
	int NodeA;
	int NodeB;
} arrow;
arrow Arrow[MAXLEN * MAXLEN];
int main() {
	void GetM();
	void MiniSpanTree(); 
    GetM();
	MiniSpanTree();
	return 0;
}
void GetM() {
	cin >> N;
	int temp;
	Count = 0;
	for(int i = 0; i < N; i++) {
	    for(int j = 0; j < N; j++) {
		     cin >> temp;
			 if(temp != 0 && i >= j) {
			     Arrow[Count].len = temp;
				 Arrow[Count].NodeA = i;
				 Arrow[Count].NodeB = j;
				 Count++;
			 }
		}
	}
}
void MiniSpanTree() {
    arrow Temp;
	int LenNum = 0;
	int Sum = 0;
	int i;
	for(i = 0; i < Count; i++) {
	    for(int j = i; j < Count; j++) {
		    if(Arrow[i].len > Arrow[j].len) {
				Temp.len = Arrow[i].len;
				Temp.NodeA = Arrow[i].NodeA;
				Temp.NodeB = Arrow[i].NodeB;
				Arrow[i].len = Arrow[j].len;
				Arrow[i].NodeA = Arrow[j].NodeA;
				Arrow[i].NodeB = Arrow[j].NodeB;
				Arrow[j].len = Temp.len;
				Arrow[j].NodeA = Temp.NodeA;
				Arrow[j].NodeB = Temp.NodeB;
			}
		}
	}
    flag = 0;
    int a , b;
	for(int i = 0; i < Count && LenNum < N - 1; i++) {
        a = Arrow[i].NodeA;
        b = Arrow[i].NodeB;
        if(Flag[a] == 0 && Flag[b] == 0) {
                Sum += Arrow[i].len;
                LenNum++;
                flag++;
                Flag[a] = flag;
                Flag[b] = flag;
        }
        else if(Flag[a] == 0 && Flag[b] != 0) {
            Sum += Arrow[i].len;
            LenNum++;
            Flag[a] = Flag[b];
        }
        else if(Flag[a] != 0 && Flag[b] == 0) {
            Sum += Arrow[i].len;
            LenNum++;
            Flag[b] = Flag[a];
        }
        else if(Flag[a] != 0 && Flag[b] != 0 && Flag[a] != Flag[b]) {
            Sum += Arrow[i].len;
            LenNum++;
            int t = Flag[b];
            Flag[b] = Flag[a];
            for(int j = 0; j < N; j++) {
                if(Flag[j] == t)
                    Flag[j] = Flag[a];
            }
        }
    }
	cout << Sum << endl;
}

问题 I: 8.5.11 Disk Tree

题目描述

Hacker Bill has accidentally lost all the information from his workstation’s hard drive and he has no backup copies of its contents. He does not regret for the loss of the files themselves, but for the very nice and convenient directory structure that he had created and cherished during years of work. Fortunately, Bill has several copies of directory listings from his hard drive. Using those listings he was able to recover full paths (like “WINNT\SYSTEM32\CERTSRV\CERTCO~1\X86”) for some directories. He put all of them in a file by writing each path he has found on a separate line. Your task is to write a program that will help Bill to restore his state of the art directory structure by providing nicely formatted directory tree.

输入

The first line of the input file contains single integer number N (1 <= N <= 500) that denotes a total number of distinct directory paths. Then N lines with directory paths follow. Each directory path occupies a single line and does not contain any spaces, including leading or trailing ones. No path exceeds 80 characters. Each path is listed once and consists of a number of directory names separated by a back slash ("").

Each directory name consists of 1 to 8 uppercase letters, numbers, or the special characters from the following list: exclamation mark, number sign, dollar sign, percent sign, ampersand, apostrophe, opening and closing parenthesis, hyphen sign, commercial at, circumflex accent, underscore, grave accent, opening and closing curly bracket, and tilde ("!#$%&’()-@^_`{}~").

输出

Write to the output file the formatted directory tree. Each directory name shall be listed on its own line preceded by a number of spaces that indicate its depth in the directory hierarchy. The subdirectories shall be listed in lexicographic order immediately after their parent directories preceded by one more space than their parent directory. Top level directories shall have no spaces printed before their names and shall be listed in lexicographic order. See sample below for clarification of the output format.

样例输入

7
WINNT\SYSTEM32\CONFIG
GAMES
WINNT\DRIVERS
HOME
WIN\SOFT
GAMES\DRIVERS
WINNT\SYSTEM32\CERTSRV\CERTCO~1\X86

样例输出

GAMES
DRIVERS
HOME
WIN
SOFT
WINNT
DRIVERS
SYSTEM32
CERTSRV
CERTCO~1
X86
CONFIG

提示
思路
代码
#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
#include <map>
using namespace std;
#define MAXNODE 20000
#define MAXLEN 85
#define MAXWORD 45
map<string , int> m[MAXNODE];
void preOder_traversal(int midx , int indentation) {
	for (map<string , int>::iterator i = m[midx].begin(); i != m[midx].end(); ++i) {
		for (int i = 0; i < indentation; ++i)
			printf(" ");
		printf("%s\n" , (i->first).c_str());
		preOder_traversal(i->second , indentation+1);
	}
}
int main() {
	int n , i , j , midx , midx_counter = 0;
	char str[MAXLEN];
	int word_init[MAXWORD];
	string current_str;
	scanf("%d" , &n);
	while (n--) {
		scanf("%s", str);
		word_init[0] = 0;
		j = 1;
		for (i = 0; str[i]; ++i) {
			if(str[i] == '\\') {
				str[i] = 0;
				word_init[j++] = i + 1;
			}
		}
		midx = 0;
		for (i = 0; i < j; ++i) {
			current_str = str + word_init[i];
			if(!m[midx].count(current_str))
				m[midx][current_str] = (++midx_counter);
			midx = m[midx][current_str];
		}
	}
	preOder_traversal(0 , 0);
	return 0;
}
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值