单向链表的基本操作-创建、插入、删除

一.链表的基本概念

单链表 :  n个结点链接成一个链式线性表的结构叫做链表,当每个结点中只包含一个指针域时,叫做单链表 

表头结点:链表中的第一个结点,包含指向第一个数据元素的指针以及链表自身的一些信息 如长度等

􏰀数据结点:链表中代表数据元素的结点,包含指向下一个数据元素的指

􏰀尾结点:   链表中的最后一个数据结点,其下一元素指针为空,表示无后继 

 

 

二.链表的定义

由于带头的链表操作比较方便,下文介绍的所有操作都是基于都头结点的单链表,

1.链表的定义

1 /* 链表节点的定义 */
2 typedef struct list
3 {
4     int data;          //数据域
5     struct list *next; //指针域
6 }linkList;
View Code

2.链表的创建

创建一个带头结点的空链表,头结点中的数据成员存储的是当前链表的节点个数

/* 创建一个带头结点的空链表 */
linkList *linkListCreate()
{
    // 为头结点申请空间
    linkList *pHead = (linkList *)malloc(sizeof(linkList));
    if (pHead != NULL)
    {
        pHead->data = 0;
        pHead->next = NULL;// 由于创健的链表为空,指向的节点为空
    }
    // 节点个数为0
    pHead->data = 0;
    return pHead;
}
View Code

3.链表的插入

插入元素到位置pos的算法 􏰁

1)判断线性表是否合法

2)判断插入位置是否合法

3)由表头开始通过next指针移动pos次后,当前元素的next指针即指向要插入的位置 􏰁

4)将新元素插入

􏰁5)线性表长度加1

插入元素操作指针的步骤非常重要,一定要先将新节点的指针指向current的next。

代码如下:

/* 功能:带头节点的单链表中的pos位置插入元素,指定位置大于链表长度则插到链表尾
   参数: pHead-头指针  pos-位置 pNode-要插入的节点
   返回值: 成功返回1 失败-1
   说明:位置大于等于0
 */
int linkListInsertNode(linkList *pHead,int pos,linkList *pNode)
{
    // 安全性的检查
    if(pHead == NULL ||pNode == NULL || pos < 0)
    {
        return -1;
    }
    linkList *pCurrent = pHead;
    for (int i = 0; (i < pos)&&(pCurrent->next != NULL); i++)
    {
        pCurrent = pCurrent->next;
        // 避免成环,如果调用函数者传的参数都是同一节点地址就会成环
        if(pCurrent == pNode)
        {
            return -1;
        }
    }
    pNode->next = pCurrent->next;
    pCurrent->next = pNode;
    // 链表长度记录加1
    pHead->data++;
    return 1;
}
View Code

3. 链表的删除

链表删除指定位置节点的步骤:

1)链表是否合法

2)链表的位置是否合法

3)获取指定位置的元素

4)将元素下链

5)长度减一

代码如下:

 1 /* 带头节点的单链表中删除pos位置的元素,指定位置大于链表长度则返回NULL
 2    参数: pHead头指针  pos位置
 3    返回值: 成功返回被删除的节点 失败NULL
 4    说明:位置大于等于0 小于长度
 5  */
 6 int linkListDeleteNode(linkList *pHead,int pos)
 7 {
 8     // 删除的节点位置不能超过当前链表的长度
 9     if((pHead == NULL) || (pos < 0) || (pos > pHead->data - 1))
10     {
11         return -1;
12     }
13     linkList *currentNode = pHead;
14     linkList *deleteNode = NULL;
15     // 定位pos位置currentNode->next即为pos位置节点
16     for (int i = 0; i < pos; i++)
17     {
18         currentNode = currentNode->next;
19     }
20     deleteNode = currentNode->next;
21     currentNode->next = deleteNode->next;
22     // 释放节点内存
23     free(deleteNode);
24     // 长度减一
25     pHead->data--;
26     return 1;
27 }
View Code

4. 获取指定位置的元素

获取第pos个元素操作 􏰁

1)判断线性表是否合法

􏰁2)判断位置是否合法

3  由表头开始通过next指针移动pos次后,当前元素的next指针即指向要获取的元素 

 1 /* 带头节点的单链表中获取pos位置的元素,指定位置大于链表长度则返回NULL
 2    参数: pHead头指针  pos位置
 3    返回值: 成功返回节点地址 失败NULL
 4    说明:位置大于等于0小于当前元素个数
 5  */
 6 linkList *linkListGetNode(linkList *pHead,int pos)
 7 {
 8     // 链表与位置是否合法
 9     if(pHead == NULL || pos < 0 || (pos > pHead->data -1))
10     {
11         return NULL;
12     }
13     linkList *pGetNode = NULL;
14     linkList *pCurrent = pHead;
15     for (int i = 0; i < pos; i++)
16     {
17         pCurrent = pCurrent->next;
18     }
19     pGetNode = pCurrent->next;
20     return pGetNode;
21 }
View Code

5. 获取当前链表的元素个数

由于头结点中的数据存储的是链表的节点个数,所以只要将此值返回即可

1 int linkListGetLength(linkList *pHead)
2 {
3     if(pHead != NULL)
4     {
5         return pHead->data;
6     }
7     return -1;
8 }
View Code

6. 链表节点的创建

 1 linkList *linkLisNodeCreate(int val)
 2 {
 3     // 申请空间
 4     linkList *node = (linkList *)malloc(sizeof(linkList));
 5     // 申请成功则初始化
 6     if(node != NULL)
 7     {
 8         node->data = val;
 9         node->next = NULL;
10     }
11     return node;
12 }
View Code

7.链表的销毁

由于节点的空间都是使用malloc从堆空间分配,所以使用完毕必须释放空间,否则造成内存泄露

 1 void freeList(linkList *pHead)
 2 {
 3     linkList *node = pHead;
 4     while (node != NULL)
 5     {
 6         pHead = pHead->next;
 7         free(node);
 8         node = pHead;
 9     }
10     free(pHead);
11 }
View Code

8.测试程序

int main()
{

    // 链表的创建
    linkList *pHead = linkListCreate();
    // 创建四个节点
    linkList *node1 = linkLisNodeCreate(1);
    linkList *node2 = linkLisNodeCreate(2);
    linkList *node3 = linkLisNodeCreate(3);
    linkList *node4 = linkLisNodeCreate(4);
    linkList *node5 = linkLisNodeCreate(5);

    // 头插法插到链表中先插入的节点会在后面
    linkListInsertNode(pHead, 0, node1);
    linkListInsertNode(pHead, 0, node2);
    linkListInsertNode(pHead, 0, node3);
    linkListInsertNode(pHead, 0, node4);

    /* 获取链表长度 */
    printf("lengh %d\n",linkListGetLength(pHead));
    /* 遍历链表 */
    printWithHeadLinkList(pHead);
    
    // 获取第三个位置的元素
    linkList *temp = linkListGetNode(pHead,3);
    printf("temp ->data = %d\n",temp->data);
    
    /* 删除链表测试用例 */
    
    // 删除右边界节点(最后一个)
    linkListDeleteNode(pHead, linkListGetLength(pHead)-1);
    // 删除左边界节点(第0个)
    linkListDeleteNode(pHead, 0);
    // 删除中间的节点
    linkListDeleteNode(pHead, 2);
    // 删除不存在的节点
    linkListDeleteNode(pHead, -1);
    

    printWithHeadLinkList(pHead);
    
    // 销毁链表
    freeList(pHead);
    pHead = NULL;

    return 0;
}
View Code

 

 

posted @ 2015-04-14 11:50  HugoJiang  阅读(624)  评论(0编辑  收藏  举报