本次使用C++
删除相比于插入稍微简单一点
首先设单链表长为NodeNum
假设要删除第i个结点,只需要遍历到第i个,并删除这个结点,即可。
需要使用的函数free()
头文件:malloc.h或stdlib.h
作用:释放malloc(或calloc、realloc)函数给指针变量分配的内存空间。
注意:使用后该指针变量一定要重新指向NULL,防止野指针出现,有效规避错误操作。
本次因使用C++ 因此需要一个无需这些头文件
原理:先建立一个单链表,再对单链表进行遍历,让一个结构体指针指向对应要删除的结点,对其进行释放。
#include<iostream>
using namespace std;
struct node{
int num;
node* next;
};
首先是声明一个结构体
node* head, * now, * p;
再试对创建链表函数需要的变量声明
该变量最好声明为全局变量,因为是单向链表,所以后期想要让指针返回到头指针,全局变量比较方便
node* create()
{
int Node;
int NodeNum;
head = new node;
now = head;
cout << "Please input NodeNum:";
cin >> NodeNum;
for (int i = 0; i < NodeNum; i++)
{
cout << "Please input number:";
cin >> Node;
p = new node;
p->num = Node;
now->next = p;
now = p;
}
now->next = NULL;
return head;
}
这里是最简单的单链表的建立
很常规
接下来是删除链表对应结点的函数
void Delete(node* head, int n)//删除第n个结点
{
node* front, * N;
front = head;
N = head;
for (int i = 0; i < n - 1; i++)//刚好在第n - 1个结点
front = front->next;
for (int i = 0; i < n ; i++)//刚好在第n 个结点
N = N->next;
//删除第n个结点
front->next = N->next;
free(N);
N = NULL;
}
front是指向对应结点的前趋,
N指向对应结点
front = head;
N = head;
首先都让这两个指针指向头结点
for (int i = 0; i < n - 1; i++)//刚好在第n - 1个结点
front = front->next;
for (int i = 0; i < n ; i++)//刚好在第n 个结点
N = N->next;
接下来,用for循环分别将两个指针指向对应结点的前 和 对应结点
front->next = N->next;
让front指针跳过对应结点,连接对应结点的下一个结点
free(N);
然后释放对应结点
同时
N = NULL;
使用后该指针变量一定要重新指向NULL,防止野指针出现,有效规避错误操作。
为了有效的确定已经删除了这个结点
我们写一个求长函数,来求出这个链表的长度
int len(node* head)
{
int n=0;
node* p;
p = head;
while (p != NULL)
{
n++;
p = p->next;
}
return n;
}
简单的循环遍历这个链表
n来记录这个链表的长度
返回n的值
最后的主函数
int main()
{
int DeleteNodeNum;
node* po;
po = create();
cout << "现在链表的实际长度" << len(head) << endl;
po = po->next;
while (po != NULL)
{
cout << "Out num:" << po->num << endl;
po = po->next;
}
po = head;
cout << "请输入要删除的结点数:";
cin >> DeleteNodeNum;
Delete(po, DeleteNodeNum);
po = po->next;
while (po != NULL)
{
cout << "Out num:" << po->num << endl;
po = po->next;
}
cout << "现在链表的实际长度" << len(head);
return 0;
}
主函数只是有效的验证链表的建立 以及告诉我们链表是否删除
以及现在链表的长度 没有什么技术含量
以上是对单向链表的删除
接下来是对单链表的插入
几乎所有都是相同的
不同只有一个插入函数
void Insert(node* head, int n)//n结点之后
{
node* heq,* heh;
node* p;
heq = head;
heh = head;
int Node;
p = new node;
cout << "请输入要插入的数据:";
cin >> Node;
p->num = Node;
for (int i = 0; i < n; i++)
{
heq = heq->next;//循环结束刚好在n结点
}
for (int i = 0; i <= n; i++)
{
heh = heh->next;//循环结束刚好在n结点后
}
heq->next = p;
p->next = heh;
}
解析变量:
node* heq,* heh;
一个是n结点前的指针
另一个是指向n结点的指针
heq->next = p;
p->next = heh;
该语句连接了p指向的结点,p的前后继指向heh指向的结点
这样就完成了对链表的插入
为了确保插入的成功
可以利用求长函数len();来确定链表的长度
以上是对链表的插入
接下来是建立一个简单的双向链表
双向链表的好处就是知道一个结点就可以知道他的前趋和后继
但是这种事以空间换时间的方法
换句话说就是占用了你的空间来使时间上更快
struct node {
int num;
node* pre, * next;
};
node* head, * now, * p;
node* create()
{
int Node;
int NodeNum;
head = new node;
now = head;
cout << "Please input NodeNum:";
cin >> NodeNum;
for (int i = 0; i < NodeNum; i++)
{
p = new node;
cout << "Please input number:";
cin >> Node;
p->num = Node;
p->pre = now;
now->next = p;
now = p;
}
now->next = NULL;
return head;
}
看到代码就应该知道,与单向链表几乎差不多。
就是指针域多了一个,一个指向前趋 另一个指向后继
还有代码唯一不同的就是:
p->pre = now;
now->next = p;
now = p;
建立时候让p的前趋指向now
此处我犯了一个错误
就是我把 p->pre = now;写成了now->pre=now
我以为在now跳到下一个结点之前,让他的前趋指向他自己
写的时候没有问题
但是在遍历的时候实际上他的前趋指向自己所在的结点
因为now的后继存的是其他指针的地址 这个指针指向的是一个结点 但是如果我这样写 now的前趋指向是自己的结点
就像是一个等差数列公差为1
一个从0开始
一个从1开始
即使后面差不多 但是每个数都相差了一
好比现在这个语句now的前趋指向now
到了指针的最后now的后继是NULL
那么now的前趋就是now 因此说明了前面的每一个结点的前趋都只是指向了自己,没有达到连接的目的
接下来是主函数:
int main()
{
node* po;
po = create();
po = po->next;
while (po != NULL)
{
cout << "Out num:" << po->num << endl;
po = po->next;
}
cout << endl << endl;
//因为此时的po是NULL 所以连数据域都没有
//cout << po->pre->num;
po = head->next;
po = po->next;
cout << "当前:" << po->num;
cout << "前驱:" << po->pre->num;
cout << "后驱:" << po->next->num;
return 0;
}
主函数也犯了一个错误
就是我注释的地方
因为循环让此时的po是空指针
因为空指针更本连数据域都没有,更没有什么前趋和后继
所以这样肯定是错误的
cout << "当前:" << po->num;
cout << "前驱:" << po->pre->num;
cout << "后驱:" << po->next->num;
这个代码是为了验证这个链表是不是双向链表
就是有了这个代码我才发现前面建立链表时的错误
以上就是双向链表的建立
双向链表可以更好的进行插入 因为知道了某一结点 就知道了前趋和后继
当然双向链表只是比单向链表多了一个指针域
所以插入 删除 和 求长几乎都是一样的 所以没有多大的必要在这上面做文章
其次 还有一种循环链表 只是在最后一个结点的后继指向了头结点而已 所以近期我应该马上就会再写一片博客
以上的所有代码 均是在没有看书 求助等情况下写出 如有雷同纯属巧合
本次博客是在我失眠的情况下写的 从早上四五点左右写的
有些语言可能表达不当 请见谅
然后就是我们的镇店之图: