顺序表(C++实现)

1. 思维导图

        一张简单的思维导图有助于你理解顺序表的一些特性,下面是一张简单的顺序表思维导图:

顺序表思维导图

 

2. 代码实现

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
using namespace std;

#define InitSize 5

template<typename T>
struct SeqList {
	T* data;
	int length;
	int maxSize;
};

struct Person {
	string name;
	int age;

	// << 运算符重载
	friend ostream& operator<<(ostream& output, const Person& p) {
		output << "Name: " << p.name << "   Age: " << p.age << endl;
		return output;
	}

	// == 运算符重载
	bool operator==(const Person& p) const {
		return (name == p.name && age == p.age);
	}
};

template<typename T>
void printValue(T value) {
	cout << value << "  ";
}

template<typename T>
class Test {

public:
	SeqList<T> seqList;

	// 无参构造
	Test() {
		InitList();
	}

	// 有参构造
	Test(T value) {
		InitList();
		this->seqList.data[0] = value;
		this->seqList.length++;
	}

	// 拷贝构造
	Test(const Test<T>& t) {
		this->seqList.maxSize = t.seqList.maxSize;
		this->seqList.data = new T[this->seqList.maxSize];
		this->seqList.length = t.seqList.length;
		for (int i = 0; i < this->seqList.length; i++)
			this->seqList.data[i] = t.seqList.data[i];
	}

	// 初始化(静态分配)
	void InitList() {
		this->seqList.maxSize = InitSize;
		this->seqList.data = new T[this->seqList.maxSize];
		this->seqList.length = 0;
	}

	// 动态增加顺序表长度(动态分配)
	void UpdateList(int increment) {

		// 保存原有的数据
		T* temp = this->seqList.data;
		// 新分配内存,并拷贝原有数据
		this->seqList.data = new T[this->seqList.maxSize + increment];
		for (int i = 0; i < this->seqList.length; i++)
			this->seqList.data[i] = temp[i];
		// 更新数据容量
		this->seqList.maxSize += increment;
		// 释放原有数据占用的内存
		delete[] temp;
	}

	// 头补数据
	void PushHead(T value) {

		if (this->seqList.length == this->seqList.maxSize)
			UpdateList(1);

		for (int i = this->seqList.length; i > 0; i--)
			this->seqList.data[i] = this->seqList.data[i - 1];
		this->seqList.data[0] = value;
		this->seqList.length++;
	}

	// 头删数据
	void PopHead() {
		for (int i = 0; i < this->seqList.length - 1; i++)
			this->seqList.data[i] = this->seqList.data[i + 1];
		this->seqList.length--;
	}

	// 尾补数据
	void PushBack(T value) {
		if (this->seqList.length == this->seqList.maxSize)
			UpdateList(1);
		this->seqList.data[this->seqList.length] = value;
		this->seqList.length++;
	}

	// 尾删数据
	void PopBack() {
		this->seqList.length--;
	}

	// 在位序为 rank 的位置插入元素
	bool Insert(int rank, T element) {

		if (rank <1 || rank > this->seqList.length) {
			cout << "Error:Illegal insertion position!" << endl;
			return false;
		}

		if (this->seqList.length == this->seqList.maxSize)
			UpdateList(1);

		for (int i = this->seqList.length; i >= rank; i--)
			this->seqList.data[i] = this->seqList.data[i - 1];
		this->seqList.data[rank - 1] = element;
		this->seqList.length++;
		return true;
	}

	// 按位删除元素
	bool DeleteByRank(int rank) {

		if (rank <1 || rank > this->seqList.length) {
			cout << "Error:Illegal deletion location!" << endl;
			return false;
		}

		for (int i = rank - 1; i < this->seqList.length - 1; i++)
			this->seqList.data[i] = this->seqList.data[i + 1];
		this->seqList.length--;
		return true;
	}

