双向链表c语言5万的阶乘,一起talk C栗子吧(第十五回:C语言实例--双向链表)...

本文通过一个大型章回体科技小说的形式,详细介绍了C语言中的双向链表。首先定义了双向链表的数据结构,包括next和pre指针,然后展示了创建、插入、删除和查找节点的函数实现。在操作双向链表时,可以双向遍历,提供了更大的灵活性。文章还特别强调了在删除操作中处理好指针的重要性,以避免破坏链表的完整性。最后,给出了一个完整的示例代码,包括创建、插入、查找和删除节点,以及遍历链表的过程。
摘要由CSDN通过智能技术生成

各位看官们,大家好,从今天开始,我们讲大型章回体科技小说 :C栗子,也就是C语言实例。闲话休提,

言归正转。让我们一起talk C栗子吧!

看官们,上一回中咱们说的是循环链表的例子,这一回咱们说的例子是:双向链表。

看官们,双向链表也是一种链表。我们在前面两回中说到的链表,都是沿着链表头部到链表尾部这样的方

向进行操作,而今天咱们要说的双向链表既可以沿着链表头部到链表尾部这样的方向进行操作,也可以沿

着链表尾部到链表头部这样的方向进行操作。这也是正是叫它双向链表的原因。

在例子中,查找和删除结点的函数中,可以使用沿着链表尾部向链表头部这样的方向进行查找或者删除,

当然了,也可以向单链表一样沿着链表头部到链表尾部这样的方向进行查找或者删除。不论沿着哪个方向

操作,只需要关注该方向的指针就可以。比如,沿着链表头部到链表尾部这样的方向进行相关的操作,只

需要关注结点中的next指针就行,pre指针可以忽略。但是删除操作需要注意,因为它会从链表中删除一

个符合要求的结点,删除的时候需要把该结点的pre和next指针都处理好,不然会破坏链表的完成性,在

删除操作后,如果再进行遍历操作,就会因为链表不完整,遍历不到链表中的所有结点,也就是形成了断

链,这是最严重的错误。我在代码中有中文注释。

看官们,详细的代码如下,大家可以参考:

1 /* **************************

2 * Head file of Double Linked List

3 * *************************/

4 #ifndef DOUBLE_LINKED_LIST_H

5 #define DOUBLE_LINKED_LIST_H

6

7 #include

8 #include

9

10 //#define DEBUG 0

11 #ifdef DEBUG

12 int size = 0;

13 #endif

14

15 #define SUCCESS 0

16 #define FAILE 1

17

18 typedef int ListElmt; //把int当作List类型,实际中可以使用其它的类型或者自己定义一个List类型,不过不能是使用struct复合类型

19 typedef struct _ListNode //List node 类型

20 {

21 ListElmt data;

22 struct _ListNode *pre;

23 struct _ListNode *next;

24 }ListNode;

25

26 //typedef struct _ListNode ListNode;

27 typedef struct _ListNode *List; //定义链表的类型为ListNode类型的指针

28

29 //声明函数原型,这里有插入,删除,查找链表元素的函数,以及遍历链表的函数

30 int ListCreate(List *list,int len);

31 int ListDestroy(List *list);

32 int ListInsert(List *list,ListNode *node);

33 int ListDelete(List *list,ListElmt data);

34 int ListTravel(List list);

35 int ListFindElement(List list,ListElmt data);

36

37 #endif /*DOUBLE_LINKED_LIST_H*/

1 /* **************************

2 * Soure file of Double Linked List

3 * *************************/

4

5 #include"DoubleLinkedList.h"

6

7 //实现List的函数,为了方便,放到了主函数所在的文件中,最好是单独建立实现函数的源文件

8

9 //创建List Node,创建一个长度为len的链表,其中有一个链表头,链表中结点个数为len

10 int ListCreate(List *list,int len)

11 {

12 ListNode *l = NULL;

13 ListNode *p = NULL;

14

15 l = (ListNode*)malloc(sizeof(ListNode)); //先创建头结点

16

17 if(NULL == l) //分配成功后才能对它进行操作

18 return FAILE;

19

20 *list = l; //创建头结点,并且初始化

21 l->data = 0;

22 l->pre = NULL;

23 l->next = NULL;

24 #ifdef DEBUG

25 size += 1;

26 #endif

27

28 while(len-- > 0 )

29 {

30 p = (ListNode*)malloc(sizeof(ListNode)); //新创建结点

31

32 if(NULL != p)

33 {

34 l->next = p;

35 p->pre = l;

36 p->next = NULL;

37 l = p;

38 l->data = 0; //结点中的元素初始化为0,这里的data是Int类型

39 }

40 #ifdef DEBUG

41 size += 1;

42 #endif

43 }

44

45 return SUCCESS;

46 }

47

48 //删除List,从链表头开始删除,每次删除一个结点,直到所有结点都删除为止,此时为空链表,只剩下头结点

49 int ListDestroy(List *list)

