C++ 数据结构 —— 链表

题目:

PAT-A 1074 Reversing Linked List

PAT-A 1032 Sharing

PAT-A 1052 Linked List Sorting

PAT-A 1097 Deduplication on a Linked List


1. 链表的定义

struct node{
	typename data; //数据域
	node* next;	   //指针域
};

2. 使用malloc函数或new运算符为链表节点分配空间

2.1 malloc函数

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

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

        int* p1 = (int*)malloc(sizeof(int));
	node* p2 = (node*)malloc(sizeof(node));

malloc申请一块大小为sizeof(node)空间,并且返回指向这块空间的指针,但是此时这个指针是一个未确定类型的指针void*,因此需要把他强转为node*型,然后赋给p2

2.2 new运算符

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

typename* p = new typename;

        int* p1 = new int;
	node* p2 = new node;

如果申请失败,则会启动C++异常机制处理而不是返回空指针NULL

2.3 内存泄漏

free()函数是对应的malloc函数的    free(p);

delete()函数是对应new运算符的    delete(p);

C/C++设计者认为程序员完全有能力自己控制内存的分配和释放,因此把对内存的控制操作全部交给了程序员。切记在使用完malloc和new开辟出来的空间后必须将其释放,否则会造成内存泄漏

3. 链表的基本操作

3.1 创建链表

#include <iostream>
using namespace std;

struct node{
	int data; //数据域
	node* next;	   //指针域
};

//创建链表(关键函数)
	node* create(int Array[]){
		node *p,*pre,*head; //pre保存当前节点的前驱节点,head为头结点
		head = new node; //创建头结点
		head->next = NULL; 	//头结点不需要数据域,指针域初始为NULL
		pre = head;	//记录pre为head
		for(int i=0;i<5;i++){
			p = new node; //新建节点
			//将Array[i]赋给新建的结点作为数据域,也可以scanf输入
			p->data = Array[i];
			p->next = NULL;	//新结点的指针域设为NULL
			pre->next = p;	//前驱结点的指针域设为当前新建节点的地址
			pre = p;			//把pre设为p,作为下个节点的前驱结点
		}
		return head;
	}

int main() {
	int Array[5] = {5,3,6,1,2};
	node* L = create(Array);	//新建链表,返回的头指针head赋给L
	L = L->next;	//从第一个结点开始有数据域
	while(L != NULL){
		printf("%d ",L->data);
		L=L->next;
	}
	return 0;
}

3.2 查找元素

    int search(node* head,int x){
		//在以head为头结点的链表上计数元素x的个数
		int count = 0;
		node* p = head->next; 
		while(p!=NULL){
			if(p->data == x){
				count++;
			}
			p = p->next;
		}
		return count;
	}

3.3 插入元素

	void insert(node* head,int pos,int x){
		node* p = head;
		for(int i=0;i<pos-1;i++){
			p = p->next;		//pos-1是为了到插入位置的前一个结点
		}
		node* q = new node;	//新建结点
		q->data = x;			//新结点的数据域为x
		q->next = p->next;	//新节点的下一个结点指向原先插入位置的结点
		p->next = q;			//前一个位置的结点指向新节点
	}

3.4 删除元素

	//删除以head为头结点的链表中所有数据域为x的结点
	void del(node* head,int x){
		node* p = head->next;	//p从第一个结点开始枚举
		node* pre = head;	//pre始终保存p的前驱结点指针
		while(p != NULL){
			if(p->data == x){	//数据域恰好为x,说明要删除该结点
				pre->next = p->next;
				delete(p);
				p = p->next;
			}else{	//数据域不是x,把pre和p都后移一位
				pre = p;
				p=p->next;
			}
		}
	}

4. 静态链表

    前面讲解的都是动态链表,即需要指针简历结点之间的连接关系。而对有些问题来说,结点的地址是比较小的整数,这样就没有必要去简历动态链表,而应使用方便的多的静态链表

    静态链表的实现原理是Hash,即通过建立一个结构体数组,并令数组的下标直接表示结点的地址,来达到直接访问数组中的元素就能访问结点的效果。另外,由于结点的访问非常方便,因此静态链表是不需要头结点的。

//静态链表
	struct Node{
		typename data;
		int next;
	}node[1000];
next是一个int型的整数,用以存放下一个结点的地址,事实上就是数组下标。注意,在使用静态链表时,尽量不要把结构体类型名和结构体变量名取成相同的名字,因为由于静态链表是由数组实现的,那么就有可能需要对其进行排序,如果两个名字相同,sort函数就会报编译出错


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猪突猛进!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值