	// 根据值删除元素(所有)
	void DeleteByValue(T value) {
		vector<int>* rank = this->SearchByValue(value);
		sort(rank->begin(), rank->end(), greater<int>());
		for_each(rank->begin(), rank->end(),
			std::bind(&Test::DeleteByRank, this, std::placeholders::_1));
		delete rank;
	}

	// 按值查找
	vector<int>* SearchByValue(T value) {

		vector<int> rank;
		for (int i = 0; i < this->seqList.length; i++)
			if (this->seqList.data[i] == value)
				rank.push_back(i + 1);

		if (rank.empty())
			cout << "Error:no value in sequence table!" << endl;
		vector<int>* vec = new vector<int>(rank);
		return vec;
	}

	// 按位修改
	bool UpdateByRank(int rank, T value) {

		if (rank <1 || rank > this->seqList.length) {
			cout << "Error:Illegal deletion location!" << endl;
			return false;
		}

		this->seqList.data[rank - 1] = value;
		return true;
	}

	// 按值修改
	void UpdateByValue(T originalValue, T newValue) {

		for (int i = 0; i < this->seqList.length; i++)
			if (this->seqList.data[i] == originalValue)
				this->seqList.data[i] = newValue;
	}

	// 清除顺序表
	void Clear() {
		this->seqList.length = 0;
	}

	// 打印
	void PrintList() {
		cout << "顺序表数据为:\n  ";
		for (int i = 0; i < this->seqList.length; i++)
			cout << this->seqList.data[i] << "  ";
		cout << endl;
	}
};

// 已有数据类型测试代码
void test01() {

	// First example
	cout << "t:" << endl;
	Test<int> t;

	// 头尾补、头尾删
	t.PushBack(56);
	t.PushBack(23);
	t.PushBack(56);
	t.PushBack(211);
	t.PushBack(56);
	t.PushBack(101);
	t.PushHead(110);
	t.PushHead(985);
	t.PushHead(13);
	t.PushHead(25);
	t.PushHead(777);
	t.PopBack();
	t.PopHead();
	t.PrintList();

	// 按值查找
	vector<int>* SBV = t.SearchByValue(56);
	for_each(SBV->begin(), SBV->end(), printValue<int>);
	cout << endl;

	// 按位插入
	t.Insert(1, 1024);
	t.PrintList();

	// 按位删除
	t.DeleteByRank(2);
	t.PrintList();

	// 按位修改
	t.UpdateByRank(2, 13 * 13);
	t.PrintList();

	// 按值修改
	t.UpdateByValue(56, 88);
	t.PrintList();

	// 按值查找
	SBV = t.SearchByValue(56);
	for_each(SBV->begin(), SBV->end(), printValue<int>);
	cout << endl;
	SBV = t.SearchByValue(88);
	for_each(SBV->begin(), SBV->end(), printValue<int>);
	cout << endl;

	// 按值删除
	t.DeleteByValue(88);
	t.PrintList();

	delete SBV;

	// Second example:拷贝构造
	cout << "t2:" << endl;
	Test<int> t2(t);
	t2.PrintList();


	// Third example:有参构造
	cout << "t3:" << endl;
	Test<int> t3(101);
	t3.PrintList();
}

