数据结构实验(三)

数据结构实验(三)

数据结构实验(三)


串、数组和广义表

  1. 串的封装及基本操作

    • “String.hpp”

      // Test4-1:串的封装及基本操作
      
      #include <iostream>
      #include "../SeqList/SeqList.hpp"
      using namespace std;
      
      struct String :SeqList<char>
      {
      	String(int c = 100) :SeqList(c)		//按指定长度构造串
      	{
      	}
      
      	String(const char* chars)			//以""结尾的串构造串,方便将C语言的字符串转换为当前封装的String
      	{
      		while (*chars)
      		{
      			append(*chars);
      			chars++;
      		}
      	}
      
      	String* subString(int pos, int len)//取子串
      	{
      		String* result = new String(len);
      		memcpy(result->items, items + pos, sizeof(char) * len);
      		length = len;
      		return result;
      	}
      
      	String& concat(String& T)			//连接字符串
      	{
      		int len = length + T.length;
      		if (capacity < len)				//长度不够则扩容
      			resize(len);
      		memcpy(items + length, T.items, sizeof(char) * T.length);//连接第二部分
      		length = len;
      		return *this;					//返回自身,方便调用者连续使用
      	}
      
      	int compare(String& T)				//比较两个串是否相等,返回正数、零、负数分别表示大于、等于、小于	
      	{
      		int n = length, m = T.length;
      		int i = 0, j = 0;
      		while (i < n && j < m)
      		{
      			if (items[i] != T.items[i]) //存在一个字符不等则不等
      				return items[i] - T.items[i];//以第一个不相等的字符计算大小
      			i++; j++;
      		}
      		return n - m;					//全部字符都没有不等,则两个串相等
      	}
      
      	bool operator==(String& T)
      	{
      		return compare(T) == 0;
      	}
      
      	void operator=(const String& T)		//深拷贝函数,不重写会导致字符串的数组赋值出现浅拷贝
      	{
      		length = T.length;
      		resize(length);
      		memcpy(items, T.items, sizeof(char) * T.length);
      	}
      
      	void split(SeqList<String>& subs, char splitter)
      	{
      		//TODO:依据spliter字符,将字符串的内容分割开,依次存储到subs中
      	}
      
      	void replace(String A, String B)
      	{
      		//TODO:查找当前字符串中所以的A,替换成B
      	}
      
      	void remove(int pos, int len)
      	{
      		//TODO:删除从pos开始的len个字符
      	}
      
      	void insert(String& A, int pos)
      	{
      		//TODO:将A插入到pos位置上
      		if (length + A.length > capacity)		//如果长度不够扩容
      		{
      			resize(length + A.length);
      		}
      		for (int i = length - 1; i >= pos; i--)
      		{
      			items[i + A.length] = items[i];
      		}
      		for (int i = 0; i < A.length; i++)
      		{
      
      			items[pos + i] = A.items[i];
      		}
      		length += A.length;
      	}
      
      	int index(String& T, int pos = 0)
      	{
      		//TODO:返回T出现的第一个位置,找不到则返回-1
      	}
      
      	friend ostream& operator << (ostream& os, String& st);
      };
      
      ostream& operator<< (ostream& os, String& st)
      {	//标准输出流方式接口
      	for (int i = 0; i < st.length; i++)
      		os << st.items[i];
      	return os;
      }
      
      
    • “String.cpp”

      #include <iostream>
      #include "./String.hpp"
      using namespace std;
      
      int main()					//字符串测试函数
      {
      	String A("hello ");		//测试显示构造函数
      	String B = "world!";	//测试类型转换构造函数
      	A.concat(B).output();	//测试A串连接B串并打印A串
      	printf("A - B = %d 
      ", A.compare(B));		//测试A串和B串比较
      
      	String S("Such a day!");
      	String T("happy ");
      	S.output();
      	T.output();
      	cout << "插入字符串"Such a happy day!":" << endl;
      	S.insert(T, 7);
      	S.output();
      	//printf("子串搜索结果是:%d
      ", S.index(T));//测试求子串位置
      
      	return 0;
      }
      
      
    • 运行截图:

  2. 串的快速匹配——KMP Matching算法

    • “KMP Matching.cpp”

      // Test4-2:串的快速匹配——KMP Matching算法
      
      #include <iostream>
      #include "string.h"
      #include "time.h"
      using namespace std;
      
      // 暴力匹配算法
      int Index(const char* S, const char* T, int pos = 0)
      {
      	//从pos位置开始查找T,返回T最早出现的位置,如果不存在T,返回-1
      	int n = strlen(S), m = strlen(T);
      	int i = pos, j = 0;
      	while (i < n && j < m)
      	{
      		if (S[i] == T[j])	//若匹配则一并移动两个指针
      		{
      			++i;
      			++j;
      		}
      		else				//若失配则退回重新开始
      		{
      			i = i - j + 1;
      			j = 0;
      		}
      	}
      	if (j == m)
      		return i - m;
      	return -1;
      }
      
      // KMP Matching算法
      void get_next(const char* T, int* next)
      {
      	//next表构造函数
      	int i = 0;
      	next[i] = -1;
      	int j = -1;
      	int m = strlen(T);
      	while (i < m)
      	{
      		if (j == -1 || T[i] == T[j])
      		{
      			++i; ++j;
      			next[i] = j;
      		}
      		else
      			j = next[j];
      	}
      }
      
      int Index_KMP(const char* S, const char* T, int pos)
      {
      	//TODO:实现KMP匹配算法
      	int m = strlen(S), n = strlen(T);
      	int* next = new int[n];
      	get_next(T, next);
      	int i = pos, j = 0;
      	while (i < m && j < n)
      	{
      		if (j < 0 || S[i] == T[j])
      		{
      			++i;
      			++j;
      		}
      		else
      		{
      			j = next[j];
      		}
      	}
      	if (j == n)
      		return i - n;
      	return -1;
      }
      
      int main()
      {//字符串匹配性能测试函数
      	char S[] = "00000000000000000000000000,0000000000001";
      	char T[] = "0000000000001";
      	int Next[20];				//Next[j]表示T[j]前的最长前后缀相等的长度
      	get_next(T, Next);
      
      	int pos;
      	int repeats = 10000000;
      	time_t tBegin0, tEnd0, tBegin1, tEnd1;
      
      	time(&tBegin0);					//记录当前时间tBegin0
      	for (int i = 0; i < repeats; i++)
      		pos = Index(S, T, 0);		//暴力匹配算法测试
      	time(&tEnd0);					//记录当前时间tEnd0
      	float cost0 = tEnd0 - tBegin0;	//计算暴力匹配耗时
      
      	time(&tBegin1);					//记录当前时间tBegin1
      	for (int i = 0; i < repeats; i++)
      		pos = Index_KMP(S, T, 0);	//KMP匹配算法测试
      	time(&tEnd1);					//记录当前时间tEnd1
      	float cost1 = tEnd1 - tBegin1;	//计算KMP算法匹配耗时
      
      	printf("子串暴力匹配算法结果是:%d,耗时%.2fs
      ", pos, cost0);
      	printf("子串KMP匹配算法结果是: %d,耗时%.2fs
      ", pos, cost1);
      	return 0;
      }
      
    • 运行截图:

  3. 稀疏矩阵的封装及其快速转置

    • “SparseMatrix.hpp”

      //Test5-1:稀疏矩阵的封装及其快速转置
      
      #pragma once
      #include <iostream>
      #include <iomanip>
      #include <memory>
      using namespace std;
      #include "../SeqList/SeqList.hpp"			//利用顺序表实现三元组的元素存储
      
      template <typename ElemType>
      struct Triplet {
      	int row, col;							//行列下标
      	ElemType e;								//数据
      
      	Triplet() {}							//必须提供默认构造函数,以便创建三元组数组
      	Triplet(int r, int c, ElemType v)
      	{
      		row = r;
      		col = c;
      		e = v;
      	}
      
      	void output()
      	{	
      		// 标准化输出
      		cout << "*Triplet*" << endl;
      		cout.setf(ios::right);
      		cout << setw(5) << "row";
      		cout << setw(5) << "col";
      		cout << setw(5) << "ele";
      		cout << endl;
      		cout << setw(5) << row;
      		cout << setw(5) << col;
      		cout << setw(5) << e;
      		cout << endl;
      	}
      };
      
      template <typename ElemType>
      struct SparseMatrix :SeqList<Triplet<ElemType>>
      {
      	int rows, cols;						//行列大小
      
      	SparseMatrix(int r, int c, int n = 10) :SeqList<Triplet<ElemType>>(n)
      	{
      		rows = r;
      		cols = c;
      	}
      
      	int getIndex(int r, int c)			//将稠密矩阵的下标转为稀疏矩阵的下标,以便访问
      	{	//此函数当输入索引三元组中的数据为零时,会返回其上一个下标的加一值
      		//TODO:将下面的顺序查找改为二分查找
      		//找不到的时候,返回恰好比rc大的存储元素的下标
      		int i = 0;
      		for (i = 0; i < this->length; i++)
      		{
      			Triplet<ElemType>& t = this->items[i];	//取引用,减少对象的拷贝
      			if (t.row > r || t.row == r && t.col >= c)
      				break;
      		}
      		return i;
      	}
      
      	void get(int r, int c)							//获取元素
      	{
      		int index = getIndex(r, c);
      		if (index < this->length && this->items[index].row == r && this->items[index].col == c)
      			return this->items[index].output();
      		else
      			cout << "Not Find in Triplet!" << endl;	//不存在就返回默认值
      	}
      
      	void set(int r, int c, ElemType v)				//修改元素
      	{
      		int index = getIndex(r, c);
      		if (index < this->length && this->items[index].row == r && this->items[index].col == c)
      			this->items[index] = v;					//TODO:写零时,做删除处理
      		else
      			//当前的稀疏矩阵中,没有存储r行c列的元素,则插入元素
      			this->insertAt(index, Triplet<ElemType>(r, c, v));
      
      	}
      
      	void output()
      	{
      		int k = 0;
      		cout.setf(ios::right);
      		cout << "Sparse Matrix: " << endl;
      		for (int i = 0; i < rows; i++)
      		{
      			for (int j = 0; j < cols; j++)
      			{
      				ElemType v = ElemType();			//设置为默认值
      				if (k < this->length && i == this->items[k].row && j == this->items[k].col)
      				{
      					v = this->items[k].e;			//如果存在元素,就改为元素值
      					k++;
      				}
      				cout << setw(4) << v;
      			}
      			cout << endl;
      		}
      		cout << endl;
      	}
      
      	void transposeMatrix()				 //实现三元组矩阵的快速转置
      	{
      		//转置矩阵的快速实现方法
      		//创建并初始化列频数数组
      		int* arra = new int[cols];
      		//利用memset(指针或数组, 初始化值修改每一个字节(0-255), 指针或数组的长度)方法初始化数组每个字节的值
      		memset(arra, 0, sizeof(int) * cols);
      		/*
      		//速度较慢,效率不如memset高
      
      		for (int i = 0; i < cols; i++)
      		{
      			arra[i] = 0;
      		}
      		*/
      		for (int i = 0; i < this->length; i++)
      		{
      			int j = this->items[i].col;
      			arra[j]++;
      		}
      		//创建并初始化累计列频数数组
      		int* copt = new int[cols];
      		copt[0] = 0;
      		for (int i = 1; i < cols; i++)
      		{
      			copt[i] = copt[i - 1] + arra[i - 1];
      		}
      		//创建转置矩阵
      		Triplet<ElemType>* data = new Triplet<ElemType>[10];
      		memcpy(data, this->items, this->length * sizeof(Triplet<ElemType>));		//内存拷贝函数将items复制到data
      		//对转置矩阵的三元组重新进行排列
      		for (int i = 0; i < this->length; i++)
      		{
      			//提取当前三元组的列数
      			int col = this->items[i].col;
      			//根据列频数和累计列频数,找到当前元素需要存放的位置
      			int location = copt[col];
      			//为转置矩阵赋值
      			//调用三元组的有参构造函数
      			data[location] = Triplet<ElemType>(this->items[i].col, this->items[i].row, this->items[i].e);
      			/*
      			//一次对三元组的数据成员赋值
      			data[location].row = this->items[i].col;
      			data[location].col = this->items[i].row;
      			data[location].e = this->items[i].e;
      			*/
      			//存放完成后,cpot数组对应的位置要+1,以便下次该列存储下一个三元组
      			copt[col]++;
      
      		}
      		//转置矩阵的输出
      		int k = 0;
      		cout.setf(ios::right);
      		cout << "Transpose Matrix: " << endl;
      		for (int i = 0; i < cols; i++)
      		{
      			for (int j = 0; j < rows; j++)
      			{
      				ElemType v = ElemType();
      				if (k < this->length && i == data[k].row && j == data[k].col  )
      				{
      					v = data[k].e;			//如果存在元素,就改为元素值
      					k++;
      				}
      				cout << setw(4) << v;
      			}
      			cout << endl;
      		}
      		cout << endl;
      	}
      
      
      };
      
    • “SparseMatrix.cpp”

      #include <iostream>
      #include "./SparseMatrix.hpp"
      using namespace std;
      
      int main()					//测试稀疏矩阵及其运算
      {							//新建一个稀疏矩阵	
      	SparseMatrix<int> m(6, 7);
      	m.append(Triplet<int>(0, 1, 12));
      	m.append(Triplet<int>(0, 2, 9)); 
      	m.append(Triplet<int>(2, 0, -3)); 
      	m.append(Triplet<int>(2, 4, 14)); 
      	m.append(Triplet<int>(3, 2, 24)); 
      	m.append(Triplet<int>(4, 1, 18)); 
      	m.append(Triplet<int>(5, 0, 15)); 
      	m.append(Triplet<int>(5, 3, -7)); 
      	m.output();				//测试稀疏矩阵的输出
      
      	m.get(0, 2);			//测试稀疏矩阵的查找
      	m.get(0, 3);
      
      	m.transposeMatrix();	//测试稀疏矩阵的快速转置方法的实现
      }
      
    • 运行截图:

hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » 数据结构实验(三)