50 {

51 ListNode *l = NULL;

52 ListNode *p = NULL;

53

54 if(NULL == *list) //空链表时不进行删除操作

55 {

56 printf("the list is empty \n");

57 return FAILE;

58 }

59

60 l = (*list)->next;

61 free(*list); //释放头结点

62 *list = NULL;

63

64 #ifdef DEBUG

65 size -= 1;

66 printf(" a delete a node in the list \n");

67 #endif

68 while(NULL != l) //从链表头结点的下一个结点开始,一个结点接着一个结点地删除

69 {

70 p = l->next; //detroy循环链表,沿着一个方向遍历就行,不需要考虑pre,但是delete链表时需要考虑,因为只是删除链表中的一个结点,不考虑会影响链表的完成性。

71 free(l);

72 l = p;

73 #ifdef DEBUG

74 size -= 1;

75 printf("delete a node in the list \n");

76 #endif

77 }

78 return SUCCESS;

79 }

80

81 //向链表中插入结点,插入时从链表尾部插入,每次插入一个结点.

82 int ListInsert(List *list,ListNode *node)

83 {

84 ListNode *l = NULL;

85

86 if(NULL == *list)

87 {

88 printf("this is a empty list, can't be insered \n");

89 return FAILE;

90 }

91

92 l = (*list)->next;

93 // while(l != *list) //遍历链表到表尾

94 // l = l->next;

95

96 // l = node; //在表尾插入结点

97 // l->next =*list;

98

99 (*list)->next = node; //在表头,也就是头结点后面插入结点,省去遍历链表的时间,这是有头结点的好处

100 node->pre = l->pre;

101 l->pre = node;

102 node->next = l;

103

104 #ifdef DEBUG

105 size += 1;

106 #endif

107 return SUCCESS;

108 }

109

110 //删除链表中包含data的结点

111 int ListDelete(List *list,ListElmt data)

112 {

113 int flag = 0;

114 int result = FAILE;

115 ListNode *current = NULL;

116 ListNode *next = NULL;

117

118 if(NULL == *list) //空链表没有结点,不能删除结点

119 {

120 printf("this is a empty list, can't be deleted \n");

121 return FAILE;

122 }

123

124 current = *list;

125 next = (*list)->next;

126

127 while(NULL != next) //依次遍历链表,查找被删除的元素,如果找到则删除结点,并且停止遍历链表

128 {

129 if(data == next->data)

130 {

131 current->next = next->next;

132 (next->next)->pre = next->pre;

133 free(next);

134 next = NULL;

135 flag = 1;

136 #ifdef DEBUG

137 size -= 1;

138 #endif

139 break;

140 }

141 current = next; //这里只沿一个方向进行遍历就可以

142 next = next->next;

143 }

144

145 if( 1 == flag )

146 result = SUCCESS;

147 else

148 result = FAILE;

149

150 return result;

151 }

152

153 //遍历链表,显示链表中的每个结点的data

154 int ListTravel(List list)

155 {

156 ListNode *l = NULL;

157

158 if(NULL == list) //空链表直接返回

159 {

160 printf("It is a empyt list \n");

161 return FAILE;

162 }

163

164 l = list->next;

165

166 while(l != NULL) //遍历链表,并且显示链表中的data

167 {

168 printf("%d \n",l->data);

169 l = l->next;

170 }

171

172 #ifdef DEBUG

173 printf("list size: %d \n",size);

174 #endif

175 return SUCCESS;

176 }

177

178 //查找链表中是否包含值为data的结点

179 int ListFindElement(List list,ListElmt data)

180 {

181 ListNode *l = NULL;

182 int result = FAILE;

183

184 if(NULL == list) //空链表直接返回

185 {

186 printf("It is a empyt list \n");

187 return FAILE;

188 }

189

190 l = list->next;

191 while( NULL != l) //依次遍历链表,查找值为data的结点

192 {

193 if(data == l->data) //找到后停止遍历链表,否则继续遍历链表

194 {

195 result = SUCCESS;

196 break;

197 }

198 else

199 l = l->next;

200 }

201

202 return result;

203 }

204

205 int main()

206 {

207 int result = FAILE;

208 int len = 3;

209 ListNode *node = NULL; //node必须是指针,而且要用malloc分配空间,因为要使free释放

210 List list = NULL; //创建一个指向链表的空指针

211

212 node = (ListNode *)malloc(sizeof(ListNode));

213 if(NULL != node)

214 {

215 node->data = 1;

216 node->next = NULL;

217 node->pre = NULL;

218 }

219

220 result = ListCreate(&list,len); //创建一个长度为Len的链表

221 if(result == SUCCESS)

222 ListTravel(list);

223

224 printf("Insert a node into list \n");

225 ListInsert(&list,node);

226 ListTravel(list);

227

228 result = ListFindElement(list,0);

229 if(result == SUCCESS )

230 printf("find it in the list \n");

231 else

232 printf("don't find it in the list \n");

233

234 printf("main delete a node in list \n");

235 result = ListDelete(&list,0);

236 if(result == SUCCESS )

237 ListTravel(list);

238

239 ListDestroy(&list);

240

241 #ifdef DEBUG

242 printf("list size: %d \n",size);

243 #endif

244 ListTravel(list);

245 return result;

246 }

各位看官,关于双向链表的例子咱们就说到这里。欲知后面还有什么例子,且听下回分解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值