链表基本操作
创建链表
- 头节点只有next 数据域无内容,一开始赋值给pre
- 有一个pre,用来连接新生成的节点
- 用new生成新节点
- 每次循环更新当前节点为pre节点
#include<vector>
#include<iostream>
using namespace std;
struct node {
int data;
node* next;
};
//创建链表
node* create(vector<int> &arr) {
node *p, *pre, *head;//当前结点/前驱结点/头结点
head = new node;//创建头节点
head->next = NULL;//头节点不需要数据域,指针初始化为NULL
pre = head;
for (int i = 0; i < arr.size(); i++) {
p = new node;
p->data = arr[i];
p->next = NULL;
pre->next = p;
pre = p;
}
return head;
}
int main() {
vector<int> arr;
arr.push_back(5);
arr.push_back(3);
arr.push_back(6);
node* L = create(arr);
node*p = L->next;
while (p) {
printf("%d", p->data);
p = p->next;
}
return 0;
}
遍历链表
- 从头节点的下一个节点开始遍历
- 分析每个节点的内容、记录
- 更新当前节点
- 退出条件是当前节点为NULL
int search(node*head, int x) {
node* p = head->next;
int cnt = 0;
while (p) {
if (p->data == x) {
cnt++;
}
p = p->next;
}
return cnt;
}
插入节点
- 特别注意要找的是插入的位置的前一个节点
- 不知道链表的前一个节点就无法进行增删操作
void insert(node* head, int pos, int x) {
node* p = head;
for (int i = 0; i < pos - 1; i++) {
p = p->next;//找到插入位置的前一个节点
}
node*newNode = new node;//新建节点
newNode->data = x;
newNode->next = p->next;
p->next = newNode;
}
删除节点
- 设前置节点
- 找到的情况释放内存,记得要重新指定p的指向为pre->next
void del(node* head, int x) {
node *p = head->next;
node* pre = head;
while (p) {
if (p->data == x) {
pre->next = p->next;
delete(p);
p = pre->next;
}
else {
pre = p;
p = p->next;
}
}
}
题目
反转链表
- 俩指针 p q。p在q前。
- 每次把q的next指向p
- 把pq向后移动一位
- 每次最开始要保存qnext
ListNode* reverseList(ListNode* head) {
ListNode*p=NULL,*q=head;
while(q){
ListNode*t=q->next;
q->next=p;
p=q;
q=t;
}
return p;
}
奇偶链表
把一个链表的全部奇数项排在全部偶数项前面
- 四个四个一处理,分链表元素奇数个和偶数个两种情况讨论。
ListNode* oddEvenList(ListNode* head) {
if(head==NULL) return NULL;
if(head->next==NULL) return head;
ListNode*p1=head;
ListNode*p2=head->next;
ListNode*t=p2;//存放偶数开头
while(p1 && p2 && p1->next && p2->next){
p1->next=p2->next;
p2->next=p1->next->next;
p1=p1->next;
p2=p2->next;
}
p1->next=t;
return head;
}
回文链表判断
- 找到中间链表(奇偶情况讨论)
- 反转前半部分链表
- 同时遍历前半部分和后半部分链表,比较是否相同
bool isPalindrome(ListNode* head) {
if (head == NULL)return false;
if (head->next == NULL)return true;
int cnt = 0;
ListNode*p=head, *q;
while (p) {
cnt++;
p = p->next;//cnt为元素个数
}
int midIndex = cnt / 2;//中间元素(从1开始计树)的前一个
ListNode*midP = head;
for (int i = 1; i <= midIndex - 1; i++) {
midP = midP->next;//奇数个的话指向中间元素前一个,偶数个的话指向靠左的那个
}
ListNode*p1, *p2;//最后用于遍历的指针
if (cnt % 2 == 0) {//根据情况指定从左往右遍历的指针
p2 = midP->next;
}
else {
p2 = midP->next->next;
}
p = NULL;
q = head;
for (int i = 1; i <= midIndex; i++) {//反转
ListNode*t = q->next;
q->next = p;
p = q;
q = t;
}
//指定从右往左遍历的指针
p1 = p;
//比较
bool flag = true;
while (p1 && p2) {
if (p1->val != p2->val) flag = false;
p1 = p1->next;
p2 = p2->next;
}
return flag;
}