c++ 链表(基本知识详解)

千灯理解的链表QAQ


指针的概念:

1.指针的意义:

指向地址。
理解:
我们开变量的时候会有一个地址,这个地址存储着变量。
比如:

int x;

↑这样定义了一个int类型的变量x
&x是x的地址

cout<<&x;

↑这样就是输出x的地址

scanf("%d",&x);

↑比如我们常用的scanf,就是直接在地址里面存入变量,因此十分的快

2.定义指针
void *x;

↑定义一个void类型(可以是int,long long,string…)的指针

3.指针的操作
void *x;//伪代码,类型可以自己定的
x=&a;

↑将a的地址给x

void *x;
x=&a;
cout<<*x;

↑输出x地址存储的变量,* 用来调用地址存储的变量 举个例子:

 #include<bits/stdc++.h>
 using namespace std;int main()
 {
  int *x;    
  int a;    
  cin>>a;   
   x=&a;    
   cout<<*x;
   }

↑输出结果为a注意,指针只能指向同类型的地址。

int *a;
string x;
cin>>x;
a=&x;

↑错误示范,此乃违法操作。


x->y

↑x必须是一个指针,而且y必须包含在x指向的内容中,输出是y,但是要通过x调取

#include<bits/stdc++.h>
using namespace std;
struct node
{
    int *y;
}k;
int main()
{
    node *x;
    int a;
    cin>>a;
    x=&k;
    x->y=&a;
    cout<<*x->y;
}

↑比如这样,x指向一个node类型的变量k,y是node类型中的一个int类型的指针,因此调取y需要x->y;

对于y不要求是什么类型,但是x必须是指针才可以进行此操作。


链表构造:

1.链表的概念:

我们定义一个struct类型代表一个点,这个点包括该点的数据(data,即输入进去的东西),和下一个点的地址 ↓。这是单向的链表,如果想要双向的增加last指针就行

struct point
{
    int data;
    point* next;
};

↑这样通过->next就依次可以知道所有的点,下面会细讲

2.构建链表:

首先一个链表要有头(head),有尾(end)
在单向的链表里,头指向最先点的前一个,尾指向最后点,这样在调取的时候比较方便

#include<bits/stdc++.h>
using namespace std;
struct point
{
    int data;
    point* next;
};
int main()
{
    int x;
    cin >> x;
    point *end,*head = (point*)malloc(sizeof(point));
    end = head;
    for (int i = 1;i <= x;++i)
    {
        point *tmp = (point*)malloc(sizeof(point));
        cin >> tmp->data;
        end->next = tmp;
        end = tmp;
    }
    end->next = NULL;//NULL就是0
}

↑end是每一次链表的结尾,因此每一次新加入一个点,即加在未加入结尾时的链表的结尾的后一个,然后end就是新加入的点(最后一个嘛)
上面这句话有点绕,画张图看看↓

  1 - 5 - 2 - 9 - 8
h                 e
这是原来的链表(h=head,e=end) 
新读入3,要把3加入链表的最后面
那么就要加在8的后面  
  1 - 5 - 2 - 9 - 8 -   3
h                 e   e->next
                       tmp
这样子end->next就指向3,也就是tmp
因为end是指向point类型的指针
新加入3后我们发现end不在结尾上,那么我们要调整
即end=tmp
  1 - 5 - 2 - 9 - 8 - 3
h                     e

要介绍一个新的函数malloc
malloc是个好用的东西,用来给新的节点分配内存(包括一个地址)
那么你想用for每次新开一个point不就行了↓

for(int i=1;i<=x;++i)
{ 
    point* tmp;
}

↑但是很遗憾,每次for开出来地址是一样的QAQ
malloc的使用方法:

void* malloc(size)

↑void可以替换成其他类型
这样每次tmp都会是新的地址,新的内存

3.链表输出:
for (point *i = head->next;i != 0;i = i->next)
        cout << i->data << endl;

↑超级简单,不想说了(请参考邻接表存图食用更佳)。

4.单向环型链表
#include<bits/stdc++.h>
using namespace std;
struct point
{
    int data;
    point* next;
};
int main()
{
    int x;
    cin >> x;
    point* end, * head = (point*)malloc(sizeof(point));
    end = head;
    for (int i = 1;i <= x;++i)
    {
        point* tmp = (point*)malloc(sizeof(point));
        cin >> tmp->data;
        end->next = tmp;
        end = tmp;
    }
    end->next = head->next;
}

↑就是把尾巴的下一个在头接上,注意head指向第一个点的前面。

5.双向链表
#include<bits/stdc++.h>
using namespace std;
struct point
{
    int data;
    point* next;
    point* last;
};
int main()
{
    int x;
    cin >> x;
    point* end, * head = (point*)malloc(sizeof(point));
    end = head;
    for (int i = 1;i <= x;++i)
    {
        point* tmp = (point*)malloc(sizeof(point));
        cin >> tmp->data;
        end->next = tmp;
        tmp->last = end;
        end = tmp;
    }
    end->next = NULL;
    head->last = NULL;
    for (point *i = head->next;i != 0;i = i->next)
        cout << i->data << endl;
    for (point *i = end;i != 0;i = i->last)
        cout << i->data << endl;
}

