算法学习-链表-level1

part1:单向链表

1、构造

struct Node* insertNode(node* head, node* nodeInsert, int position)
{
    if (head == NULL) {
        return nodeInsert;
    }

    int listSize = getLength(head);
    if (position < 1 || position > listSize + 1) {
        cout << "OVERREACH!" << endl;
    }

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

    node* prev = head;
    int cnt = 1;
    while (cnt < position - 1) {
        cnt++;
        prev = prev->next;
    }
    nodeInsert->next = prev->next;
    prev->next = nodeInsert;
    return head;
}

2、创建节点并初始化

struct Node* initList()
{
    node* head = NULL;
    node* curr = (node*)malloc(sizeof(node));
    curr->val = 0;
    curr->next = NULL;
    head = curr;
    for (int i = 1; i < 10; i++)
    {
        node* temp = (node *)malloc(sizeof(node));
        temp->val = i;
        temp->next = NULL;
        curr->next = temp;
        curr = curr->next;
    }
    return head;
}

3、基础操作-增删

首先写出打印函数方便后续的检验

void printList(node *head)
{
    for (node* temp = head; temp != NULL; temp = temp->next)
    {
        cout << temp->val << " ";
    }
    cout << endl;
    return;
}

接下来写出获取链表长度的函数,目的是检验接下来插入时的边界的的检验

int getLength(node *head)
{
    int length = 0;
    node *temp =  head;
    while (temp!=NULL)
    {
        length++;
        temp = temp->next;
    }
    return length;
}

准备工作结束~ 

那么接下来正式开始链表的增删操作

struct Node* insertNode(node* head, node* nodeInsert, int position)
{
    if (head == NULL) {
        return nodeInsert;
    }

    int listSize = getLength(head);
    if (position < 1 || position > listSize + 1) {
        cout << "OVERREACH!" << endl;
    }

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

    node* prev = head;
    int cnt = 1;
    while (cnt < position - 1) {
        cnt++;
        prev = prev->next;
    }
    nodeInsert->next = prev->next;
    prev->next = nodeInsert;
    return head;
}

这里的增加节点的操作需要注意的是对于每一种情况最好做到不重不漏 

链表为空、插入位置的不合法、首个插入以及在中间插入

注意:

1、对于中间插入,因为单向链表中存在“开弓没有回头箭”的情况 所以我们选择记录插入节点的前一个节点(prev)这样我们就可以利用prev->next的方法很好的去进行接下来的操作。

2、插入的过程需要遵守一个原则:先连接后续的节点,再连接前面的节点。否则在我们连接好前面的节点与插入节点之后,后续的节点就会全部丢失。

这里给出图解:

image.png

这里给出一个单调插入的思路:

先进行数字的寻找,这里我们用循环遍历数组,寻找到符合要求的smaller节点

    node* smaller = head;
    while ((smaller->next != NULL) && (smaller->next->val < nodeInsert->val)) {
        smaller = smaller->next;
    }

注意:

1、这里循环的条件顺序不可以改变,进行逻辑与操作时会先进行前键的判断,也就是先判断smaller节点的next是否存在,只有存在时才能进行其下一节点大小的比较。否则程序会直接崩溃

2、这也是写链表中很重要的点,只有先确定节点的存在性才能进行下面一系列的操作,比如双向链表的插入中操作curr->prev->next = curr->next,只有确认curr->next节点的存在才能进行进一步的比对。这也是链表操作实现中分类的前提,理解好这一步就可以理解如何分类进行链表的操作,例如:双向链表头插法时,只有头节点存在head->prev = curr才能实现,所以需要提前判断,每种情况都要有所思考,不重不漏。

接下来是单调插入的具体实现代码:

struct Node* monotonousInsertnode(node* head, node* nodeInsert)
{
    if (head == NULL) {
        return nodeInsert;
    }

    if (nodeInsert->val < head->val) {
        nodeInsert->next = head;
        head = nodeInsert;
        return head;
    }

    node* smaller = head;
    while ((smaller->next != NULL) && (smaller->next->val < nodeInsert->val)) {
        smaller = smaller->next;
    }
    nodeInsert->next = smaller->next;
    smaller->next = nodeInsert;
    return head;
}

删除部分与插入部分相似这里不做过多说明

直接上代码:

struct Node* deleteNode(node* head, int position)
{
    if (head == NULL) {
        return NULL;
    }

    int listSize = getLength(head);
    if (position < 1 || position > listSize) {
        cout << "INPUT ERROR" << endl;
        return head;
    }

    if (position == 1) {
        node* temp = head;
        head = head->next;
        free(temp);
        return head;
    }

    node* prev = head;
    int cnt = 1;
    while (cnt < position - 1) {
        cnt++;
        prev = prev->next;
    }
    node* curr = prev->next;
    prev->next = curr->next;
    free(curr);
    return head;
}

最后附带一些可能用的上的测试代码:

void testInsert()
{
    node* head = NULL;
    node* temp = (node*)malloc(sizeof(node));
    temp->val=1;
//    插入第一个元素
    head = insertNode(head,temp,1);
    printList(head);

 //    插入第二个元素,因为前面至于一个元素,这里就是在尾部插入了
    temp = (node*)malloc(sizeof(node));
    temp->val=3;
    head=insertNode(head,temp,2);
    printList(head);


 //    插入第二个元素,后面有个三,所以这里就是中间位置插入了
    temp = (node*)malloc(sizeof(node));
    temp->val=2;
    head=insertNode(head,temp,2);
    printList(head);
}

void testMonotonousInsert()
{

    node* head = NULL;
    node* temp = (node*)malloc(sizeof(node));
    temp->val=1;

    head = monotonousInsertnode(head,temp);
    printList(head);

    temp = (node*)malloc(sizeof(node));
    temp->val=3;
    head=monotonousInsertnode(head,temp);
    printList(head);

    temp = (node*)malloc(sizeof(node));
    temp->val=2;
    head=monotonousInsertnode(head,temp);
    printList(head);

    temp = (node*)malloc(sizeof(node));
    temp->val=4;
    head=monotonousInsertnode(head,temp);
    printList(head);

    temp = (node*)malloc(sizeof(node));
    temp->val=8;
    head=monotonousInsertnode(head,temp);
    printList(head);

    temp = (node*)malloc(sizeof(node));
    temp->val=-1;
    head=monotonousInsertnode(head,temp);
    printList(head);
}

void testDelete()
{

    node* p = NULL;
    printf("create list: \t\n");
    //创建链表0~5
    p = initList();
    printList(p);

    // 删除第一个元素0
    p= deleteNode(p,1);
    printList(p);

   //删除中间元素
    p= deleteNode(p,5);
    printList(p);

   //删除末尾元素9
    p= deleteNode(p,8);
    printList(p);

}

希望对大家能有所帮助。

图片来源:编程导航算法通关村第一期

具体来源:算法通关村第一关——链表—青铜挑战

作者:余秋

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值