
当我研究数据结构时,我也感到非常困难. 当我发现这是困难的,因为我没有系统地研究它时,许多教授只专注于数据结构的概念而忽略了代码. 为此,我向那些试图自学数据结构的人写了这些博客文章,希望您能避免绕道而行.
我试图用最简单的语言和代码描述链表,实际上链表实现,它也非常简单
下面的讨论将集中在上面的图片上. 由于它是逐渐实现的,因此我不打算在一开始就使此单个链接列表完美. 它只有两部分: 链表的创建和遍历链表的输出
首先,我们必须了解一些简单的概念. 链表由节点组成,每个节点由另一个数据字段和指向下一个节点的指针组成,因此我们可以轻松地编写以下结构<

struct node//节点
{
int data;//数据域,这里我们选择存储int型
struct node *next;//指针域,指向下一个节点,因此被定义为struct *NODE
};
然后,如果您仔细观察上图,您会发现仍然有一个头指针. 头指针的功能是指向大内存中此链接列表的第一个节点. 一个节点的下一个指针(通常称为头节点)指向下一个指针,因此很容易想到只要有一个头指针,我们就可以轻松地对链表执行各种操作.
因此我们可以继续编写代码:
int main(){
//创建上图的链表
node *head;//一个头指针。用来指向这个链表的第一个节点
node *f=new node;//对应上图第一个节点first node,这种奇葩命名法不是我要让你们学会的,另我使用了new而不是malloc主要是因为惰性
node *s=new node;//对应上图第二个节点second node
node *t=new node;//对应上图第三个节点third node
f->data=8;//第一个node的值
f->next=s;//第一个节点next指针指向第二个节点
s->data=7;//第二个node的值
s->next=t;//第二个节点next指针指向第三个节点
t->data=9;//第三个节点值
t->next=NULL;//从上图得知第三个节点后没有节点了,所以指向NULL,通常称这个节点为尾节点
head=f;//头指针指向第一个节点,至于为什么前面已经说了//打印这个链表里面储存的元素
std::cout<
node *print_ptr=head;//为什么这里要new一个print_ptr?因为我们可能还要利用head进行其他操作,如果直接用head进行下面的操作,就意味着head指向的位置已经改变了
while(print_ptr!=NULL){
std::cout<data<
print_ptr=print_ptr->next;//更新,让当前指针指向下一个节点
}
//输出节点的个数,虽然我们已经知道了是3个
node *length_ptr=head;//同上面的
print_ptrint k=0;
while(length_ptr!=NULL){
k++;length_ptr=length_ptr->next;
}
std::cout<
node *ins_node=new node;//为即将插入的节点从堆上分配点内存
ins_node->data=14;//赋值
ins_node->next=s;//让新节点的next指向第二个节点
f->next=ins_node;//然后让第一个节点的next指向新节点,这就完成了插入//删除之前插入的节点
ins_node=f->next;//让第一个节点next指向新插入的节点,这里你可能会感到疑惑,我建议你画图或者再看看上面的图就能理解,当然你也可以看下面
f->next=ins_node->next;//第一个节点的next指向新节点的next,因为新节点的next相当于指向了第二个节点,所以这里也等价于第一个节点指向第二个节点f->next=f-next->next
system("pause");
}

上面的代码完成了使用尾部插值创建的链表,其简单的操作包括create / output / insert / delete,但是正如您所看到的,它还存在许多缺陷,例如命名命名,新建后不删除,以及主要的所有实现都没有考虑功能的使用和其他缺陷,但这没关系,因为我们将逐步对其进行修改,以使他成为一个好的链表
也许您还没有弄清楚上面的插入和删除操作,在这里我将再次专门讨论
在上图中,我们需要在1和2之间插入一个存储14数据的节点,因此我们需要更改下一个指针,因此在f-> next = s之前;它无法使用,您可能会考虑让One指向新节点,然后将新节点指向第三个节点,例如:
f->next=ins_node;
ins_node->next=f->next;

