C/C++链表

目录

概述

具体代码

1.建立一个指向头部的指针:

2.插入节点:

头部插入:

尾部插入:

随机位置插入:

3.删除节点:

4.反转链表:

5.打印链表:

 其他


概述

        链表(Linked List),运用结构体指针,可以实现将连续数组变为分段储存(内存上无须连续),比array更加灵活。

建立一个储存节点的结构体:

struct Node {
    int data;
    Node* next;//指向下一个节点,最后一个节点用NULL
};

        Array基本要给一个确定的大小,链表就不会有这个问题。如果需要扩充储存,array可以在原有长度的基础上增加(前提原先长度之后的内存并没有占用),否则电脑会找一段足够长的内存,将原先的数据粘贴过去,再把新数据记录;链表会相对简单些,只需要增加一个节点。不过添加、删除、寻找元素会比较麻烦,毕竟链表的内存不连续,需要从头开始一个一个查找。

具体代码

1.建立一个指向头部的指针:

//C++
Node* head = NULL;

//C
struct Node* head = NULL;
//C用结构体指针都要记得加struct

        因为一直要用到head,可以直接声明成全局变量;也可以在main()里声明,记得传参到函数里就行。

2.插入节点:

        写一个Insert()函数,会方便很多。

        因为是要在函数里完成插入,节点需要储存在堆(heap)里,因为函数运行完后会自动释放内存,如果结构体声明成local value,会在函数运行完后被自动释放(栈里运行完会自动释放)。所以记得用动态内存啊!

        C里的3种分配和释放内存:

void^* \quad malloc \ (size_t \ size) \\ void^* \quad calloc \ (size_t \ num, \ size_t \ size)\\ void^* \quad realloc \ (void^* \ ptr, \ size_t \ size)\\ \\free()

        (malloc和calloc申请内存,realloc调整大小)这里使用malloc()和free()即可。

//例如:
struct Node* one = (struct Node*)malloc(sizeof(struct Node));
//(struct Node*):声明data type,因为malloc返回void
free(one);

        C++中使用new 和 delete()。

Node* one = new Node();
delete(one);

        (不要混用,像malloc用delete,new用free。new和delete会调用构造函数和析构函数,而malloc和free不会。malloc+delete可能会出错,new+free会没释放内存。)

  • 头部插入:

        将原先的首个节点的地址储存到新节点的next中,然后head指向新节点。

void InsertHead(int data) {
    Node* tmp = new Node();//struct Node* tmp = (struct Node*)malloc(sizeof(struct Node));
    tmp->data = data;
    tmp->next = NULL;
    if (head == NULL) {
        head = tmp;//指向首个节点
        return;
    }
    tmp->next = head;//新节点指向原头部节点
    head = tmp;//更新head
}

       ' ->'用来访问结构体里的数据,tmp->data等于(*tmp).data,  '.'也是访问符

        (C里写Node*,前面都要加struct,which means:struct Node* tmp = ...)

  • 尾部插入:

        先遍历到尾部(指针->next == NULL),然后将最后一个节点的NULL变成新节点的地址。

void Insert(int num) {
    Node* tmp = new Node();//struct Node* tmp = (struct Node*)malloc(sizeof(struct Node));
    tmp->data = num;
    tmp->next = NULL;

    if (head == NULL) {
        head = tmp;
        return;
    }
    Node* tmp1 = head;
    while (tmp1->next != NULL) {
        tmp1 = tmp1->next;
    }//运行完后,tmp1指向最后一个节点
    tmp1->next = tmp;
}
//用C写记得一定要带struct!
  • 随机位置插入:

        插到开头位置和前面一样。插到中间的话,先遍历到插入位置的前一个节点。将下一节点的地址(储存在前一节点的next里)储存到新节点里,再将前一节点指向新节点。

void Insert(int data, int position) {
    Node* tmp1 = new Node();//struct Node* tmp1 = (struct Node*)malloc(sizeof(struct Node));
    tmp1->data = data;
    tmp1->next = NULL;

    if (position == 1) {
        tmp1->next = head;
        head = tmp1;
        return;
    }

    Node* tmp2 = head;
    for (int i = 0; i < position - 2; i++) {//head直接指向第一个位置,需要减1;还要遍历到前一节点,再减1
        tmp2 = tmp2->next;
    }
    tmp1->next = tmp2->next;
    tmp2->next = tmp1;
}

3.删除节点:

删除头部节点:更新head,删除节点。

非头部:将上一个节点的next链接到下一个节点上,删除节点。

void Delete(int x) {//删除data x
    Node* tmp = head;
    Node* prev = NULL;
    while (tmp != NULL) {
        if (tmp->data == x) {
            if (x == head->data) {
                head = tmp->next;
            }//删除头部需要更新head
            if (prev != NULL) {
                prev->next = tmp->next;
            }//非头部节点建立联结
            delete(tmp);
            return;
        }
        prev = tmp;
        tmp = tmp->next;
    }
}

4.反转链表:

  • 创建三个指针,前、中、后,一个一个修改next。
//遍历
void Reverse() {
    Node* prev, * current, * next;
    prev = NULL;
    current = head;
    while (current != NULL) {
        //next先指到下一个,修改current指向前一个
        next = current->next;
        current->next = prev;
        //prev走到下一个,current走到下一个
        prev = current;
        current = next;
    }
    head = prev;
}
  • 利用递归
//递归
void Reverse(Node* p) {
    if (p->next == NULL) {
        head = p;
        return;
    }
    Reverse(p->next);
    //Node* q = p->next;
    //q->next = p;
    //or
    p->next->next = p;//修改下一节点的next,指向本节点
    p->next = NULL;
}

5.打印链表:

  • 正序打印,遍历一遍
void Print() {
    Node* tmp = head;
    while (tmp != NULL) {
        cout << tmp->data << " ";
        tmp = tmp->next;
    }
    cout << endl;
}
  • 反向打印,用递归
void ReversePrint(Node* ptr) {
    if (ptr == NULL) {
        return;
    }
    ReversePrint(ptr->next);
    cout << ptr->data << " ";
}
//main调用的时候把head传进来

 其他

C++双向链表(插入/删除/打印)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值