↑双向链表就是多加一个last记录

关于last我们↓

  1 - 5 - 2 - 9 - 8
h                 e
这是原来的链表(h=head,e=end) 
新读入3,要把3加入链表的最后面
那么就要加在8的后面  
  1 - 5 - 2 - 9 - 8    -    3
h                 e      e->next
              tmp->last    tmp
因此tmp的last是8的地址  
而8的next是3的地址

然后输出还是一样的QAQ


链表修改

1.寻找第n个点
point* find(point* head,int n)
{
    point *tmp=head;
    for (int i = 1;i <= n;++i)
        tmp = tmp->next;
    return tmp;
}

↑由于head指第一个点前,所以n=1的时候指向第一个,所以不用考虑一些细节
返回即第n个点的地址↓

       cout<<find(head,n)->data;

↑变量名什么的自己改

2.删除第n个点

首先必须寻找到他的地址,所以find放在删除前面

point* find(point* head,int n)
{
    point *tmp=head;
    for (int i = 1;i <= n;++i)
        tmp = tmp->next;
    return tmp;
}
void delete_(point* head,int n)
{
    point *tmp=find(head, n);
    tmp->last->next = tmp->next;
    tmp->next->last = tmp->last;
}

↑我们通过find知道了第n个点的位置,那么第n-1个点和第n+1个点接上,就会忽略第n个点,达到了删除效果
所以上一个点的下一个点是第n个点的下一个点
所以下一个点的上一个点是第n个点的上一个点
如图↓

    n-1    -     n     -    n+1
 tmp->last      tmp      tmp->next
删除第n个点后
    n-1    -     n+1
 tmp->last    tmp->next
所以得到了
tmp->last->next=tmp->next;
tmp->next->last=tmp->last;

这个函数直接在原来的链表上经行修改,所以说delete是很恐怖的。没事别乱删东西。。。
还有关于delete是一个库函数。所以要加下划线,调用请注意

3.在第n个点的前面插入数字k

跟delete一样,先找到地址再插入

point* find(point* head,int n)
{
    point *tmp=head;
    for (int i = 1;i <= n;++i)
        tmp = tmp->next;
    return tmp;
}
void insert_(point* head, int n, int k)
{
    point *tmp2 = find(head, n);
    point *tmp1 = tmp2->last;
    point *insert_tmp = (point*)malloc(sizeof(point));
    tmp1->next = insert_tmp;
    insert_tmp->last = tmp1;
    tmp2->last = insert_tmp;
    insert_tmp->next = tmp2;
    insert_tmp->data = k;
}

↑看上去很复杂其实还行QAQ
tmp2是n的地址,tmp1是n-1的地址,在n前插入k相当于在n-1和n间增加k
如图↓

 n-1    -     n
tmp1         tmp2
加入k以后
    n-1      -      k      -      n
   tmp1         insert_tmp       tmp2
                tmp1->next
                tmp2->last      
insert_tmp->last             insert_tmp->next
没错要存4条信息。。。  
于是可以得到:
tmp1->next = insert_tmp;
insert_tmp->last = tmp1;
tmp2->last = insert_tmp;
insert_tmp->next = tmp2;

最后把insert_tmp->data=k就行了。


QAQ基本操作就这些了整理一下完整的代码QAQ

#include<bits/stdc++.h>
using namespace std;
struct point
{
    int data;
    point* next;
    point* last;
};
point* find(point* head,int n)
{
    point *tmp=head;
    for (int i = 1;i <= n;++i)
        tmp = tmp->next;
    return tmp;
}
void delete_(point* head,int n)
{
    point *tmp = find(head, n);
    tmp->last->next = tmp->next;
    tmp->next->last = tmp->last;
}
void insert_(point* head, int n, int k)
{
    point *tmp2 = find(head, n);
    point *tmp1 = tmp2->last;
    point *insert_tmp = (point*)malloc(sizeof(point));
    tmp1->next = insert_tmp;
    insert_tmp->last = tmp1;
    tmp2->last = insert_tmp;
    insert_tmp->next = tmp2;
    insert_tmp->data = k;
}
int main()
{
    int x;
    cin >> x;
    point* end, * head = (point*)malloc(sizeof(point));
    end = head;
    for (int i = 1;i <= x;++i)
    {
        point* tmp = (point*)malloc(sizeof(point));
        cin >> tmp->data;
        end->next = tmp;
        tmp->last = end;
        end = tmp;
    }
    end->next = NULL;
    head->last = NULL;
}

↑双向链表非环状
QAQ

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值