// 自定义数据类型测试代码
void test02() {

	// First example
	cout << "l1:" << endl;
	Test<Person> l1;

	// 头尾补、头尾删
	l1.PushHead({ "Muller", 33 });
	l1.PushBack({ "Messi", 35 });
	l1.PushBack({ "Tony Kroos", 32 });
	l1.PushBack({ "Muller", 33 });
	l1.PushBack({ "Sane", 26 });
	l1.PushBack({ "Gavi", 19 });
	l1.PushBack({ "Muller", 33 });
	l1.PushBack({ "Neymar", 31 });
	l1.PrintList();

	l1.PopBack();
	l1.PopHead();
	l1.PrintList();

	// 按值查找
	vector<int>* SBV = l1.SearchByValue({ "Muller", 33 });
	for_each(SBV->begin(), SBV->end(), printValue<int>);
	cout << endl;

	// 按位插入
	l1.Insert(1, { "Ronaldo", 37 });
	l1.PrintList();

	// 按位删除
	l1.DeleteByRank(2);
	l1.PrintList();

	// 按位修改
	l1.UpdateByRank(2, { "Lewandowski", 34 });
	l1.PrintList();

	// 按值修改
	l1.UpdateByValue({ "Muller", 33 }, { "T.Muller", 33 });
	l1.PrintList();

	// 按值查找
	SBV = l1.SearchByValue({ "Muller", 33 });
	for_each(SBV->begin(), SBV->end(), printValue<int>);
	cout << endl;
	SBV = l1.SearchByValue({ "T.Muller", 33 });
	for_each(SBV->begin(), SBV->end(), printValue<int>);
	cout << endl;

	// 按值删除
	l1.DeleteByValue({ "T.Muller", 33 });
	l1.PrintList();

	delete SBV;

	// Second example:拷贝构造
	cout << "t2:" << endl;
	Test<Person> t2(l1);
	t2.PrintList();


	// Third example:有参构造
	cout << "t3:" << endl;
	Test<Person> t3({ "Muller", 33 });
	t3.PrintList();
}

int main() {

	//test01();
	test02();
	return  0;
}

3. 代码注意点

1.DeleteByValue函数

        Q:如何在类的一个成员函数中使用for_each算法调用另一个成员函数?

        A:可以使用lambda表达式或者std::bind将另一个成员函数绑定到一个函数对象上,然后把这个函数对象作为参数传递给for_each算法。举个例子,假设我们有一个类Foo,其中有两个成员函数f1和f2:      

class Foo {
public:
 void f1(int x) {
     // do something
 }

 void f2() {
     std::vector<int> v = {1, 2, 3, 4};
     std::for_each(v.begin(), v.end(),
         [=](int x){ f1(x); }); // 使用lambda表达式
     // 或者
     std::for_each(v.begin(), v.end(),
         std::bind(&Foo::f1, this, std::placeholders::_1)); // 使用std::bind
 }
};

        在f2函数中,我们可以使用lambda表达式或者std::bind将f1函数绑定到函数对象上,并将这个函数对象作为参数传递给for_each算法,从而实现在f2函数中调用f1函数。注意,在lambda表达式或者std::bind中,必须将当前对象的指针通过this传递进去,以确保能够调用类的成员函数。  

2.关于 const

  • const 修饰成员函数:声明中将其标记为 const,以确保它不会更改任何成员变量的值

  • const 修饰形参:可以有效地防止函数在处理参数时修改它们的值

  • const 关键字通常用于修饰类和类成员函数,用于指定变量或函数在程序执行期间不会更改

  • 对于全局函数,因为它们不属于类的一部分,也没有成员变量可以被限制为只读,在全局函数中使用 const 关键字是无效的

  • 全局常量可以使用 const 关键字来限定它们的值,例如:const int MAX_SIZE = 100;

3. 动态分配内存、释放内存

void UpdateList(int increment) {

    // 保存原有的数据
    T* temp = this->seqList.data;
    // 新分配内存,并拷贝原有数据
    this->seqList.data = new T[this->seqList.maxSize + increment];
    for (int i = 0; i < this->seqList.length; i++)
        this->seqList.data[i] = temp[i];
    // 更新数据容量
    this->seqList.maxSize += increment;
    // 释放原有数据占用的内存
    delete[] temp;
}

4.结构体运算符重载(待解答) 

        结构体运算符重载的代码中有一些目前还未考虑清楚的问题,现将相关代码呈现,希望水平更高的朋友解答一下!

struct Person {
    string name;
    int age;

    // << 运算符重载
    friend ostream& operator<<(ostream& output, const Person& p) {
        output << "Name: " << p.name << "   Age: " << p.age << endl;
        return output;
    }

    // == 运算符重载
    bool operator==(const Person& p) const {
        return (name == p.name && age == p.age);
    }
};

        第一篇博客,也算是迈出第一步,如有错误或者更好的思路,希望广大读者和朋友们指正,谢谢!

 

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值