事实通常证明第一感觉是错误的. 如果仔细看一下上面的代码,您会发现添加f-> next = ins_node,那么第二个等效于ins_node-> next = ins_node;它指向你!所以我们需要反过来考虑,首先让新节点指向第二个节点,然后让第一个节点指向新节点,就像上面的代码一样,至于删除,我没有得到图片,我简要地讲一下,删除是直接的. 让第一个节点的下一个指向需要删除的节点,然后让第一个节点的下一个指向需要删除的节点. 接下来,您可能会想为什么不让第一个节点指向第二个节点呢?您可以自己回答这个问题
这时,已经实现了一个简单的链表,但是我们仍然需要继续改进,因为我们有时不知道每个节点中存储的数据,因此我们需要一个动态链表,下面将实现用户数据的输入存储在一个链结构中,这是一个动态链表
#include
struct node
{
int data;
struct node *next;
};
node *create_linklist();
void print_linklist(node *head);
node *create_linklist(){
node *head=new node;
node *new_node,*current;//一个新节点作为当前节点
current=head;//头结点复制给当前节点
int k;
printf("输入节点个数:");
scanf("%d",&k);
for (int i = 0; i < k; ++i)
{
new_node=new node;
if(i==0)//这里也就是创建第一个节点的情况
{
head=new_node;//把头指针指向第一个节点
}
printf("输入节点数据:");
scanf("%d",&new_node->data);
current->next=new_node;//注意这里由于创建了一个新节点,而当前节点还是开始的head的那个位置,所以就需要更新一下,让当前节点next等于new_node的位置
new_node->next=NULL;//当前节点的next=NULL表示当前节点就是最后一个节点了
current=new_node;//然后把new_node节点复制给当前节点,以便继续后面的节点添加
}
return head;
}
void print_linklist(node *head)//参数传入一个头指针用来指向第一个节点
{
node *phead=head;
while(phead!=NULL)
{
printf("%d", phead->data);
phead=phead->next;
}
}
int main(){
node *h=create_linklist();
print_linklist(h);
system("pause");
}
再次考虑以上图片. 以下是一个双向链接列表. 双链列表和单个项链列表之间的区别在于,它具有指向上一个节点的指针,因此我们应该定义这样的结构

typedef struct NODE
{
int data;
struct NODE *next;
struct NODE *pre;
}node;
由于不可避免地需要从头到尾遍历双向链接列表的某些操作,因此我们应该添加一个概念,即尾指针,即指向尾节点的指针,如下所示以实现双向链接列表,其中有三个节点abc,并且有两种输出方法
#include
typedef struct NODE
{
int data;
struct NODE *next;
struct NODE *pre;
}node;
int main(){
node *a=new node,*b=new node,*c=new node;
node *head=a;
node *tail=c;
a->data=9;
a->next=b;
a->pre=NULL;
b->data=17;
b->next=c;
b->pre=a;
c->data=6;
c->next=NULL;
c->pre=b;
//输出
/*node *print_head=head;
while(print_head!=NULL){
std::cout<data<
print_head=print_head->next;
}*/
/*node *print_head=tail;
while(print_head!=NULL){
std::cout<data<
print_head=print_head->pre;
}*/
system("pause");
}
双向链表的难点不是创建输出,而是插入和删除. 我没有画照片,所以这需要读者仔细考虑. 建议画一幅图,它很容易理解. 以下代码是在上面创建abc的基础上实现的. 在ab之间插入k,然后将其删除
//插入
node *k=new node;
k->data=698;
k->pre=a;
k->next=a->next;
k->next->pre=a;
a->next=k;
//删除
k->pre->next=k->next;
k->next->pre=k->pre;
我不考虑循环链表链表实现,因为它将尾节点指向头节点形成一个环,所以该循环链表不是循环链表,而是循环链表
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-268186-1.html
这篇博客详细介绍了链表这一数据结构的基础知识,包括链表的概念、创建、遍历、插入和删除操作。通过实例代码演示了单链表和双向链表的实现,强调了在操作链表时需要注意的指针更新和逻辑。此外,博客还鼓励读者通过实践和画图来理解链表的插入和删除过程,以加深对数据结构的理解。

1114

被折叠的 条评论
为什么被折叠?



