为什么我这么喜欢防御性编程和断言呢,因为他能对错误的参数及操作能过进行相应的操作,不至于程序崩溃
## 防御性编程
防御性编程(Defensive programming)是防御式设计的一种具体体现,它是为了保证,对程序的不可预见的使用,不会造成程序功能上的损坏。它可以被看作是为了减少或消除墨菲定律效力的想法。防御式编程主要用于可能被滥用,恶作剧或无意地造成灾难性影响的程序上。
断言
断言是编程术语,表示为一些布尔表达式,程序员相信在程序中的某个特定点该表达式值为真,可以在任何时候启用和禁用断言验证,因此可以在测试时启用断言而在部署时禁用断言。同样,程序投入运行后,最终用户在遇到问题时可以重新启用断言。
使用断言可以创建更稳定、品质更好且 不易于出错的代码。当需要在一个值为FALSE时中断当前操作的话,可以使用断言。单元测试必须使用断言
单链表的操作, 就像这个链子一样… 读者自己揣摩吧, 本人是真的懒…
初始化链表
就是把头节点的指针域置为NULL
前插法插入元素
头节点为 head 头节点的指针域为 head->next
插入节点为 node, 插入节点的指针域为 node->next
操作: node->next = head->next;
head->next = node;
尾插法插入元素
尾插法插入元素就只多了一步, 找到最后一个节点!!!
找到最后一个节点后 插入节点的指针域置为NULL (插入节点->next = NULL)
原先最后一个节点的指针域指向插入节点… (最后一个节点->next = 插入节点)
任意位置插入元素
**任意位置插入节点: 原理就是找到插入位置的前一个节点
插入节点的指针域指向该节点的下一个节点 (插入节点->next = 该节点->next)
把该节点的指针域指向插入节点 (该节点->next = 插入节点)
**
其他相关操作也和上述类似, 不明白的时候,画图可以让你更清晰或更迷茫, 哈哈哈哈哈哈哈!!!
单链表的基本操作
#include <iostream>
#include <Windows.h>
#include <stdio.h>
// #define MAX_SIZE 100 // 链表虽然是可以无限添加,但是得有一个上限!!! 这里就不是实现了
// 单链表的定义
typedef int ElemType;
typedef struct node {
ElemType date;
struct node *next;
}LinkList, LinkNode;
// 初始化链表
// 链表多种多样, 根据需求写相应的函数...
bool initList(LinkList** head) {
(*head) = new LinkList;
if(!*head) return false;
(*head)->date = 0; // 头节点可以使用也可以不使用( 可以存放元素 )
(*head)->next = NULL;
return true;
}
// 添加元素1(前插法)
bool linkInsertFront(LinkList** head, ElemType& e) {
if(!*head) return false;
LinkNode* p = new LinkNode;
if(!p) return false;
p->date = e;
p->next = (*head)->next;
(*head)->next = p;
return true;
}
// 添加元素2 (尾插法)
bool linkInsertBack(LinkList** head, ElemType& e) {
if(!*head) return false;
LinkNode* p = *head;
LinkNode* s = NULL;
while(p->next) { // p->next 等NULL时 推出循环 p指向最后一个节点
p = p->next;
}
s = new LinkNode;
if(!s) return false;
s->date = e;
s->next = NULL; // s->next = p->next; // p->next 一定是NULL
p->next = s;
return true;
}
// 插入元素1 (按值插入) 插在该值的前面还是后面取决自己
// 这里是插在该值的后面
bool linkInsertNum(LinkList** head, ElemType& e, ElemType& num) {
if(!*head || !(*head)->next) return false; //判断是否存在节点
LinkNode* p = (*head)->next; // 指向第一个节点
LinkNode* s = NULL;
while(p) {
if(p->date == num) break;
p = p->next;
}
if(!p) return false;
s = new LinkNode;
if(!s) return false;
s->date = e;
s->next = p->next;
p->next = s;
return true;
}
// 插入元素 (按位置插入) 插在该位置的前面还是后面取决自己
// 这里是插在这个位置之前
bool listInsertSite(LinkList** head, ElemType& e, int site) {
if(!*head) return false;
if(site < 1) return false;
LinkNode* p = *head;
LinkNode* s = NULL;
int count = 1;
while(p && count < site) {
p = p->next;
count++;
}
if(!p) return false; // 说明插入位置不存在(比如3个位置, 你要插在5的位置)
s = new LinkNode;
if(!s) return false;
s->date = e;
s->next = p->next;
p->next = s;
return true;
}
// 删除节点
bool linkDelete(LinkList** head, const int i) {
if(!*head) return false;
if(i<1) return false;
LinkNode* p = *head;
LinkNode* s = NULL;
int count = 1;
while(p && count < i) { // 找到删除节点的前一个节点
p = p->next;
count++;
}
if(!p || !p->next) return false;
s = p->next;
p->next = s->next;
delete s;
return true;
}
//单链表的销毁
bool linkDestroy(LinkList** head) {
if(!*head) return false;
LinkNode* p = *head;
while(p) {
*head = p->next;
delete p;
p = *head;
}
*head = NULL;
return true;
}
// 单链表的遍历
void linkPrint(LinkList* head) {
if(!head || !head->next) return;
while(head) {
printf("%d ", head->date);
head = head->next;
}
printf("\n");
}
// 获取元素
bool linkGetElem(LinkList*head, ElemType& e, const int i) {
if(!head) return false;
if(i<1) return false;
head = head->next; // 指向第一个节点
int count = 1;
while(head&& count < i) {
head = head->next;
count++;
}
if(!head) return false;
e = head->date;
return true;
}
// 查找元素
int linkFindElem(LinkList* head, ElemType* e) {
if(!head || !e) return -1;
LinkNode* p = head->next;
int count = 1;
while(p) {
if(p->date == *e) break;
p = p->next;
count++;
}
if(!p) return -1;
return count;
}
// 测试代码就不写了, 懒虫上身, 在vs2019进行了简单的测试
嗯… 这个不是看的, 只是说明,我当时测试过了, 反正你们看不懂, 还是自己写测试代码吧!
**本文为本人学习过程, 欢迎大佬做出点评, 让我的不足之处得到改善,致敬IT大佬 **
测试的很马虎, 如果有什么问题, 欢迎提出, 因为我也不知道对不对!!!