单链表 - 插入和删除操作

下图展示了单链表的基本结构:

head指针是链表的头指针,指向第一个节点,每个节点的next指针域指向下一个节点,最后一个节点的next指针域为NULL,在图中用0表示。

下面先来看程序(栈的链式存储实现,另外一个实现点这里)和对应的输出(注意输出前进行了链表反转(见《单链表反转》,否则程序后面的while循环输出的顺序是250,200,100),接着来分析程序:

C++ Code


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

 

/* linkedlist.h */

#ifndef LINKEDLIST_H

#define LINKEDLIST_H

typedef struct node *link;

struct node

{

unsigned char item;

link next;

};

link make_node(unsigned char item);

void free_node(link p);

link search(unsigned char key);

void insert(link p);

void deletep(link p);

void traverse(void (*visit)(link));

void reverse(void);

void destroy(void);

void push(link p);

link pop(void);

#endif

C++ Code


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

 

/* linkedlist.c */

#include <stdlib.h>

#include <stdio.h>

#include "linkedlist.h"

static link head = NULL;

link make_node(unsigned char item)

{

link p = malloc(sizeof(*p));

p->item = item;

p->next = NULL;

printf("make node from Item %d\n", item);

return p;

}

void free_node(link p)

{

printf("free node ...\n");

free(p);

}

link search(unsigned char key)

{

link p;

printf("search by key %d\n", key);

for (p = head; p; p = p->next)

if (p->item == key)

return p;

return NULL;

}

void insert(link p)

{

printf("insert node from head ...\n");

p->next = head;

head = p;

}

/*

void delete(link p)

{

link pre;

printf("delete node from ptr ...\n");

if (p == head) {

head = p->next;

return;

}

for (pre = head; pre; pre = pre->next)

if (pre->next == p) {

pre->next = p->next;

return;

}

}

*/

void deletep(link p)

{

link *pnext;

printf("delete node from ptr ...\n");

for (pnext = &head; *pnext; pnext = &(*pnext)->next)

if (*pnext == p)

{

*pnext = p->next;

return;

}

}

void traverse(void (*visit) (link))

{

link p;

printf("linkedlist traverse ...\n");

for (p = head; p; p = p->next)

visit(p);

}

void reverse(void)

{

link pnode = head;

link pprev = NULL;

printf("reverse linkedlist ...\n");

while (pnode != NULL)

{

// get the next node, and save it at pNext

link pnext = pnode->next;

// reverse the linkage between nodes

pnode->next = pprev;

// move forward on the the list

pprev = pnode;

pnode = pnext;

}

head = pprev;

}

void destroy(void)

{

link q, p = head;

printf("destory linkedlist ...\n");

head = NULL;

while (p)

{

q = p;

p = p->next;

free_node(q);

}

}

void push(link p)

{

printf("push item from head ...\n");

insert(p);

}

link pop(void)

{

if (head == NULL)

return NULL;

else

{

link p = head;

printf("pop item from head ...\n");

head = head->next;

return p;

}

}

C++ Code


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

 
/*************************************************************************

> File Name: main.c

> Author: Simba

> Mail: [email protected]

> Created Time: Fri 28 Dec 2012 01:22:24 PM CST

************************************************************************/

#include<stdio.h>

#include "linkedlist.h"

void print_item(link p)

{

printf("print item %d \n", p->item);

}

int main(void)

{

link p = make_node(10);

insert(p);

p = make_node(5);

insert(p);

p = make_node(90);

insert(p);

p = search(5);

deletep(p);

free_node(p);

traverse(print_item);

destroy();

printf("..................\n");

p = make_node(100);

push(p);

p = make_node(200);

push(p);

p = make_node(250);

push(p);

reverse();//链表反转

while ((p = pop()))

{

print_item(p);

free_node(p);

}

return 0;

}

输出为:

分析:

在初始化时把头指针head初始化为NULL,表示空链表(不带头结点)。然后main函数调用make_node创建几个节点,分别调用insert插入到链表中。

链表的插入操作如下图:

正如上图所示,insert函数虽然简单,其中也隐含了一种特殊情况(Special

Case)的处理,当head为NULL时,执行insert操作插入第一个节点之后,head指向第一个节点,而第一个节点的next指针域成为NULL,这很合理,因为它也是最后一个节点。所以空链表虽然是一种特殊情况,却不需要特殊的代码来处理,和一般情况用同样的代码处理即可,这样写出来的代码更简洁,但是在读代码时要想到可能存在的特殊情况。当然,insert函数传进来的参数p也可能有特殊情况,传进来的p可能是NULL,甚至是野指针,本章的函数代码都假定调用者的传进来的参数是合法的,不对参数做特别检查。事实上,对指针参数做检查是不现实的,如果传进来的是NULL还可以检查一下,如果传进来的是野指针,根本无法检查它指向的内存单元是不是合法的,C标准库的函数通常也不做这种检查,例如strcpy(p,
NULL)就会引起段错误。

接下来main函数调用search在链表中查找某个节点,如果找到就返回指向该节点的指针,找不到就返回NULL。

search函数其实也隐含了对于空链表这种特殊情况的处理,如果是空链表则循环体一次都不执行,直接返回NULL。

然后main函数调用delete从链表中摘除用search找到的节点,最后调用free_node释放它的存储空间。

链表的删除操作如下图:

从上图可以看出,要摘除一个节点需要首先找到它的前趋然后才能做摘除操作,而在单链表中通过某个节点只能找到它的后继而不能找到它的前趋,所以删除操作要麻烦一些,需要从第一个节点开始依次查找要摘除的节点的前趋。delete操作也要处理一种特殊情况,如果要摘除的节点是链表的第一个节点,它是没有前趋的,这种情况要用特殊的代码处理,而不能和一般情况用同样的代码处理。这样很不爽,能不能把这种特殊情况转化为一般情况呢?可以把delete函数改成上述程序那样:

消除特殊情况的链表删除操作如下图:

定义一个指向指针的指针pnext,在for循环中pnext遍历的是指向链表中各节点的指针域,这样就把head指针和各节点的next指针统一起来了,可以在一个循环中处理。(其实增加一个头节点也可以消除delete的特殊情况《线性表的链式存储结构》)

然后main函数调用traverse函数遍历整个链表,调用destroy函数销毁整个链表。

参考:《linux c 编程一站式学习》

原文地址:https://www.cnblogs.com/alantu2018/p/8471629.html

时间: 2024-11-07 13:41:28

单链表 - 插入和删除操作的相关文章

单链表实现“插入”和“删除”操作

在单链表中,又如何实现"插入"和"删除"操作呢? 插入操作: 假设我们要在线性表的两个数据元素a和b之间插入一个数据元素x,已知p为其单链表存储结构中指向结点a的指针.为插入数据元素x,首先要生成一个数据域为x的结点,然后插入在单链表中.根据插入操作的逻辑定义,还需修改结点a中的指针域,令其指向结点x,而结点x中的指针域应该指向b结点,从而实现3个元素a,b和x之间逻辑关系的变化. 假设s为指向结点x的指针.则上述指针修改用语句描述即为: s->next=p-

React---简单实现表单点击提交插入、删除操作

1 import React,{Component,Fragment} from 'react' 2 3 class App extends Component { 4 constructor(){ 5 super() // 要想使用this必须使用super 6 this.state = { 7 postList:[ 8 'item1', 9 'item2', 10 'item3' 11 ], 12 inputValue:"test" 13 } 14 } 15 render(){ 1

二叉平衡树的插入和删除操作

1.      二叉平衡树 二叉排序树的时间复杂度和树的深度n有关.当先后插入的结点按关键字有序时,二叉排序树退化为单枝树,平均查找长度为(n+1)/2,查找效率比较低.提高查找效率,关键在于最大限度地降低树的深度n.因此需要在构成二叉排序树的过程中进行“平衡化”处理,使之成为二叉平衡树. 二叉平衡树,又称AVL树.它或者是一棵空树,或者是具有下列性质的树: 1)      具备二叉排序树的所有性质: 2)      左子树和右子树深度差的绝对值不超过1: 3)      左子树和右子树都是二叉

