内容
实现了单链表的基本操作,包括:节点的创建、添加、插入、删除、遍历、翻转。
代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <time.h>
typedef unsigned long Data;
typedef struct node{
Data data;
struct node *next;
}link_node,*pnode;
static pnode free_list(pnode head)
{
pnode temp = NULL;
if (!head)
return head;
//printf("into %s\n",__func__);
temp = head;
printf("free data :\n");
while (temp != NULL) {
temp = temp->next;
printf("%lu ", head->data);
free(head);
head = temp;
}
printf("\n");
//printf("leave %s\n",__func__);
return head;
}
static void print_list(pnode head)
{
pnode temp = NULL;
//printf("into %s\n",__func__);
if (!head) {
printf("List is null!\n");
return ;
}
temp = head;
printf("print data :\n");
while (temp != NULL) {
printf("%lu ", temp->data);
temp = temp->next;
}
printf("\n");
//printf("leave %s\n",__func__);
}
static pnode reverse_list(pnode head)
{
if (!head || head->next == NULL) {
return head;
}
pnode temp = head, pre = head->next;
temp->next = NULL;
//while(pre->next != NULL) //err
while (pre != NULL) {
head = pre;
pre = pre->next;
head->next = temp;
temp = head;
}
temp = NULL;
return head;
}
static pnode dele_first_node(pnode head)
{
if (head == NULL) {
return head;
}
pnode temp = head;
if (temp->next != NULL)
temp = temp->next;
Data data = head->data;
free(head);
head = temp;
printf("delet the first node, the data=%lu\n", data);
return head;
}
static pnode insert_node_first(pnode head, pnode node)
{
assert(node);
printf("insert the data=%lu\n", node->data);
pnode temp = head;
head = node;
node->next = temp;
return head;
}
static pnode add_node_tail(pnode head, pnode node)
{
//printf("into %s\n",__func__);
assert(node);
if (head == NULL) {
head = node;
return head;
}
pnode temp = head;
//printf("%s, list data : ", __func__);
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = node;
//printf("leave %s\n",__func__);
return head;
}
static pnode creat_node(Data data)
{
pnode node = (pnode)malloc(sizeof(link_node));
if (!node) {
perror("malloc:");
return NULL;
}
//printf("into %s\n",__func__);
memset(node, 0, sizeof(link_node));
node->data = data;
node->next = NULL;
//printf("leave %s\n",__func__);
return node;
}
int main(void)
{
pnode head = NULL;
pnode new_node = NULL;
//srand((unsigned)time(NULL));
for(int i = 0; i < 10; i++) {
//new_node = creat_node(rand());
new_node = creat_node(i*100);
head = add_node_tail(head, new_node);
}
print_list(head);
head = dele_first_node(head);
print_list(head);
new_node = creat_node(1234);
head = insert_node_first(head, new_node);
print_list(head);
head = reverse_list(head);
print_list(head);
if(free_list(head)) {
printf("unlikely: maybe some exception !!!!!\n");
}
return 0;
}
测试结果
./a.out
print data :
0 100 200 300 400 500 600 700 800 900
delet the first node, the data=0
print data :
100 200 300 400 500 600 700 800 900
insert the data=1234
print data :
1234 100 200 300 400 500 600 700 800 900
print data :
900 800 700 600 500 400 300 200 100 1234
free data :
900 800 700 600 500 400 300 200 100 1234
总结
链表很简单,总结点如下:
1. 注意 malloc 的使用,注意 free 的使用;
2. 区分何时判断节点为空,何时判断节点的下一个节点为空,代码表示为, if(node == NULL) 和 if (node->next == NULL);
3. 链表的翻转,链表的打环,链表环点检测,链表的中间点检测,都是在指针的基础上做文章。单链表的翻转,需要一个前指针,一个后指针,一个临时节点指针,它们前进的“速度”是一样的;而后面几个问题的解决,需要“快慢”指针进行处理,所谓的快慢,一个是 temp = tem->next; 一个是 temp = temp->next->next,而在这过程中,一定处理好总结的第二点。
4. 链表和数据的关系,本文的测试代码,链表节点中的数据类型是统一的,就形成了一种链表节点包含数据的关系。但是在实际中,如果希望同一条链表上,可以挂载不同类型的数据,那么本文的示例代码就不再合适,就必须想办法,让数据来包含链表,最直接的做法,就是在数据结构体中,包含一个链表的成员,这一部分,可参考 Linux kernel 的链表实现方法。