赞
踩
链表是由一个个结点,通过指针串联起来的,一个结点是一个结构体,结构体中包括数据域和指针域。数据域中存储数据,指针域存储的是下一个结点的地址。
无论带头还是不带头,都应该先创建一个指针,这个指针可以指向一个结构体(结点)。
先定义一个结构体:
- typedef struct s {
- int data;
- struct s* next;
- }s;
这个结构体中有int类型的数据域 ,和指向下一个相同类型结构体的指针
什么叫不带头结点,就是初始化时只创建了一个指针,但是这个指针并没有指向一个结构体,而是指向NULL。
如下图所示:
相应的代码:
- void init(s* ps) //ps为创建的结构体指针
- {
- ps = NULL;
- }
带头结点的单链表会比不带头结点的单链表有很多的好处
首先,什么叫带头结点的单链表,和不带头结点的区别是创建了一个新的结构体指针,这个指针不再指向NULL。而是指向一个结构体,而这个结构体里面的一个指针指向NULL.
如图所示:
相应的代码如下:
- s* ps;
-
- ps = (s*)malloc(sizeof(s));
- ps->next = NULL;
先输入的排在后面,而后输入的排在前面
如图所示:
从头指针往后看,先创建的排在后面,而后创建的排在前面。
代码实现如下:
- int main()
- {
- s* p; //先创建一个指针
- p = (s*)malloc(sizeof(s));
- p->next = NULL;//创建一个带头结点的单链表
- s* s1; //创建一个新指针,指向一个新的结构体
- int x = 10;//要输入到一个结点的数据,可以是任何数字
- s1 = (s*)malloc(sizeof(s));
- s1->data = x;
- s1->next = p->next;
- p->next = s1;//注意的地方
- return 0;
- }
如图:
这里需要注意的是上面代码中两个指针改变的语句。上下两句顺序不可改变。
首先应用新创建的结构体里面的指针指向头指针指向的内容
然后再覆盖头指针只得地方,改为s1指针指向的地方,
这样新创建的结点就串在这个单链表中了
从头指针往后看,先插入的排在前面,后插入的排在后面。
如图所示:
实现代码如下:
- int main()
- {
- s* p;
- p = (s*)malloc(sizeof(s));//和前插法不同,这里一开始并没有让头结点的指针指向NULL
- s* p1;
- s* end = p;//指向最后一个结点位置
- int x = 10;
- p1 = (s*)malloc(sizeof(s));
- p1->data = x;
- end->next = p1;//让最后一个结点的指针指向要再后面传进来的结点
- end = p1;// p1 = end; //end指向新串进来的最后一个结点
- end->next = NULL;//在插入完之后,最后才让最后一个结点里面的指针指向NULL
- return 0;
- }
如图:
假设,现在获取了一串单链表中的一个结点,并知道指向这个结点的一个指针
那么我们就可以进行操作了
首先如图所示:
代码实现:
- int main()
- {
- s* p;//表示获取的一个指针,我们这里假设就是头指针了
- p = (s*)malloc(sizeof(s));
- p->next = NULL;
- s* s1;
- int x = 10;//要插入的数据
- s1 = (s*)malloc(sizeof(s));
- s1->data = x;
- s1->next = p->next;
- p->next = s1;
- return 0;
- }
这里我们其中有两种方法
第一种就是从头开始,然后往后查找,找到指定的结点,在前面插入一个新的结点
这种方法的时间复杂度是O(n)。
第二种方法是在这个结点后面插入一个新的结点,然后进行数据的交换,这样就可以实现前插操作
代码实现:
- int main()
- {
- s* p;//假设这是我们获取的一个结点,要在这个结点前插入一个结点
- p = (s*)malloc(sizeof(s));
- s* s1;//创建的一个新的结点指针
- s1 = (s*)malloc(sizeof(s));//新的结点
- int x = 10;//要前插的数据
- s1->next = p->next;
- p->next = s1;//先实现后插操作
- s1->data = p->data;//前一个结点的数据赋值到后面
- p->data = x;//前面结点的数据被新的数据覆盖
- return 0;
- }
首先,要删除第i个结点的内容,我们要找到第i-1个结点。因为我们要修改第i-1个结点的指针,指向第i+1个结点,然后把第i个结点的内容释放掉。
如图所示:
代码如下:
- int main()
- {
- s* p;//
- s* p1 = p;//用来标记查找到哪个节点了
- int j = 0;//当前p指向的是第几个结点
- int i = 5;//假设我们要删除第5个结点的内容
- while (p1 != NULL && j < i - 1)//目的是找到第i-1个结点
- {
- p1 = p1->next;
- j++;
- }
- if (p1 == NULL)
- {
- printf("i的数值不合法");
- return 0;
- }
- s* shanchu = p1->next;
- p->next = shanchu->next;//第i-1个结点指针指向第i+1个结点
- free(shanchu);//释放掉这个结点
- return 0;
- }

这里我只是按照思路写的代码,并不能运行,因为我还没有初始化一个单链表
值得思考的是,这里我新建了一个shanchu这个指针,指向要删除的结点,为什么要新建一个,而不是直接用p1->next来进行操作
因为p1->next在过程中会发生改变。最后如果释放掉p1->next的值,会错误释放,因此需要特地来新建一个指针,指向要删除的结点。
代码如下:
- int main()
- {
- s* p;//为头指针
- s* p1 = p;//用来移动指向
- int j = 0;//用来标记第几个结点
- //假设要查找第i个结点
- int i = 5;//我们随便设一个数字
- while (p1 != NULL && j < i) //思考为什么是j<i
- {
- p = p->next;
- j++;
- }
- return 0;
- }
和上面的代码类似,时间复杂度都是O(n)
代码如下:
- int main()
- {
- s* p;//p为头指针
- s* p1 = p;//用来移动,防止头指针因移动导致找不到头结点
- int j = 0;//用来标记找到了第几个结点
- //假设要查找的这个结点的数据为5
- int i = 5;
- while (p != NULL && p->data != i)
- {
- p = p->next;
- j++;
- }
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。