Linked list这种数据结构,主要用于对数据进行操作。链表长成下面这样,由多个节点串起来,每个节点有两个域,一个是数据域(用于存储你的数据),一个是指针域(用于存储指向下一个节点的指针),最后一个节点一般指向NULL。
那么再看下面这张图
从上图可以看出,每个节点之间的地址不是连续的,这个地址是由系统分配的(用malloc创建节点的时候,系统会给该节点分配内存,而每一块内存都有对应的地址)。如a1的指针域是800,而a2的起始地址是800,说明a1的下一个节点就是a2,以此类推,a4的下一个节点是a5,a5是最后一个节点(一般系统会默认NULL为0地址,而a5的指针域指向的是0)
链表基本操作有创建/插入/删除/查找,下面,用两张图来说明插入和删除的操作原理:
有些人为了方便链表的操作,经常会给链表添加一个头结点做处理,见下图
至于头结点的意义在哪里,详见 链表头结点存在的意义
下面我们就直接看代码的实现
linked_list.c
#include <stdio.h>
#include <stdlib.h>
#include "typedef.h"
#include "linked_list.h"
LINK_LIST_T link_list_init(VOID)
{
LINK_LIST_T pList = (LINK_LIST_T)malloc(sizeof(NODE_T));
if(!pList)
{
printf("link_list_init malloc failed! \n");
return NULL;
}
pList->next = NULL;
return pList;
}
BOOL link_list_is_empty(LINK_LIST_T pList)
{
LINK_LIST_CHK_FAIL(pList, TRUE);
return pList->next == NULL;
}
BOOL link_list_is_last(ElementType element, LINK_LIST_T pList)
{
LINK_LIST_CHK_FAIL(pList, FALSE);
LINK_LIST_T pTemp = pList;
while(pTemp->next != NULL) // fine the last node
pTemp = pTemp->next;
if(pTemp->element == element)
return TRUE;
else
return FALSE;
}
/****************************************************************************
***
*** Check the element in the list or not, if find, return TRUE, if not find, return FALSE
***
****************************************************************************/
BOOL link_list_find_element(ElementType element, LINK_LIST_T pList)
{
LINK_LIST_CHK_FAIL(pList, FALSE);
LINK_LIST_T pTemp = pList->next;
while(pTemp)
{
if(pTemp->element == element)
return TRUE;
pTemp = pTemp->next;
}
return FALSE;
}
/****************************************************************************
***
*** Check the element in the list or not, if find, return the index, if not find, return 0
***
****************************************************************************/
INT32 link_list_find_element_ret_index(ElementType element, LINK_LIST_T pList)
{
LINK_LIST_CHK_FAIL(pList, LISTR_FAIL);
LINK_LIST_T pTemp = pList->next;
INT32 index = 0;
while(pTemp)
{
index++;
if(pTemp->element == element)
return index;
pTemp = pTemp->next;
}
return 0;
}
/****************************************************************************
***
*** Find the element by the index, if find, it can get the element, if not, return FALSE
***
****************************************************************************/
BOOL link_list_find_by_index(ElementType *element, INT32 index, LINK_LIST_T pList)
{
LINK_LIST_CHK_FAIL(pList, FALSE);
LINK_LIST_T pTemp = pList->next;
INT32 i = 1;
while(pTemp && i<index)
{
pTemp = pTemp->next;
i++;
}
if(!pTemp || i>index)
{
printf("Cannot find the index, invalid args!\n");
return FALSE;
}
*element = pTemp->element;
return TRUE;
}
POSITION link_list_find_previous(ElementType element, LINK_LIST_T pList)
{
LINK_LIST_CHK_FAIL(pList, NULL);
LINK_LIST_T pTemp = pList;
LINK_LIST_T qTemp = pTemp;
while(pTemp && pTemp->element != element)
{
qTemp = pTemp;
pTemp = pTemp->next;
}
if(!pTemp)
{
printf("Cannot find the element in the list!\n");
return NULL;
}
return qTemp;
}
INT32 link_list_insert_at_tail(ElementType element, LINK_LIST_T pList)
{
LINK_LIST_CHK_FAIL(pList, LISTR_FAIL);
LINK_LIST_T pTemp = pList;
while(pTemp->next != NULL)
{
pTemp = pTemp->next;
}
LINK_LIST_T node = (LINK_LIST_T)malloc(sizeof(NODE_T));
if(!node)
{
printf("link_list_insert_at_tail malloc failed! \n");
return LISTR_FAIL;
}
node->element = element;
node->next = NULL;
pTemp->next= node;
return LISTR_OK;
}
INT32 link_list_insert_at_head(ElementType element, LINK_LIST_T pList)
{
LINK_LIST_CHK_FAIL(pList, LISTR_FAIL);
LINK_LIST_T pTemp = pList;
LINK_LIST_T pNext = pList->next;
LINK_LIST_T node = (LINK_LIST_T)malloc(sizeof(NODE_T));
if(!node)
{
printf("link_list_insert_at_head malloc failed! \n");
return LISTR_FAIL;
}
node->element = element;
node->next = pNext;
pTemp->next= node;
return LISTR_OK;
}
INT32 link_list_insert_by_index(ElementType element, INT32 index, LINK_LIST_T pList)
{
LINK_LIST_CHK_FAIL(pList, LISTR_FAIL);
LINK_LIST_T pTemp = pList;
INT32 i = 1;
while(pTemp && i<index)
{
pTemp = pTemp->next;
i++;
}
if(!pTemp || i>index)
{
printf("The index is not exist! \n");
return LISTR_FAIL;
}
LINK_LIST_T node = (LINK_LIST_T)malloc(sizeof(NODE_T));
if(!node)
{
printf("link_list_insert_at_head malloc failed! \n");
return LISTR_FAIL;
}
node->element = element;
node->next = pTemp->next;
pTemp->next = node;
return LISTR_OK;
}
INT32 link_list_delete_by_index(ElementType *element, INT32 index, LINK_LIST_T pList)
{
LINK_LIST_CHK_FAIL(pList, LISTR_FAIL);
LINK_LIST_T pTemp = pList;
LINK_LIST_T qTemp;
INT32 i=1;
while(pTemp->next && i<index)
{
pTemp = pTemp->next;
i++;
}
if(pTemp->next == NULL || i>index)
{
printf("The index is not exist\n");
return LISTR_FAIL;
}
qTemp = pTemp->next;
*element = qTemp->element;
pTemp->next = qTemp->next;
free(qTemp);
return LISTR_OK;
}
INT32 link_list_get_list_len(LINK_LIST_T pList)
{
LINK_LIST_CHK_FAIL(pList, LISTR_FAIL);
LINK_LIST_T pTemp = pList;
INT32 len = 0;
if(!pList)
{
printf("The link list is uninit, pls init it\n");
return LISTR_FAIL;
}
while(pTemp->next)
{
len++;
pTemp = pTemp->next;
}
return len;
}
INT32 link_list_uninit(LINK_LIST_T pList)
{
LINK_LIST_T pTemp;
while(pList)
{
pTemp = pList->next;
free(pList);
pList = pTemp;
}
return LISTR_OK;
}
VOID link_list_traverse(LINK_LIST_T pList)
{
LINK_LIST_CHK_FAIL(pList, (void)LISTR_FAIL);
LINK_LIST_T pTemp = pList->next;
while(pTemp != NULL)
{
printf("node->element : %d\n", pTemp->element);
pTemp = pTemp->next;
}
}
VOID link_list_main_test(VOID)
{
INT32 i;
LINK_LIST_T pList = link_list_init();
for(i=1; i<=10; i++)
link_list_insert_at_tail(i, pList);
link_list_traverse(pList);
if(pList)
{
link_list_uninit(pList);
}
}
linked_list.h
#ifndef __LINKED_LIST_H__
#define __LINKED_LIST_H__
typedef int ElementType;
typedef struct _NODE_T
{
ElementType element;
struct _NODE_T *next;
}NODE_T;
typedef struct _NODE_T * LINK_LIST_T;
typedef struct _NODE_T * POSITION;
#define LISTR_OK ((INT32)0)
#define LISTR_FAIL ((INT32)-1)
#define LINK_LIST_CHK_FAIL(argu, value) if(!(argu)) {printf("<LINK_LIST> ERR : func=%s, line=%d, argument="#argu".\n", __func__, __LINE__); return value;}
extern LINK_LIST_T link_list_init(VOID);
extern BOOL link_list_is_empty(LINK_LIST_T pList);
extern BOOL link_list_is_last(ElementType element, LINK_LIST_T pList);
extern BOOL link_list_find_element(ElementType element, LINK_LIST_T pList);
extern INT32 link_list_find_element_ret_index(ElementType element, LINK_LIST_T pList);
extern BOOL link_list_find_by_index(ElementType *element, INT32 index, LINK_LIST_T pList);
extern POSITION link_list_find_previous(ElementType element, LINK_LIST_T pList);
extern INT32 link_list_insert_at_tail(ElementType element, LINK_LIST_T pList);
extern INT32 link_list_insert_at_head(ElementType element, LINK_LIST_T pList);
extern INT32 link_list_insert_by_index(ElementType element, INT32 index, LINK_LIST_T pList);
extern INT32 link_list_delete_by_index(ElementType *element, INT32 index, LINK_LIST_T pList);
extern INT32 link_list_get_list_len(LINK_LIST_T pList);
extern INT32 link_list_uninit(LINK_LIST_T pList);
extern VOID link_list_traverse(LINK_LIST_T pList);
extern VOID link_list_main_test(VOID);
#endif
PS:本文所用的图片全都引用自《数据结构与算法分析C语言描述 第2版》第三章