第七章 数据结构专题
7.3 链表处理
7.3.1 链表的概念
不连续存储。
结点=数据域+结点域。
struct Node{
typename data; //数据域
Node* next; //指针域
};
链表分类
头结点head
:数据域不放任何东西,指针域指向第一个数据域有内容的结点。
根据链表有没有头结点可以分为带头结点的链表和不带头结点的链表。
7.3.2 malloc函数或new运算符为链表节点分配内存空间
1. malloc函数
头文件:#include <stdlib.h>
typename * p=(typename*)malloc(sizeof(typename)); //返回指向开辟空间的指针。申请失败返回空指针NULL。
int* p=(int*)malloc(sizeof(int));
node* p=(node*)malloc(sizeof(node));
2. new运算符
typename* p=new typename;
int* p=new int;
node* p=new node;
3. 内存泄漏
free函数
头文件:#include <stdlib.h>
释放指针变量p
指向的内存空间,将指针变量p
指向空地址NULL
。
free(p);
delete运算符
释放指针变量p
指向的内存空间,将指针变量p
指向空地址NULL
。
delete(p);
7.3.3 链表的基本操作
1. 创建链表
#include <cstdio>
#include <cstdlib>
struct node{
int data;
node* next;
};
node* create(int array[])
{
node *p,*pre,*head;
head=new node;
head->next=NULL; //头结点不需要数据域
pre=head;
for(int i=0;i<5;i++)
{
p=new node;
p->data=array[i]; //当前指针
p->next=NULL;
pre->next=p; //前一个指针->next=当前指针
pre=p;
}
return head;
}
int main()
{
int array[5]={5,2,3,6,1};
node* L=create(array);
L=L->next; //第一个结点开始(非头结点)
while(L!=NULL)
{
printf("%d",L->data);
L=L->next;
}
return 0;
}
2. 查找元素个数
从第一个结点开始顺序遍历,查找元素。
int search(node*head,int x)
{
int cnt=0;
node* p=head->next; //从第一个结点开始
while(p!=NULL)
{
if(p->data==x)
cnt++;
p=p->next;
}
return cnt;
}
3. 插入元素
在给定位置插入一个结点。
void insert(node* head,int pos,int x)
{
node* p=head;
for(int i=0;i<pos-1;i++) //插入的前一个结点
{
p=p->next;
}
node* q=new node;
q->data=x;
q->next=p->next; //先更新新节点的next
p->next=q; //再更新前一个结点的next
}
4. 删除元素
删除链表上所有值为x的结点。
结点p枚举结点,结点pre记录了当前结点的前一个结点。
void del(node* head,int x)
{
node* p=head->next;
node* pre=head;
while(p!=NULL)
{
if(p->data==x)
{
pre->next=p->next;
deletr(p);
p=pre->next;
}
else
{
pre=p;
p=p->next;
}
}
}
7.3.4 静态链表
实现原理
hash。
建立结构体数组,令数组下标直接表示结点的地址,达到直接访问数组中的元素就能访问结点的效果。不需要头结点。
struct Node{
typename data; //数据域
int next; //指针域
}node[size];
例题
【例】1097 Deduplication on a Linked List (25 分)
remove v.删除
Deduplication n.重复数据删除
absolute value 绝对值
duplicated a.重复的
ATTENTION
- 注意绝对值相等就要remove。
修改前:
//duplicated
#include <cstdio>
#include <vector>
#include <cmath>
#include <cstdlib>
using namespace std;
bool key[10010]={0};
vector<int> ans,rem;
struct Node{
int adr;
int key;
int next;
int nextIdx;
Node()
{
next=-1;nextIdx=-1;
}
}node[100010];
int main()
{
int start=-1,startIdx=-1,n;
scanf("%d %d",&start,&n);
for(int i=0;i<n;i++)
{
int adr,key,next;
scanf("%d %d %d",&adr,&key,&next);
node[i].adr=adr;
node[i].key=key;
node[i].next=next;
if(adr==start)
startIdx=i;
}
int cur=startIdx;
while(node[cur].next!=-1)
{
for(int i=0;i<n;i++)
{
if(node[i].adr==node[cur].next)
{
node[cur].nextIdx=i;
cur=i;
}
}
}
cur=startIdx;
int p=-1,q=-1;
while(cur!=-1)
{
if(key[abs(node[cur].key)]==0)
{
ans.push_back(cur);
key[abs(node[cur].key)]=1;
if(p!=-1)
node[p].next=node[cur].adr;
p=cur;
}
else
{
rem.push_back(cur);
if(q!=-1)
node[q].next=node[cur].adr;
q=cur;
}
cur=node[cur].nextIdx;
}
if(ans.size()>0) //这地方不判断会指向非法内存
node[ans[ans.size()-1]].next=-1;
if(rem.size()>0) //这地方不判断会指向非法内存
node[rem[rem.size()-1]].next=-1;
for(int i=0;i<ans.size();i++)
{
if(node[ans[i]].next==-1)
printf("%05d %d %d\n",node[ans[i]].adr,node[ans[i]].key,node[ans[i]].next);
else
printf("%05d %d %05d\n",node[ans[i]].adr,node[ans[i]].key,node[ans[i]].next);
}
for(int i=0;i<rem.size();i++)
{
if(node[rem[i]].next==-1)
printf("%05d %d %d\n",node[rem[i]].adr,node[rem[i]].key,node[rem[i]].next);
else
printf("%05d %d %05d\n",node[rem[i]].adr,node[rem[i]].key,node[rem[i]].next);
}
return 0;
}
修改后: