目录
一、关于蛇形矩阵
1.界说:
2.输入:
3.输出与释放:
二、有序单循环链表的插入
1.链表结构的构建:
2.输入:
3.输出:
4.释放:
5.目录:
6.主函数:
*一些学到的新知识:
1.delete和free的区别:
2. nullptr和NULL的区别:
三、类计划题目
1.基类和继承类
2. 基类的建立:
3.派生类的建立:
四、结语
一、关于蛇形矩阵
1.界说:
矩阵的输入输出一般使用二维数组,由于其列数和行数由控制台输入,所以要界说的是一个动态二维数组,如下所示:
- int rows , cols;
- cin >> rows >> cols;
- //定义:
- int **arr = new int *[rows];
- for(int i = 0 ; i < rows ; i++)
- {
- arr[i] = new int [cols];
- }
复制代码 2.输入:
有了界说,下一步就是要思量怎样输入,通过观察蛇形矩阵的特点,思量边界条件和方向切换的情况,可以通过以下的方式进行输入:
- int rowStart = 0 , rowEnd = rows - 1;
- int colStart = 0 , colEnd = cols - 1;
- int num = 1;
- while (rowStart <= rowEnd && colStart <= colEnd)
- {
- //行(从左到右输入):从 colStart 列到 colEnd 列
- for (int i = colStart; i <= colEnd; i++)
- {
- arr[rowStart][i] = num;
- num = num + 1;
- }
- rowStart = rowStart + 1;//(输入完一行,使得开始行数加一)
- //列(从上往下输入):从 rowStart 行到 rowEnd 列
- for (int i = rowStart; i <= rowEnd; i++)
- {
- arr[i][colEnd] = num;
- num = num + 1;
- }
- colEnd = colEnd - 1;//(输入完一行,使得终止列数减一)
- //行(从右到左输入):从 colEnd 列到 colStart 列
- for (int i = colEnd; i >= colStart; i--)
- {
- arr[rowEnd][i] = num;
- num = num + 1;
- }
- rowEnd = rowEnd - 1;//(输入完一行,使得终止行数减一)
- //列(从下往上输入):从 rowEnd 行到 rowStart 列
- for (int i = rowEnd; i >= rowStart; i--)
- {
- arr[i][colStart] = num;
- num = num + 1;
- }
- colStart = colStart + 1;//(输入完一行,使得开始列数加一)
- }
复制代码 3.输出与释放:
接下来就是很通例的输出和内存的释放:
- //输出
- for(int i = 0 ; i < rows ; i++)
- {
- for(int j = 0 ; j < cols ; j++)
- {
- cout << setw(3) << arr[i][j];//setw()用于控制输出格式
- }
- cout << endl;
- }
- //释放内存:
- for(int i = 0 ; i < rows ; i++)
- {
- delete [] arr[i];
- }
- delete [] arr;
- arr = NULL;
复制代码 二、有序单循环链表的插入
关于链表,本次学习重要通过链表底子知识详解(非常详细简单易懂)-CSDN博客一文,下面是一些简单的感悟和代码誊写的思绪:
1.链表结构的构建:
(链表由一个个节点构成,每个节点一般接纳结构体的形式构造)
链表节点分为两个域
数据域:存放各种现实的数据
指针域:存放下一节点的首地点
- typedef struct Node
- {
- //数据域
- int data;
- //指针域
- struct Node* next;
- }node;
复制代码 2.输入:
- //node **p_head:使用指向指针的指针
- //原因:需要修改指向链表头部的指针。C++ 中的函数参数传递是值传递,
- // 即函数内对参数的修改不会影响到外部的实际参数。
- // 因此,如果想要在函数内修改外部的指针(比如修改链表头指针),就需要传入指针的指针,
- // 这样在函数内修改指针的指向就可以影响到外部的实际指针。
- //node *p_new:插入的新节点
- //原因:由于只需要修改新节点本身的数据域和指针域,并不需要修改该节点在外部的指向,
- // 所以直接传入指针即可
- void link_insert_data(node **p_head , node *p_new)
- {
- //定义两个指针pb和pf,用来遍历链表。
- node *pb,*pf;
- //将pb和pf初始化为指向链表头部的指针
- pb = pf = *p_head;
- //链表为空链表:
- if(*p_head == nullptr)
- {
- //新节点p_new作为链表的头节点
- *p_head = p_new;
- //将新节点的next指针置为nullptr,表示新节点是链表中的最后一个节点
- p_new->next = nullptr;
- return;
- }
- //链表非空链表:
- //查找新节点应该插入的位置
- while((p_new->data >= pb->data) && (pb->next !=nullptr) )
- {
- pf = pb;
- pb = pb->next;//继续向后遍历
- }
- //找到一个节点的num比新来的节点num大,插在pb的前面
- if(p_new->data < pb->data)
- {
- //找到的节点是头节点,插在最前面
- if(pb == *p_head)
- {
- p_new->next = *p_head;
- *p_head = p_new;
- }
- //找到的节点不是头节点,将新节点插入到找到的节点(pf所指)之前。
- else
- {
- pf->next = p_new;
- p_new->next = pb;
- }
- }
- //没有找到比新节点数据(p_new->data)大的节点,则新节点应该插在链表的最后
- else
- {
- pb->next = p_new;
- p_new->next = nullptr;
- }
- }
复制代码- //大概还可以写成:(是一些尝试过程中的产物)
- //输入不太一样,但效果应该差不多
- void insertInSortedCircularLinkedList(node *head, int value)
- {
- node *p_new = new Node();
- p_new->data = value;
- p_new->next = nullptr;
- if (head == nullptr)
- {
- // 空链表情况
- head = p_new;
- p_new->next = p_new; // 让新节点指向自身,构成循环
- }
- else if (value <= head->data)
- {
- // 新节点的值比头节点小或等于头节点的值,插入到头部
- p_new->next = head;
- node *last = head;
- while (last->next != head)
- {
- last = last->next; // 找到最后一个节点
- }
- last->next = p_new; // 更新尾节点的 next 指针
- head = p_new; // 更新头节点
- }
- else
- {
- // 中间或尾部插入
- node *current = head;
- while (current->next != head && current->next->data < value)
- {
- current = current->next;
- }
- p_new->next = current->next;
- current->next = p_new;
- }
- }
- 或者:
- node* insertInSortedCircularLinkedList(node *head, int value)
- {
- node* newNode = new Node();
- //使用 new 运算符在堆内存中动态分配了一个 Node 类型的对象,并将返回的地址赋给指针 newNode
- newNode->data = value;
- if (head == nullptr)
- {
- newNode->next = newNode;
- return newNode;
- }
- node* pb = head ;
- node* pf = nullptr;
- do
- {
- pf = pb;
- pb = pb->next;
- }
- while (pb != head && newNode->next >= pb->data);
- if (pb == head)
- {
- newNode->next = head;
- pf->next = newNode;
- return newNode;
- }
- pf->next = newNode;
- newNode->next = pb;
- return head;
- }
复制代码 3.输出:
- void link_print(node *head)
- {
- if (head == nullptr)
- {
- cout << "链表为空" << endl;
- return;
- }
- node *p_mov;
- //定义新的指针保存链表的首地址,防止使用head改变原本链表
- p_mov = head;
- //当指针回到头结点时,表示已经遍历完整个循环链表
- //当指针保存最后一个结点的指针域为nullptr时,循环结束
- while(p_mov != nullptr)
- {
- //先打印当前指针保存结点的指针域
- cout << p_mov->data << " ";
- //指针后移,保存下一个结点的地址
- p_mov = p_mov->next;
- }
- cout << endl;
- }
复制代码- //也可以写成do-while 循环的形式,效果一样
- do
- {
- //先打印当前指针保存结点的指针域
- cout << p_mov -> data << " ";
- //指针后移,保存下一个结点的地址
- p_mov = p_mov -> next;
- } while(p_mov != head);
复制代码 4.释放:
- //加入之后会使退出变得非常卡顿,在此留疑
- void freeCircularLinkedList(node* head)
- {
- if (head == nullptr)
- {
- return;
- }
- //定义一个指针变量保存头结点的地址
- node* current = head;
- node* temp;
- do{
- temp = current;
- current = current -> next;
- delete temp;
- } while (current != head);
- }
复制代码 5.目录:
- void menu(node*& head)
- {
- cout << "****** Data Structure ******" << endl;
- cout << "1——有序插入单列表" << endl;
- cout << "2——查看单列表" << endl;
- cout << " 退出,请输入0" << endl;
- int sel;
- while(cin >> sel)
- {
- if(sel == 0)
- {
- //freeCircularLinkedList(head);
- cout << endl << "期待您的下次使用!" ;
- break;
- }
- switch(sel)
- {
- case 1:
- {
- node* p_new = new Node();//申请一个新节点
- cout << "请输入要插入的值:"; //给新节点赋值
- cin >> p_new->data;
- p_new->next = nullptr;
- link_insert_data(&head,p_new);
- break;
- }
- case 2:
- {
- link_print(head);
- break;
- }
- default:
- {
- cout << endl;
- cout << "您输入数字有误,请重新输入:";
- break;
- }
- }
- }
- }
复制代码 6.主函数:
- int main()
- {
- node* head = nullptr;
- menu(head);
- return 0;
- }
复制代码 *一些学到的新知识:
1.delete和free的区别:
delete 和 free 是释放内存的两种方式,重要用于释放动态分配的内存,但在 C++ 和 C 语言中有一些区别:
delete:
delete 是 C++ 中的关键字,用于释放使用 new 运算符动态分配的单个对象或对象数组的内存。
delete 会调用对象的析构函数,然后释放内存空间。
使用 delete 释放指向对象的指针后,指针会主动设置为 nullptr。
不能用 delete 来释放使用 malloc() 或 calloc() 分配的内存。
free:
free 是 C 语言中的函数,用于释放动态分配的内存。
free 只是简单地释放内存,不会调用任何析构函数。
调用 free 后,指针并不会被主动置空,可能会导致野指针问题。
不能用 free 来释放使用 new 运算符分配的内存。
总的来说,如果在 C++ 中动态分配了内存,应该使用 delete 进行释放;在 C 语言中动态分配内存则应使用 free 进行释放。在 C++ 中,最好避免混合使用 new/delete 和 malloc/free,以避免因为差别的释放方式导致的问题。
2. nullptr和NULL的区别:
在C++中,nullptr 是 C++11 中引入的空指针常量,用于表示空指针。而 NULL 在较早的 C++ 尺度中就存在,通常被界说为宏或者整数 0,也用于表示空指针。
区别:
- nullptr 是 C++11 引入的空指针常量,具有明白的空指针类型,可以隐式转换为任意指针类型,且不会与整数 0 肴杂。
- NULL 在较早的 C++尺度中就存在,通常被界说为宏或者整数 0,可能会与整数 0 肴杂,不具有明白的空指针类型。
*最好使用nullptr 来表示空指针,因为它更加明白和安全,避免了与整数 0 的肴杂。
三、类计划题目
1.基类和继承类
在写此题目之前,必要提前了解什么是基类和继承类,本次学习通过Th3.11:基类与派生类关系之详细再讨论_派生类是基类的子集-CSDN博客一文了解,在此仅简述其运用方法:
class Dad {};
class Son : public Dad {};
//C++中给出了final关键字,可以防止误用了不想当基类的类作为基类
类型1
class Dad final {//让不想做基类的Dad类声明为final的!
public:
/*...*/
};
class Son : public Dad {//错误!Dad不能用作基类
public:
/*...*/
};
类型2
class Dad {
public:
/*...*/
};
class Son final : public Dad {//让不想做基类的Son类声明为final的!
public:
/*...*/
};
class GrandSon:public Son{//错误!Son不能用作基类
public:
/*...*/
}
多余不再赘述
2. 基类的建立:
- #ifndef ACCOUNT_H
- #define ACCOUNT_H
- using namespace std;
- class Account
- {
- private:
- double balance;
- public:
- Account()
- {
- }
- Account(double Balance)
- {
- if (Balance >= 0)
- {
- balance = Balance;
- }
- else
- {
- balance = 0;
- cout << "\t\t该初始化余额是一个无效的值,已将账户余额定义为0" << endl;
- }
- }
- ~Account()
- {
- }
- void credit(double amount)
- {
- balance = balance + amount;
- }
- void debit(double amount)
- {
- if (amount > balance)
- {
- cout << endl << "\t\tDebit amount exceeded account Balance." << endl;
- }
- else
- {
- balance = balance - amount;
- }
- }
- double getBalance() const
- {
- return balance;
- }
- };
- #endif // ACCOUNT_H
复制代码 3.派生类的建立:
- #ifndef SAVINGSACCOUNT_H
- #define SAVINGSACCOUNT_H
- #include "Account.h"
- using namespace std;
- class SavingsAccount : public Account
- {
- private:
- double Rate;
- int Year;
- public:
- SavingsAccount()
- {
- }
- SavingsAccount(double Balance , double rate , int year) :
- Account(Balance) , Rate(rate) , Year(year){}
- ~SavingsAccount()
- {
- }
- double calculate()
- {
- double total = getBalance();
- for (int i = 1; i <= Year; i++)
- {
- double interest = total * Rate * 0.01;
- total = total + interest;
- }
- return total;
- }
- };
- #endif // SAVINGSACCOUNT_H
复制代码 4.主函数的建立:
(利用C++中的控制台界面来实现可视化菜单操纵(大概可以算是某种程度上的可视化))
- #include <iostream>
- #include "SavingsAccount.h"
- using namespace std;
- void menu(SavingsAccount &account)
- {
- system("cls");
- cout << "\t\t************************************" << endl;
- cout << "\t\t当前余额为:" << account.getBalance() << endl;
- cout << "\t\t************************************" << endl;
- cout << "\t\t****** 1.存款 ******" << endl;
- cout << "\t\t****** 2.取款 ******" << endl;
- cout << "\t\t****** 3.算存款之后的总余额 ******" << endl;
- cout << "\t\t****** 0.退出 ******" << endl;
- cout << "\t\t************************************" << endl;
- cout << "\t\t请输入您的选择:";
- }
- int main()
- {
- double Balance , amount;
- cout << "\t\t创建一个账户,并输入初始余额:";
- cin >> Balance;
- cout << endl;
- SavingsAccount account(Balance , 0 , 0);
- system("pause");//请按任意键继续
- menu(account);
- int sel;
- while(cin >> sel)
- {
- cout << endl;
- if(sel == 0)
- {
- cout << "\t\t期待您的下次使用!" ;
- exit(0);
- //exit(0)函数可以立即终止程序的执行,并返回给操作系统。
- //参数0表示正常退出,非零值表示异常退出
- }
- switch(sel)
- {
- case 1:
- cout << "\t\t请输入存款金额:";
- cin >> amount;
- account.credit(amount);
- cout << endl;
- system("pause");//请按任意键继续
- menu(account);
- break;
- case 2:
- cout << "\t\t请输入取款金额:";
- cin >> amount;
- account.debit(amount);
- cout << endl;
- system("pause");//请按任意键继续
- menu(account);
- break;
- case 3:
- double rate;
- int year;
- cout << "\t\t请输入存款年利率(单位:%):";
- cin >> rate;
- cout << "\t\t请输入存款年份:";
- cin >> year;
- cout << endl;
- account = SavingsAccount(account.getBalance() , rate , year);
- cout << "\t\t账户经过" << year <<
- "年(年利率为:" << rate << ")后,账户的总余额为:" <<
- account.calculate() << endl;
- cout << endl;
- system("pause");//请按任意键继续
- menu(account);
- break;
- default:
- cout << "\t\t您输入数字有误,请重新输入:";
- break;
- }
- }
- return 0;
- }
复制代码 *本来想实行一下改配景颜色,但是不太好看就没改,在此附上修改方式,参考c++可视化操纵(一)——控制台点击型菜单(windows.h)-CSDN博客一文
#include <Windows.h>
//配景白色
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(handle, BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
// 将文本颜色设置为淡蓝色
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(handle, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
四、结语
本次学习到此竣事啦,虽然可能程序上另有很多的不敷(欢迎各位指正),还是感谢各位可以看我写到这里。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |