数据结构 数组、链表

本文探讨了数据结构中的核心概念——数组和链表。数组提供了随机访问但插入和删除效率低,而链表则在这些操作上表现更优。详细介绍了链表的查找、插入和删除,包括单链表反转、环检测、两个有序链表合并等典型问题,并讨论了链表在缓存、栈实现中的应用。同时,文章也对比了C/C++与Java数组的实现优缺点。
摘要由CSDN通过智能技术生成

数据结构与算法 数组、链表

相关:单链表反转,链表中环的检测(快慢指针),两个有序链表的和并(类似归并排序),删除链表倒数第K个结点,寻找链表的中间结点(快慢指针)


2135周 学习日志

数组
  • 定义
  • 动态扩容
  • 容器与数组
  • 寻址公式与随机访问特性
  • 定义(3点)
  • 低效的插入与删除
  • 越界问题
  • 不同编程语言中的数组实现方式
    • 方面:一维/二维数组,一维/二维结构体数组的实现方式
    • c / c + + c/c++ c/c++
    • j a v a java java(二维,结构体,特殊)
    • J a v a S c r i p t JavaScript JavaScript的数组(特殊)( A r r a y B u f f e r ArrayBuffer ArrayBuffer 数组与标准数组相同)
  • 和并有序数组(归并排序)
  • 思考: c / c + + c/c++ c/c++ j a v a java java数组实现的优缺点(连续、空间、内存要求)
