今日主要写写指针、单链表结构体、单链表的建表方法!
指针和结构体可以算的上是c语言里面最重要的两个东西了。
指针变量和普通的变量不同,指针变量里面存的是地址!
假如我们定义了一个int型的指针变量A(指针变量也需要声明类型),一个int型的变量B。这个时候我们将B的地址赋值给A,A=&B,这时候A里面存的就是B变量在内存中的地址了。
这里的内存是瞎标的,于是我们可以通过*A(这里的*表示解引用)来修改变量B的值,这种通过访问地址来找其他变量的方式就叫指针,我们通常可以通过图示的方法来理解指针,
int *A=B,也可以叫A指向了B(B必须为int型变量)。
OK,接着来看单链表的结构体定义:
typedef struct Lnode{
int data;
Lnode *next;
}Lnode,*Linklist;
一步一步的拆分,首先定义了一个结构体struct Lnode,里面有两个成员变量,一个是data域存单链表的值,另一个是指针域(这个指针域的类型就是Lnode型的),存的是下一个单链表结点的地址。由于结构体里规定了Lnode的类型,所以这个单链表的指针只能指向这个结构体,而不能指向所有的非struct Lnode变量!
然后再来说说typedef,这个是重命名的意思,将struct Lnode重命名为Lnode,后面定义单链表变量时直接Lnode p就行了,效果等同于struct Lnode p;没错,就是为了偷懒少打点代码而已!后面的*Linklist就代表将Lnode *重命名为Linklist,我们定义结构体指针的时候直接Linklist q,效果等同于Lnode *,也等同于struct Lnode *。
这就是我们定义的单链表结构体啦,原则上来说data和next的位置是可以互换的!
如果互换,画起来感觉有点怪异,不过效果都是一样的,新手还是按规矩来吧。
注意,两幅图里面的指针指向的均是结构体,而不是单独的next域或者指针域;通俗点说,如果我们定义了Lnode *p=L(L为一个单链表结点),这里的P指向的是L这个结点全部,而不是该结点的next域或者data域!
再来说说单链表的插入和删除结点操作!
单链表的插入操作很好说,就是修改指针域就行了。假如有这样的表,我们要在2和4的中间插入3这个结点
我们只需要修改2和3的指针域就行了,让2的next域指向3,3的next域指向4即可!
然后是删除操作,还是上面那个表,我们要把刚插入进去的3删除了,只需修改2的指针域,让2的next域指向4就行了,再free掉3这个结点就行了,其实3这个结点free不free无所谓的,因为你从单链表表头开始遍历,根本找不到3这个结点,但考试还是得删!
ok,开始单链表的创建过程了,单链表的建表有两种方法,头插法和尾插法!
头插法就是在插入时,新的结点不断插入到当前链表的表头(也就是头结点的后面)。解释一下头结点,头结点是为了方便运算的实现而提出来的,他是一个特殊的结点,他的data域不存放任何数据,他的指针域指向表头结点。带头结点的单链表如下:
一般我们会用一个L指针指向头结点,这样L->next恒为表头结点!(指针访问结构体成员用->)。
头插法代码如下:
Linklist list_insertbyhead(Linklist &L){
Lnode *s;
int x;
// 创建头节点
L = new Lnode;
L->next = NULL;
cin >> x;
while(x!=9999){
s = new Lnode;
s->data = x;
s->next = L->next;
L->next = s;
cin >> x;
}
return L;
}
这个函数类型为Linklist,说明返回值必须为指针!因为Linklist=Lnode *,s->next = L->next; L->next = s;就是不断往表头插入新结点的过程!设置循环条件,当手动输入9999时停止建表!
实践一下:(由于头插法是不断往表头插入结点,所以打印表数据时是倒着的)
尾插法:这个好理解点,就是不断往表尾追加结点,所以需要一个辅助指针s,一直指向表尾,插入结点后更新这个尾指针(尾指针一直指向表尾结点)!
Linklist list_insertbytail(Linklist &L){
Lnode *s;
int x;
L = (Lnode*)malloc(sizeof(Lnode));
L->next = NULL;
Lnode *r = L;
cin >> x;
while(x!=9999){
s = (Lnode*)malloc(sizeof(Lnode));
s->data=x;
s->next=NULL;
r->next = s;
r=r->next; // 更新尾指针
cin >> x;
}
return L;
}
实践一下:
完整代码如下:(在vscode环境下成功跑通)
#include <iostream>
#include <cstdio>
#include <ctime>
using namespace std;
// 单链表结构体定义
typedef struct Lnode{
int data;
Lnode *next;
}Lnode,*Linklist;
// 头插法建立单链表
Linklist list_insertbyhead(Linklist &L){
Lnode *s;
int x;
// 创建头节点
L = new Lnode;
L->next = NULL;
cin >> x;
while(x!=9999){
s = new Lnode;
s->data = x;
s->next = L->next;
L->next = s;
cin >> x;
}
return L;
}
// 尾插法建立单链表
Linklist list_insertbytail(Linklist &L){
Lnode *s;
int x;
L = (Lnode*)malloc(sizeof(Lnode));
L->next = NULL;
Lnode *r = L;
cin >> x;
while(x!=9999){
s = (Lnode*)malloc(sizeof(Lnode));
s->data=x;
s->next=NULL;
r->next = s;
r=r->next;
cin >> x;
}
return L;
}
int main(){
Linklist L;
list_insertbyhead(L);
// list_insertbytail(L);
Lnode *p = L->next;
printf("list:");
while (p != NULL) {
printf("%d-> ",p->data);
p = p->next;
}
printf("null");
printf("\n");
return 0;
}