day7: homework

This commit is contained in:
flykhan 2023-08-01 21:46:18 +08:00
parent aae9aba049
commit 5ab334d200
8 changed files with 509 additions and 0 deletions

41
day7/homework/h1.cpp Normal file
View File

@ -0,0 +1,41 @@
#include <iostream>
using namespace std;
// 前置声明否则会报错因为下面的友元函数模版中使用了Pair模版
template <typename T1, typename T2>
class Pair;
template <typename T1, typename T2>
ostream &operator<<(ostream &out, const Pair<T1, T2> &p);
template <typename T1, typename T2>
class Pair
{
// 使用外部实现友元函数的方式,需要添加<>空泛型标识,否则编译器会认为是重复声明
friend ostream &operator<<<>(ostream &out, const Pair<T1, T2> &p);
private:
T1 first;
T2 second;
public:
Pair(T1 f, T2 s) : first(f), second(s) {}
T1 getFirst() const { return first; }
T2 getSecond() const { return second; }
};
template <typename T1, typename T2>
ostream &operator<<(ostream &out, const Pair<T1, T2> &p)
{
out << p.getFirst() << " " << p.getSecond();
return out;
}
int main()
{
Pair<string, int> p1 = Pair<string, int>("x", 20);
Pair<string, string> p2 = Pair<string, string>("name", "disen");
// cout << p1 << endl;
cout << p1 << "," << p2 << endl;
return 0;
}

36
day7/homework/h1_2.cpp Normal file
View File

@ -0,0 +1,36 @@
#include <iostream>
using namespace std;
template <typename T1, typename T2>
class Pair
{
// 使用友元函数模版的方式,可以避免重复声明
template <typename U1, typename U2>
friend ostream &operator<<(ostream &out, const Pair<U1, U2> &p);
private:
T1 first;
T2 second;
public:
Pair(T1 f, T2 s) : first(f), second(s) {}
T1 getFirst() const { return first; }
T2 getSecond() const { return second; }
};
template <typename U1, typename U2>
ostream &operator<<(ostream &out, const Pair<U1, U2> &p)
{
out << p.getFirst() << " " << p.getSecond();
return out;
}
int main()
{
Pair<string, int> p1 = Pair<string, int>("x", 20);
Pair<string, string> p2 = Pair<string, string>("name", "disen");
// cout << p1 << endl;
cout << p1 << "," << p2 << endl;
return 0;
}

42
day7/homework/h2_1.cpp Normal file
View File

@ -0,0 +1,42 @@
// 请简述static_cast、dynamic_cast和reinterpret_cast的区别并给出示例代码进行说明。
// static_cast :
// 静态转换,用于基本类型的转换、隐式转换、向上转换和非多态类之间的转换。它在编译时进行类型检查,并且只能用于具有相关性的类型之间的转换。因为没有运行时类型检查,不能用于多态类的向下转换(即将基类指针或引用转换为派生类指针或引用)。
#include <iostream>
using namespace std;
int num = 10;
double res = static_cast<double>(num); // 将整数类型转换为浮点数类型
class Base
{
public:
virtual void foo()
{
cout << "基类 foo() 函数" << endl;
} // 基类的虚函数
};
class Derived : public Base
{
public:
void bar()
{
cout << "派生类 bar() 函数" << endl;
} // 派生类的成员函数
void foo()
{
cout << "派生类 foo() 函数" << endl;
} // 派生类的虚函数: 重写基类的虚函数
};
int main()
{
Base *p = new Derived();
Derived *dp = static_cast<Derived *>(p); // 向下转换,不安全
dp->bar(); // 但是可以调用派生类的成员函数
dp->foo();
return 0;
}

41
day7/homework/h2_2.cpp Normal file
View File

@ -0,0 +1,41 @@
// 请简述static_cast、dynamic_cast和reinterpret_cast的区别并给出示例代码进行说明。
// dynamic_cast :
// 动态转换用于多态类之间的转换即在基类指针或引用和派生类指针或引用之间进行转换。它在运行时进行类型检查如果转换是安全的则返回转换后的指针或引用如果转换不安全则返回空指针或引用。dynamic_case 只能用于具有虚函数的类之间的转换。
#include <iostream>
using namespace std;
class Base
{
public:
virtual void foo() { cout << "基类 foo() 函数" << endl; }
};
class Derived : public Base
{
public:
void bar() { cout << "派生类 bar() 函数" << endl; }
void foo() { cout << "派生类 foo() 函数" << endl; }
};
int main()
{
Base *p = new Derived();
Derived *dp = dynamic_cast<Derived *>(p); // 向下转换,安全
dp->bar(); // 可以调用派生类的成员函数
dp->foo(); // 可以调用派生类的虚函数
Base *p1 = new Base();
Derived *dp1 = dynamic_cast<Derived *>(p1); // 向下转换,不安全
dp1->bar();
// dp1->foo();
Derived *dp2 = new Derived();
Base *p2 = dynamic_cast<Base *>(dp2); // 向上转换,安全
p2->foo();
return 0;
}

