欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

链表基本操作

程序员文章站 2024-03-19 15:46:04
...

今天上课男神讲了链表,可以说是非常懵逼。为了防止遗忘及时整理,但个人感觉理解的还是不太到位。
话不多说,开始正题。
链表通过一个结构体来构建:

typedef struct node{
    int data;
    struct node * next;
}Node;

几种功能函数的手写:
首先是最简单的打印链表函数printList:

/*打印链表元素的函数,传入首节点地址即可*/
void printList(Node * head)
{
    for(; head; ){
        printf("%d ", head ->data);
        head = head -> next;
    }
    puts("");
}

链表长度 sizeList:

/*统计链表长度*/
int sizeList(Node *head)
{
    int i;
    for(i = 0; head; ++i)
        head = head ->next;
    return i;
}

尾部插入

/*尾部插入法*/
/*
*尾部插入分两种情况
*  ① list存在(一般情况)
*  ② list是空链表插入的元素是链表的第一个元素
*  步骤:  动态分配内存创建一个新的链表(结构体成员)
*  然后根据实际链表情况将新创建的链表放到原链表的末尾
*/
//形参列表 由于函数要修改指针的指向 所以应该用二级指针来操作一级指针!
void pushBacklist(Node **plist, int data)
{
    //创先新链表单元
    Node * newNode = (Node *)malloc(sizeof(Node));
    newNode->data = data;
    newNode->next = NULL;
    //核心插入 分两种情况
    //一般情况,List不为空链表, 那就往后找直到最后一个。
    if(*plist != NULL){
        Node * temp = * plist;
        while(temp ->next != NULL)
            temp = temp ->next;
        temp ->next = newNode;
    }
    //空链表的情况
    else{
        *plist = newNode;
    }
}

首部插入法:

/*首部插入法*/
void pushFrontlist(Node ** plist, int data)
{
    //同样先建创建新的链表单元
    Node * newNode = (Node *)malloc(sizeof(Node));
    newNode ->data  = data;
    newNode ->next = *plist;
    //插入  只有一种情况直接赋值即可
    *plist = newNode;
}

清空链表操作

/*清空链表*/
/*想要清空链表仍然要对指向链表的指针进行操作,故形参列表要传二级指针!
* 清空链表要维护两个指针,一个指针(temp)负责free该单元的,另一个指针
*(head)要指向下一个单元,两指针共同向前移动直到释放最后一个链表单元。
*/
void freeList(Node **plist)
{
    Node * head = *plist;
    Node * temp;
    while(head != NULL){
        temp = head;
        head = head->next;
        free(temp);
    }
    //切记清空 *plist
    *plist = NULL;
}

删除特定单元:

/*删除链表中某特定值data值的单元*/
/*
*要从第一个链表的data开始依次比对data值与目标值是否相符,如果相符
*就删去,否则continue。
*/
void deletData(Node ** plist, int data)
{
    Node * head = *plist;
    Node * temp;
    while(head ->next != NULL){
        //如果不是目标data,就指向下一个节点
        if(head ->next->data != data){
            head = head ->next;
            continue;
        }
        //如果是目标data,进行删除操作
        temp = head ->next;
        head ->next = temp ->next;
        //删除目标节点
        free(temp);
    }
    //最后对第一个节点进行操作
    if((*plist) ->data == data){
        temp = *plist;
        *plist = temp ->next;
        free(temp);
    }
}

附上完整的测试样例

int main(void)
{
    Node n1, n2, n3, n4;
    n1.data  = 10;
    n2.data = 20;
    n1.next = &n2;
    n2.next = NULL;
    printList(&n1); //10
    printf("%d\n", sizeList(&n1)); //20

    //维护一个动态指针
    Node * list = NULL;

    printf("尾插后的数组是:\n");
    pushBacklist(&list, 10);
    pushBacklist(&list, 20);
    pushBacklist(&list, 30);
    printList(list);  //10 20 30

    printf("首插后的数组是:\n");
    pushFrontlist(&list, 80);
    pushFrontlist(&list, 90);
    printList(list);  //90 80 10 20 30

    printf("释放链表:\n");
    freeList(&list);
    pushBacklist(&list, 100);
    printList(list);//100
    freeList(&list);

    puts("==========================");
    printf("验证删除链表元素\n");
    pushBacklist(&list, 1);
    pushBacklist(&list, 1);
    pushBacklist(&list, 2);
    pushBacklist(&list, 3);
    pushBacklist(&list, 4);
    pushBacklist(&list, 4);
    pushBacklist(&list, 5);
    pushBacklist(&list, 5);
    puts("删除前:");
    printList(list);
    puts("删除1");
    deletData(&list, 1);
     puts("删除后:");
    printList(list);
    return 0;
}
相关标签: 链表的基本操作