链表
  • L R U LRU LRU缓存淘汰算法

  • 底层存储结构

  • 定义与操作

    • 查找、插入、删除(前驱结点,指定结点,值等于给定值)
  • 利用哨兵化简代码

    • 有头结点:便于第一个结点的插入、删除

      head = new Node;
      head->next= nullptr;//not head=nullptr
      
    • 线性搜索中的标记,将待搜索元素放在最后,可减少一次比较( i < n i<n i<n)

  • 用于实现栈:可以将头结点作为栈顶,降低时间复杂度

  • 循环链表,双向链表,双向循环链表

  • 缓存

  • 链表与数组性能对比

  • 指针丢失与内存泄漏

  • 指针或引用赋值的含义

  • 留意边界条件与特殊情况能否正常工作

    • 空链表
    • 一个/两个结点
    • 特殊结点:头尾
  • swap(node1, node2)理解为交换名字,

  • 练习题

    • 回文字符串
    • 单链表反转
    • 链表中环的检测(快慢指针)
    • 两个有序链表的和并(类似归并排序)
    • 删除链表倒数第 K K K个结点
    • 寻找链表的中间结点(快慢指针)
    • 双向循环链表(基本完成:11_210824.cpp)
    /*单链表*/
    
    /*头结点*/
    	head = new Node;
    	head->next= nullptr;//not head=nullptr
     
     
    /*delete*/
    	while (head) {
        	Node* p=head;
        	head=head->next;
        	delete p;
    	}
    	
    /*链表反转(无头结点)*/
    Node* Reverse(Node* head) {
            Node* pre=nullptr;
            Node* cur=head;//有头结点 cur = head->next,head->next=nullptr;
            while(cur) {
                Node* nex=cur->next;
                cur->next=pre;
                pre=cur;
                cur=nex;
            }			//有头结点 head->next = pre, return head;
            return pre;
        }
    /*简洁版(无头结点)*/
        Node *p;
        for (p = nullptr; head; swap(head, p))
            swap(p, head->next);
        return p;
    /*有头结点*/
        Node *p;
        Node* cur = head->next;
        for (p = nullptr; cur; swap(cur, p))
            swap(p, cur->next);
        head->next = p;
        return head;
    
    /*使用构造函数添加结点*/
    	Node *head = new Node(INT_MAX, nullptr);
        Node *p = head;
        for (int i = 0; i < 5; i++)
        {
            //关键
            p->next = new Node(i, nullptr);
            p = p->next;
        }
    /*递归版*/
    Node *ReverseList(Node *head)
        {
            if (!head || !head->next)
                return head;
            Node *newHead = ReverseList(head->next);
            head->next->next = head; //head is 这次函数传入的head,再没有操作之前,实际图为 head->newHead<-next<....
            head->next = nullptr;
            return newHead; //newHead is 上一次返回的head
        }
    /*判断循环链表:快慢指针*/
        bool Circle(Node *head)
        {
            if (!head || !head->next)
                return false;
            Node *slow = head;
            Node *fast = head->next;
            while (slow != fast)
            {
                if (fast == nullptr || fast->next == nullptr)
                    return false;
                slow = slow->next;
                fast = fast->next->next;
            }
            return true;
        }
    /*和并有序链表*/
    Node *MergeTwoLists(Node *list_1, Node *list_2)
        {
            Node *preHead = new ListNode; //哨兵
            Node *p = preHead;
            while (list_1 && list_2)
            {
                if (list_1->val > list_2->val)
                {
                    p->next = list_2;
                    list_2 = list_2->next;
                }
                else
                {
                    p->next = list_1;
                    list_1 = list_1->next;
                }
                p = p->next;
            }
            p->next = list_1 ? list_1 : list_2;
            LitNode *tmp = preHead;
            preHead = preHead->next;//head
            delete tmp;//注意清理之前动态申请的
            return preHead;
        }
    /*获取中间结点*/
        Node *middleNode(Node *head)
        {
    		//不知道是否会造成内存泄漏
            //        vector<Node*> A = {head};
            //        while (A.back()->next != nullptr)
            //            A.push_back(A.back()->next);
            //        return A[A.size() / 2];
    
            int len = GetLength(head);
            ListNode *p = head;
            for (int i = 0; i < len / 2; i++)
            {
                p = p->next;
            }
            return p;
        }
    /*快慢指针*/
        Node *middleNode(Node *head)
        {
            Node *slow = head;
            Node *fast = head;
            while (fast && fast->next) //need fast->next, avoid assess nullptr
            {
                slow = slow->next;
                fast = fast->next->next;
            }
            return slow;
        }
    /*删除倒数第n个结点*/
    Node *RemoveNodeFromEnd(Node *head, int n)
        {
            static int cur = 0; //对于需要用来计数的变量,如果不是static 每次递归返回都是cur=0;
        //走至链表尾部
            if (!head)
                return nullptr;
        //接下来,递归一直走到链表尾部
            head->next = RemoveNodeFromEnd(head->next, n);
        //递归开始返回,cur为倒数第几个结点
            cur++;
             if (n == cur)
            {
                ListNode *p = head;
                head = head->next;
                delete p;
                return head;
                // return head->next;
            }
                //return head->next;//仅这样会内存泄漏
            return head;
        }
    
        int GetLength(Node *head)
        {
            int length = 0;
            Node *p = head;
            while (p)
            {
                length++;
                p = p->next;
            }
            return length;
        }
    
        Node *RemoveNodeFromEnd(Node *head, int n)
        {
            int length = GetLength(head); //存在问题 如果length=n,对于头节点特别对待
            Node *p = head;
            if (length == n)
            {
                head = head->next;
                delete p;
                return head;
            }
            for (int i = 0; i < length - n - 1; i++) //length-n-1 is preNode
            {
                p = p->next;
            }
            Node *q = p->next;
            p->next = q->next;
            delete q;
            return head;
        }
    
        Node *RemoveNodeFromEnd(Node *head, int n)
        {
            int length = GetLength(head);
            ListNode *guard = new ListNode(0, head);
            ListNode *pre = guard;
            for (int i = 0; i < length - n; i++) //length-n is preNode
            {
                pre = pre->next;
            }
            Node *q = pre->next;
            pre->next = q->next;
            delete q;
            Node *result = guard->next; //head may be changed/deleted , cant return head
            delete guard;
            return result;
        }
    
        Node *RemoveNodeFromEnd(ListNode *head, int n)
        {
            Node *guard = new ListNode(0, head);
            ListNode *p = guard;
            stack<ListNode *> list;
            while (p)
            {
                list.push(p);
                p = p->next;
            }
            for (int i = 0; i < n; i++)
            {
                list.pop();
            }
            p = list.top();
            Node *q = p->next;
            p->next = q->next;
            delete q;
            q = guard;
            guard = guard->next;
            delete q;
            return guard;
        }
    
        Node *RemoveNodeFromEnd(Node *head, int n)
        {
            Node *guard = new ListNode(0, head);
            Node *fast = guard;
            Node *slow = guard;
            for (int i = 0; i < n + 1; i++) //need add 1,slow为前驱结点
            {
                fast = fast->next;
            }
            while (fast)
            {
                fast = fast->next;
                slow = slow->next;
            }
            Node *p = slow->next;
            slow->next = p->next;
            delete p;
            p = guard;
            guard = guard->next;
            return guard;
        }
        Node *RemoveNodeFromEnd(Node *head, int n)
      {
          Node *guard = new ListNode(0, head);
          Node *fast = guard;
          Node *slow = guard;
          for (int i = 0; i < n + 1; i++) //need add 1,slow为前驱结点
          {
              fast = fast->next;
          }
          while (fast)
          {
              fast = fast->next;
              slow = slow->next;
          }
          Node *p = slow->next;
          slow->next = p->next;
          delete p;
          p = guard;
          guard = guard->next;
          return guard;
      }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值