寒假自学数据结构打卡 Day1 单链表
众所周知,南京某顶着985,211,双一流名头的三本大学的放假时间是极晚的,若不是学生闹一闹,恐怕得到二月份才放假。上学期的C++课我虽然考了100,但越学越觉得力不从心。所以抽出来寒假来学一下数据结构。
数据结构书配合网课虽然易于理解,但使用的毕竟是类C语言而且还不完整,所以用C++来实操一下就特别有必要了。
C++中单链表的构建
struct ListNode
{
double value;
ListNode *next;
ListNode(double value1, ListNode *next1 = nullptr)
{
value = value1; next = next1;
}//构造函数
};
链表就是用链子把一连串节点给串起来,节点中存有数据与指向下一个节点的指针,用结构体来实现再合适不过了。(虽然我们C++课学的是类,不过类还是要用public之类的语句,我觉得不如结构体简便)
ListNode* head=NULL;
这里我建立了头节点,它不存储数据,但是整个链表的开始。
ListNode* first=new ListNode(1);
head->next=first;
这里我创建了首元节点,并存入了数据1,然后把头节点的next指向了首元,这样就基本串了起来。
对单链表进行操作
取第i个值
Status GetElem(LinkList L,int i,ElemType &e)
{
p=L->next;j=1;
while(p&&j<i)
{
p=p->next;
++j;
}
if(!p||j>1)return 0;
e=p->data;
return 1;
}
这是类C语言描述出来的函数,用e来承接返回来的数据。这个函数还是比较简单的,把它转换为C++语言很容易。
查找某个元素
查找的算法与取值类似,不同之处在于查找到后返回的是地址。不过我感觉这种方法还是有缺陷的,它只能返回查找到的首个数据地址,如果之后还有的话那就查不到了。我认为可以给它改一下,用数组指针来承接每个元素。
插入
插入来说相对难实现一些。假如我们要在第二和第三个节点之间插入一个节点A,应该如何实现呢?
一开始我们要插入的节点其next为nullptr,只存有数据
第一步,让A节点的next指向三,代码为
A->next=second->next;
第二步,让第二个节点的next指向A
second->next=A;
这两步是不能互换的,一换就会出问题。
于是,其完整的算法为
Status ListInsert(ListNode &L,int i,ElemType e)
{
p=L;j=0;
while(p&&(j<i-1))
{p=p->next;++j;}
if(!p||j>i-1)return error;
s=new LNode(e);
s->next=p->next;
p->next=s;
return OK;
}
展示一下我写的一个很简单的C++代码
int insert(ListNode* head,int e,int i)
{
int j=0;ListNode* p=head;
while(p->next!=nullptr&&j<i-1)
{
p=p->next;
j++;
}
ListNode* s;
s=new ListNode(e);
s->next=p->next;
p->next=s;
return 1;
}
这段代码基本上实现了简单的插入,当然其健壮性不高。
删除
删除单链表中的一个节点,我们仅需让该节点的前驱指向该节点的后继,然后再把该节点的next改为nullptr。但这样操作后节点所占内存还是存在的,我们要想办法把它给释放掉。我们一般把要删除的节点的地址保存在一个临时的q中,然后C++中通常用delete删除。这个算法个人感觉比较简单,因此不再赘述。
创建单链表
前面研究这些操作时我创建了first,second等结构体指针来作为节点。但这样子不仅效率不高而且与顺序表没有本质区别,因此必须寻求一种高效的方法。
前插法
void CreateList_H(LinkList &L,int n)
{
L=new LNode;
L->next=NULL;
for(int i=0;i<n;i++)
{
p=new LNode;
cin>>p->data;
p->next=L->next;L->next=p;
}
}
这个算法还是容易理解的,我们要在L后插入n个节点,每次都要创建一个新的节点,让它的next变为L的next(即上一个p的next),然后让L的next变为这个p。
这个可以这么理解,在初始的L后面还存在着一个NULL节点,每次操作都相当于在NULL和NULL之前的节点之间插入一个节点。
前插法中数据的顺序并不是按照输入顺序来的
后插法
后插法数据的顺序就是按照输入顺序来的了。
L=new LNode;
L->next=NULL;
r=L;
for(int i=0;i<n;++i)
{
p=new LNode;
cin>>p->data;
p->next=NULL;r->next=p;
r=p;
}
不同的是后插法需要辅助节点,该辅助节点始终指向链表的最后一个元素