25
day7/homework/h2_3.cpp Normal file
View File

@ -0,0 +1,25 @@
// 请简述static_cast、dynamic_cast和reinterpret_cast的区别并给出示例代码进行说明。
// reinterpret_cast :
// 重新解释转换,用于不同类型之间的强制转换,即将一个指针或引用转换为完全不相关的类型。它可以将任何指针类型转换为其他指针类型,也可以将整数类型转换为指针类型,反之亦然。它非常危险,不进行类型检查。
#include <iostream>
using namespace std;
int num = 10;
int *np = &num;
double *dp = reinterpret_cast<double *>(np); // 将整数类型指针转换为浮点数类型指针
class Base
{
public:
virtual void foo() {}
};
int main()
{
Base *base = new Base();
int *intp = reinterpret_cast<int *>(base); // 将基类指针转换为整数类型指针
return 0;
}

87
day7/homework/h3.cpp Normal file
View File

@ -0,0 +1,87 @@
// 设计一个模板类 Stack实现基本的堆栈功能包括入栈push、出栈pop、获取栈顶元素top和判断栈是否为空isEmpty等操作。
// 【提示】Stack栈结构的特性是FILO(先进后出)
#include <iostream>
using namespace std;
template <typename T>
class Stack
{
private:
int capacity; // 容量
int size; // 已存数量计数器
T *arr; // 指向数组的指针
public:
Stack(int capacity)
{
this->capacity = capacity;
this->arr = new T[capacity];
this->size = 0;
}
Stack(const Stack<T> &other)
{
this->capacity = other.capacity;
this->size = other.size;
this->arr = new T[capacity];
for (int i = 0; i < size; i++)
{
this->arr[i] = other.arr[i];
}
}
~Stack()
{
delete[] arr;
}
public:
// & 用于返回引用,支持链式调用
Stack &push(T val)
{
if (size == capacity)
{
cout << "栈已经满了!" << endl;
return *this;
}
arr[size++] = val;
return *this; // 返回自身,支持链式调用
}
T pop()
{
if (size == 0)
{
cout << "栈已经空了!" << endl;
return -1;
}
return arr[--size]; // 先减再取因为size是计数器指向下一个空位
}
T top()
{
if (size == 0)
{
cout << "栈已经空了!" << endl;
return -1;
}
return arr[size - 1]; // 直接取顶部元素
}
string isEmpty()
{
return size == 0 ? "栈空" : "栈未空"; // 判断计数器是否为 0为 0 表示栈空
}
};
int main()
{
Stack<int> s(5);
s.push(1).push(2).push(3).push(4).push(5);
cout << s.pop() << endl; // 5
cout << s.pop() << endl; // 4
cout << s.top() << endl; // 3
cout << s.isEmpty() << endl; // 栈未空
cout << s.pop() << endl; // 3
cout << s.pop() << endl; // 2
cout << s.pop() << endl; // 1
cout << s.isEmpty() << endl; // 栈空
cout << s.pop() << endl; // 栈已经空了! -1
return 0;
}

96
day7/homework/h4.cpp Normal file
View File

@ -0,0 +1,96 @@
// 设计一个模板类 Queue实现基本的队列功能包括入队enqueue、出队dequeue、获取队首元素front和判断队列是否为空isEmpty等操作。
// 【提示】Queue队列结构的特性是FIFO(先进先出)
#include <iostream>
using namespace std;
template <typename T>
class Queue
{
private:
int capacity; // 容量
int size; // 已存数量计数器
T *arr; // 指向数组的指针
public:
Queue(int capacity)
{
this->capacity = capacity;
this->arr = new T[capacity];
this->size = 0;
}
Queue(const Queue<T> &other)
{
this->capacity = other.capacity;
this->size = other.size;
this->arr = new T[capacity];
for (int i = 0; i < size; i++)
{
this->arr[i] = other.arr[i];
}
}
~Queue()
{
delete[] arr;
}
public:
Queue &enqueue(T val)
{
if (size == capacity)
{
cout << "队列已满!" << endl;
return *this;
}
arr[size++] = val;
return *this;
}
T dequeue() // 取出队首元素,并删除
{
if (size == 0)
{
cout << "队列已空!" << endl;
return -1;
}
T val = arr[0]; // 取出队首元素
for (int i = 0; i < size - 1; i++)
{
arr[i] = arr[i + 1]; // 元素前移
}
size--; // 计数器减一
return val; // 返回队首元素
}
T front() // 只是返回队首元素,并不删除
{
if (size == 0)
{
cout << "队列已空!" << endl;
return -1;
}
return arr[0];
}
string isEmpty()
{
return size == 0 ? "队列空" : "队列未空";
}
};
int main()
{
Queue<float> q(5);
q.enqueue(1.1).enqueue(2.2).enqueue(3.3).enqueue(4.4).enqueue(5.5);
cout << q.dequeue() << endl; // 1.1
cout << q.front() << endl; // 2.2
q.enqueue(6.6);
q.enqueue(7.7); // 队列已满
q.dequeue();
q.dequeue();
cout << q.dequeue() << endl; // 4.4
cout << q.isEmpty() << endl; // 队列未空
cout << q.dequeue() << endl; // 5.5
cout << q.dequeue() << endl; // 6.6
cout << q.isEmpty() << endl; // 队列空
cout << q.dequeue() << endl; // 队列已空
return 0;
}