[数据结构]顺序单链表插入

一,单链表插入操作 [cpp] view plaincopy typedef struct NODE { struct NODE *link; int value; }Node; #include <stdlib.h> #include <stdio.h> #define FALSE 0 #define TRUE 1 int s_insert(Node **rootp,int new_value)  //root是一个指向Node的指针,所以指针root的指针类型是Node** {

链表插入和删除,判断链表是否为空,求链表长度算法的,链表排序算法演示——C语言描述

关于数据结构等的学习,以及学习算法的感想感悟,听了郝斌老师的数据结构课程,其中他也提到了学习数据结构的或者算法的一些个人见解,我觉的很好,对我的帮助也是很大,算法本就是令人头疼的问题,因为自己并没有学习过算法的系统性的课程,现在还是处于不断摸索的阶段,好多算法题目根本就没有什么思路,导致自己对好多题目都很是头疼,就算是自己做过的一些算法的题目,再次遇到也还是不一定会做出来,他给出的建议就是,看懂别人的程序,然后自己去敲,一定会出错,然后调试,有错误接着调试,一直到没有错误为止,并且要时常的去复习

C语言实现单链表节点的删除(带头结点)

我在之前一篇博客<C语言实现单链表节点的删除(不带头结点)>中具体实现了怎样在一个不带头结点的单链表的删除一个节点,在这一篇博客中我改成了带头结点的单链表.代码演示样例上传至 https://github.com/chenyufeng1991/DeleteLinkedList_HeadNode.删除类型有两种: (1)删除某个位置pos的节点: (2)推断x值是否在链表中,若存在则删除该节点: 核心代码例如以下: //删除某个位置pos的节点 Node *DeletePosNode(Node

二叉查找树(二叉排序树)创建,插入,删除操作。

二叉排序树 二叉排序树是一个基础的树的数据结构.应用非常多. 它的特性就是,左孩子小于parent,右孩子大于parent. 寻找节点 寻找节点就是直接根据数值的大小,从root节点开始遍历,大于当前遍历节点就向它的右子树查找,相反则查找它的左子树.然后返回. 查找最大最小节点 直接根据root节点,遍历到最右就是最大节点,遍历到最左,就是最小节点. 插入节点 插入节点我这里插入的节点都会成为叶子节点.根据大小的关系向下遍历,遍历到最后的节点,然后插入就可以了. 删除节点 这里删除节点是相对麻烦

单链表插入操作

URL:http://jpkc.onlinesjtu.com/CourseShare/Courses/ResourceModule/PreReading.aspx?courseid=701018&nodid=238&chapterid=238&preid=16 单链表的插入操作 1)已知线性链表head,在p指针所指向的结点后插入一个元素x. 在一个结点后插入数据元素时,操作较为简单,不用查找便可直接插入. 操作过程如下图所示: 相关的语句如下: { s=(slnodetype*)

数据结构与算法基础之链表插入和删除算法

1 #include<stdio.h> 2 #include<malloc.h> 3 #include<stdlib.h> 4 5 //函数声明 6 PNODE create_list();//返回值是链表头结点的地址 7 void traverse_list(PNODE pHead); 8 bool is_empty(PNODE pHead); 9 int length_list(PNODE pHead); 10 bool insert_list(PNODE,int,