【链表】专辑

题目考点分值难度
19冬 2-Block Reversing25
19秋 2-Merging Linked Lists25
A1032 Sharing 25
A1052 Linked List Sorting 25
A1074 Reversing Linked List25
A1097 Duplication on a Linked List 25

1.链表的概念

结点的定义

// 结点的定义
sturct node {
    typename data;    // 数据域
    node* next;    // 指针域
};

《算法笔记》中统一为 带头结点的写法。
带头结点的链表:头结点称为 head,数据域data不存放内容,指针域next 指向第一个数据域有内容的结点(第一个结点)

示例:

2.为 链表结点 分配内存空间

1.malloc函数

malloc 是C语言中 stdlib.h 头文件下用于申请动态内存的函数,其 返回类型 申请的同变量类型的指针

typename* p = (typename*)malloc(sizeof(typename));

示例

int* p = (int*)malloc(sizeof(int));
node* p = (node*)malloc(sizeof(node));

含义:malloc函数向内存申请一块大小为 sizeof(int) 的空间,并且 返回 指向这块空间的指针,因此时这个指针是一个未确定类型的指针 void*,因此需要强制转换为 int* 类型的指针。
若申请失败,则返回空指针 null。

2.new运算符

new 是C++中用来申请动态空间的运算符,返回类型同样是申请的同变量类型的指针。

typename* p = new typename;

示例

int* p = new int;
node* p = new node;

3.内存泄露

指使用 malloc 与 new 开辟出来的内存空间在使用过后没有释放,导致其在程序结束之前时钟占据该内存空间。

(1) free函数

对应 malloc函数。只需在 free的参数中填写需要释放的内存空间的指针变量即可。

free(p);

实现效果:①释放指针变量p所指向的内存空间;②将指针变量p指向空地址NULL。

(2) delete运算符

对应 new运算符。

delete(p);

3.链表的基本操作

1.创建链表

①创建头结点,并指向null;

②pre 指向 当前结点;

③循环:新建结点 p,赋值数据域data,指针域设为null,尾插到链表中(pre->next = p),前驱结点指向当前结点 为了下一次插入。

④返回头结点。

图示:

代码:

#include <stdio.h>
#include <stdlib.h>

// 结点定义
struct node {
	int data;    // 数据域
	node* next;  // 指针域
};

// 创建链表
node* create(int a[]) {
	node *pre, *p, *head;
	head = new node;    // 创建头结点
	head->next = NULL;
	pre = head;   // 指向头结点,便于尾插
	for (int i = 0; i < 5; i++) {
		p = new node;    // 创建结点p
		p->data = a[i];  // 数据域
		p->next = NULL;  // 指针域
		pre->next = p;   // 插入到链表中
		pre = p;         // 指针右移
	}
	return head;    // 返回头结点
}

int main() {
	int a[5] = { 3, 1, 4, 5, 2 };
	node* L = create(a);   // 返回头结点
	L = L->next;    // 指针指向第一个有数据域的结点
	while (L) {     // 若当前结点不为空
		printf("%d ", L->data);
		L = L->next;
	}
	return 0;
}

2.查找元素

①新建结点指向头结点的下一个结点;

②while循环,依次访问当前结点的数据域,若==x,cnt++;

③访问完当前结点之后,指针指向下一个结点。

int search(node* head, int x) {
	int cnt = 0;
	node *p = head->next;
	while (p) {
		if (p->data == x)
			cnt++;
		p = p->next;
	}
	return cnt;
}

3.插入元素

①定义指针p指向头结点head;

②指针p后移到待插入结点的前一个结点;

③新建结点q,数据域为待插入值,指针域指向上一个结点的下一个结点;

④上一个结点p指针指向这个结点q。

图示:

代码:

void insert(node* head, int pos, int x){
    node* p = head;
    // 找到插入位置的前一个结点,并用 指针p指向
    for(int i = 0; i < pos-1; i++){
        p = p->next;
    }
    // 新建结点,并用 指针q指向
    node* q = new node;
    q->data = x;
    q->next = p->next;
    p->next = q;
}

4.删除元素

①设置一个前驱结点pre指向头结点,设置一个当前节点p指向头结点的下一个结点;

②只要当前结点p不为null,就往后遍历;

③如果当前结点p->data == x,让前驱结点pre直接指向当前结点的后一个结点p->next,删除当前结点;

④如果当前结点不等于x,往后遍历。

void del(node* head, int x){
    node* pre = head;
    node* p = head->next;
    while(p != NULL){
        if(p->data == x){
            pre->next = p->next;
            delete(p);
            p = pre->next;
        }
        else{
            pre = p;
            p = p->next;
        }
    }
}

Leetcode总结的删除操作

 

代码:

ListNode* removeElements(ListNode* head, int val) {
    // 建立虚拟头结点
    ListNode* dummy = new ListNode(0, head);
    // 遍历用指针
    ListNode* cur = dummy;
    // 遍历链表
    while(cur->next != nullptr){
        if(cur->next->val == val){  // 删除链表结点
            ListNode* tmp = cur->next;
            cur->next = cur->next->next;
            delete tmp;
        }else{
            cur = cur->next;
        }
    }
    // 返回头结点
    return dummy->next;
}

静态链表的通用解题步骤

①定义静态链表

struct Node{
    int address; // 当前结点的地址
    int data; // 数据域
    int next; // 指针域,指向下一个结点的地址
    XXX; // 结点的某个性质,不同的题目有不同的设置,详见例题
}node[100010];

②初始化

对XXX初始化,定义为正常情况下达不到的数字

for(int i = 0; i < maxn; i++){
    node[i].XXX = 0;
}

③遍历整条链表

int p = begin, count = 0;
while(p != -1){
    XXX = 1;
    count++;
    p = node[p]->next;    
}

④对数组进行排序以把有效结点移到数组左端,这样就可以用步骤3得到的count来访问它们。

bool cmp(Node a, Node b){
    if(a.XXX == -1 || b.XXX == -1){
        return a.XXX > b.XXX;
    }else{
        // 第二级排序
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值