141
day7/homework/h5.cpp Normal file
View File

@ -0,0 +1,141 @@
// 设计一个模板类 LinkedList实现基本的链表功能包括插入节点insert、删除节点remove、查找节点search等操作 通过全局友元函数,实现列表的打印功能。
#include <iostream>
using namespace std;
template <typename T>
class LinkedList
{
// 使用友元函数模版的方式,可以避免重复声明
template <typename U>
friend ostream &operator<<(ostream &out, const LinkedList<U> &list);
private:
// 只能在类内部使用的私有结构体
struct Node // 节点结构体,定义数据结构,包括数据和指针
{
T val; // 节点的值
Node *next; // 指向下一个节点的指针
Node(T val) // 构造函数,用于初始化节点
{
this->val = val;
this->next = nullptr;
}
};
Node *head;
int size;
public:
LinkedList()
{
this->head = nullptr;
this->size = 0;
}
LinkedList(const LinkedList<T> &other)
{
this->head = nullptr;
this->size = 0;
Node *p = other.head;
while (p != nullptr)
{
this->insert(p->val);
p = p->next;
}
size = other.size; // 计数器赋值
}
~LinkedList()
{
Node *p = head; // 从头节点开始
while (p != nullptr) // 当前节点不为空时,循环
{
Node *q = p->next; // 保存下一个节点的指针
delete p; // 删除当前节点
p = q; // p 重新指向保存的下一个节点 q
}
size = 0; // 计数器清零
}
public:
LinkedList &insert(T val)
{
Node *node = new Node(val); // 创建新节点
if (head == nullptr)
{
head = node; // 如果头节点为空,直接将新节点赋值给头节点
return *this; // 如果头节点为空,直接返回
}
Node *p = head;
while (p->next != nullptr)
{
p = p->next; // 找到最后一个节点
}
p->next = node; // 将新节点插入到最后一个节点的后面
size++; // 计数器加一
return *this; // 返回当前对象
}
LinkedList &remove(T val)
{
if (head == nullptr)
{
cout << "链表为空,无法删除" << endl;
return *this; // 如果头节点为空,直接返回
}
Node *p = head;
if (p->val == val) // 如果头节点的值等于要删除的值
{
head = p->next; // 将头节点的下一个节点赋值给头节点
delete p; // 删除头节点
size--; // 计数器减一
return *this; // 返回当前对象
}
while (p->next != nullptr && p->next->val != val)
{
p = p->next; // 找到要删除的节点的前一个节点
}
if (p->next == nullptr) // 找到最后也没有找到要删除的节点
{
cout << "未找到要删除的节点" << endl;
return *this; // 如果未找到要删除的节点,直接返回
}
Node *q = p->next; // 保存要删除的节点
p->next = q->next; // 将要删除的节点的下一个节点赋值给要删除的节点的前一个节点的下一个节点
delete q; // 删除要删除的节点
size--; // 计数器减一
return *this; // 返回当前对象
}
Node *search(T val)
{
Node *p = head;
while (p != nullptr && p->val != val)
{
p = p->next; // 找到要删除的节点的前一个节点
}
return p; // 返回找到的节点,如果未找到,返回 nullptr
}
};
template <typename U>
ostream &operator<<(ostream &out, const LinkedList<U> &list)
{
LinkedList p = list; // 从头节点开始
while (p != nullptr) // 遍历链表
{
out << p->val << " "; // 输出节点的值
p = p->next; // 指向下一个节点
}
out << endl; // 最后输出换行
return out; // 返回输出流对象
}
int main()
{
LinkedList<double> list; // 创建一个链表
list.insert(1.1).insert(2.2).insert(3.3).insert(4.4).insert(5.5); // 插入节点
cout << list; // 输出链表
Node *tmp = list.search(3.3); // 查找节点
cout << tmp->val << endl;
list.remove(3.3); // 删除节点
cout << list; // 输出链表
return 0;
}