嘤嘤嘤当初数据结构没学好,只能现在来补啦
链表(linked-list):链表就是线性表的链式存储方式。链表的内存是不连续的,前一个元素存储地址的下一个地址中存储的不一定是下一个元素。链表通过一个指向下一个元素地址的引用将链表中的元素串起来。
单向链表
单向链表就如图所示
1 2 3 4
| head为头指针 head->val=data1; head->next=data2的指针域 head->next->val=data2
|
操作
创建链表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| typedef struct node { int val; struct node* next; }Node;
Node* CreateNode(int val) { Node* newnode=(Node*)malloc(sizeof(Node)); if(newnode==NULL) { cout<<"out of memory"<<endl; return NULL; } else { newnode->val=val; newnode->next=NULL; return newnode; } }
|
插入
插入有两种插入方法,一种是头插法,一个是尾插法
头插法
让头指针指向新结点,始终让新结点处于第一位
1 2 3 4 5 6
| void Insert(Node* head,int val) { Node* p=CreateNode(val); p->next = head->next; head->next=p; }
|
尾插法
新的结点插在尾结点的后面(所以需要定义一个尾结点)
1 2 3 4 5 6
| void Insert(Node* tail,int val) { Node* p=CreateNode(val); tail->next=p; tail=p->next; }
|
删除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| void Delete(Node *head,int val) { if(head->next==NULL) { cout<<"empty list"<<endl; return; } Node* cur=head->next,*pre=head; while(cur) { if(cur->val==val) break; else { cur->next; pre->next; } pre->next=cur->next; free(cur); } }
|
反转
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Node* Reverse(Node* head) { if(head==NULL) return head; else{ Node* cur=head,*pre=NULL,*next=NULL,*pR=NULL; while(cur!=NULL) { next=cur->next; if(next==NULL) pR=cur; cur->next=pre; pre=cur; cur=next; } return pR; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Node* Reverse(Node* head) { if(head==NULL||head->next==NULL) return head; else { Node* pR=Reverse(head->next); head->next->next=head; head->next=NULL; } return pR; }
|
例子
题目描述:
解题思路:主要的思想就是将链表分为三段(om,mn,n结尾),将mn段反转,再将这三段连起来。但我遇到的问题是,这三段我连不起来,之后我发现需要再建一个链表。然后我就发现我反转有问题,后来参考其他人的,才发现我对链表指针相互的赋值有问题,我会直接用val来代替这个节点,但实际上每个节点指针存放了val和下一个节点的地址。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Solution { public: ListNode* reverseBetween(ListNode* head, int m, int n) { if(m==n) return head; else{ ListNode res(0); res.next=head; ListNode* pre=&res; for(int i=1;i<m;i++) pre=pre->next; ListNode *cur=pre->next,*next=NULL; for(int i=m;i<n;i++) { next = cur->next; cur->next = next->next; next->next = pre->next; pre->next = next; } return res.next; } } };
|
双向链表
与单向链表不同,双向链表不仅储存指向下一个节点的指针,也指向上一个节点的指针。双向链表可以快速找到前驱结点,但会增加大量的指针存储空间
操作
创建链表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| typedef struct node { int val; struct node* pre; struct node* next; }Node;
Node* CtreateNode(int val) { Node* newnode=(Node*)malloc(sizeof(Node)); if(newnode==NULL) { cout<<"out of memory"<<endl; return NULL; } else { newnode->val=val; newnode->pre=NULL; newnode->next=NULL; return newnode; } }
|
插入
插入的方法和单向链表的插入类似
1 2 3 4 5 6 7
| void Insert(Node* head,int val) { Node* newnode=CreateNode(val); newnode->next=head->next; head->next>pre=newnode; head->next=newnode; }
|
删除
由于双向链表中每个节点记录了它的前驱结点,所以不需要像单向链表中一样索引目的节点的前驱节点,而是可以通过目标节点直接获得。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| Node* Find(int val) { for(Node* tmp=head;tmp!=NULL;tmp=tmp->next) { if(tmp->val==val) return tmp; } return NULL; } void Detele(Node* head,int val) { Node* p=Find(val); if(p==NULL) { cout<<"Can't Find"<<endl; return; } p->pre->next=p->next; p->next->pre=p->pre; free(p); }
|