链表通过自引用结构体类型的指针成员指向结构体本身建立起来,“自引用结构体”包含一个指针成员,该指针指向与结构体一样的类型。
struct node
{
int data;//整形成员
struct node *next;//指针成员
};
自引用结构体单元称为节点,jie'结点之间通过箭头连接qi'l起来,构成一个表,成为链表。
链表中zhi'指向第一个节点的指针chen成为头指针,tong通过头指针,可以访问链表的每一个结点。
链表的最后一个节点的指针部分用空(NULL)表示。
为了方便,在链表的第一个结点之前增加一个结点,称为tou'头结点。
不带头节点的指针 head ->[a ]->[b ]->[c ]->[d ^]
带头节点de'z的指针 head->[ ]->[a ]->[b ]->[c ]->[d ^]
单链表的存储结构
typedef struct Node
{
DataType data;
struct Node *next;
} ListNode,*LinkList;
其中,ListNode是lian链表的结点类型,LinkList 是指向链表节点的指针类型
定义LinkList L;定义了一个链表,L指向该链表的第一个结点,对于不带头结点的链表来说,如果链表为空,则有L=NULL;
对于带头结点的链表,如果链表为空,则L->next=NULL;
单链表上的基本运算
1.单链表的初始化
void InitList(LinkList *head)
//将单链表初始化为空,动态生成一个头节点,并将头结点的指针域置为空。
{
if((*head=(LinkList)malloc(sizeof(ListNode)))==NULL)//为头节点分配一个存储空间。
exit(-1);
(*head)->next=NULL;//将单链表的头结点的指针域置为空
}
2.判断单链表是否为空,
int ListEmpty(LinkList head)
//判断单链表是否为空,通过判断头结点的指针域是否为空
{
if(head->next==NULL)//判断单链表头结点的指针域是否为空。
return 1;
else
return 0;
}
3.按序号查找操作
///按序号查找操作;从头指针head出发,利用节点的next 域,扫描链表的结点。
ListNode* Get(LinkList head,int i)
{
ListNode *p;
int j;
if(ListEmpty(head)) return NULL;
if(i<1) return NULL;
j=0;
p=head;
while(p->next!=NULL&&j<i)
{
p=p->next;
j++;
}
if(j==i) return p;
else return NULL;
}
4.///按内容查找操作
///按内容查找操作
ListNode* LocateElem(LinkList head,DataType e)
{
ListNode *p;
p=head->next;
while(p)
{
if(p->data !=e)
p=p->next;
else
break;
}
return p;
}
5。定位操作
int LocatePos(LinkList head,DataType e)
{
ListNode *p;
int i;
if(ListEmpty(head)) return 0;
p=head->next;///p指向第一个节点
i=1;
while(p)
{
if(p->data==e) return i;
else
{
p=p->next;
i++;
}
}
if(!p) ///没有找到与e相等的元素,表示失败,返回0;
return 0;
}
6.cha'插入操作
///插入操作,在单链表的第i个位置插入一个节点,节点元素的值为e,插入成功返回1,插入失败返回0;
int InsertList(LinkList head,int i,DataType e)
{
ListNode *p,*pre;
///定义指向第i个元素的前驱结点指针pre,指针p指向新生成的结点
int j;
pre=head;
j=0;
while(pre->next!=NULL&&j<i-1)
{
pre=pre->next;
j++;
}
if(j!=i-1)
{
printf("插入位置错误");
return 0;
}
//x新生成一个结点,并将 E赋值给该i节点的数据域
if((p=(ListNode*)malloc(sizeof(ListNode)))==NULL)
exit(-1);
///插入节点操作;
p->data=e;
p->next=pre->next;
pre->next=p;
return 1;
}
7.删除操作
int DeleteList(LinkList head,int i,DataType *e)
{
ListNode *pre,*p;
int j;
pre=head;
j=0;
while(pre->next!=NULL&&pre->next->next!=NULL && j<i-1)
{
pre=pre->next;
j++;
}
if(j!=i-1)
{
printf("删除位置错误");
return 0;
}
///删除操作
///指针p指向单链表中的第i个结点,并将该节点的数据域值赋值给E
p=pre->next;
*e=p->data;
pre->next=p->next;
free(p);
return 1;
}
8.求表长
///求表长操作
int ListLength(LinkList head)
{
ListNode *p;
int count = 0;
p=head;
while(p->next!=NULL)
{
p=p->next;
count++;
}
return count;
}
9.销毁链表
///销毁链表操作
void DestroyList (LinkList head)
{
ListNode *p,*q;
p=head;
while(p!=NULL)
{
q=p;
p=p->next;
free(q);
}
}
应用举例:单链表应用举例:实现如果单链表A中出现的元素在单链表B中也出现,则将A中该元素删除。
///l单链表应用举例:
#include <iostream>
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef int DataType;
typedef struct Node
{
DataType data;
struct Node *next;
} ListNode,*LinkList;
//单链表上的基本运算
void InitList(LinkList *head)
//将单链表初始化为空,动态生成一个头节点,并将头结点的指针域置为空。
{
if((*head=(LinkList)malloc(sizeof(ListNode)))==NULL)//为头节点分配一个存储空间。
exit(-1);
(*head)->next=NULL;//将单链表的头结点的指针域置为空
}
int ListEmpty(LinkList head)
//判断单链表是否为空,通过判断头结点的指针域是否为空
{
if(head->next==NULL)//判断单链表头结点的指针域是否为空。
return 1;
else
return 0;
}
///按序号查找操作;从头指针head出发,利用节点的next 域,扫描链表的结点。
ListNode* Get(LinkList head,int i)
{
ListNode *p;
int j;
if(ListEmpty(head)) return NULL;
if(i<1) return NULL;
j=0;
p=head;
while(p->next!=NULL&&j<i)
{
p=p->next;
j++;
}
if(j==i) return p;
else return NULL;
}
///按内容查找操作
ListNode* LocateElem(LinkList head,DataType e)
{
ListNode *p;
p=head->next;
while(p)
{
if(p->data !=e)
p=p->next;
else
break;
}
return p;
}
int LocatePos(LinkList head,DataType e)
{
ListNode *p;
int i;
if(ListEmpty(head)) return 0;
p=head->next;///p指向第一个节点
i=1;
while(p)
{
if(p->data==e) return i;
else
{
p=p->next;
i++;
}
}
if(!p) ///没有找到与e相等的元素,表示失败,返回0;
return 0;
}
///插入操作,在单链表的第i个位置插入一个节点,节点元素的值为e,插入成功返回1,插入失败返回0;
int InsertList(LinkList head,int i,DataType e)
{
ListNode *p,*pre;
///定义指向第i个元素的前驱结点指针pre,指针p指向新生成的结点
int j;
pre=head;
j=0;
while(pre->next!=NULL&&j<i-1)
{
pre=pre->next;
j++;
}
if(j!=i-1)
{
printf("插入位置错误");
return 0;
}
//x新生成一个结点,并将 E赋值给该i节点的数据域
if((p=(ListNode*)malloc(sizeof(ListNode)))==NULL)
exit(-1);
///插入节点操作;
p->data=e;
p->next=pre->next;
pre->next=p;
return 1;
}
int DeleteList(LinkList head,int i,DataType *e)
{
ListNode *pre,*p;
int j;
pre=head;
j=0;
while(pre->next!=NULL&&pre->next->next!=NULL && j<i-1)
{
pre=pre->next;
j++;
}
if(j!=i-1)
{
printf("删除位置错误");
return 0;
}
///删除操作
///指针p指向单链表中的第i个结点,并将该节点的数据域值赋值给E
p=pre->next;
*e=p->data;
pre->next=p->next;
free(p);
return 1;
}
///求表长操作
int ListLength(LinkList head)
{
ListNode *p;
int count = 0;
p=head;
while(p->next!=NULL)
{
p=p->next;
count++;
}
return count;
}
///销毁链表操作
void DestroyList (LinkList head)
{
ListNode *p,*q;
p=head;
while(p!=NULL)
{
q=p;
p=p->next;
free(q);
}
}
void DelElem(LinkList *A ,LinkList B)//解决问题的函数
{
int i,pos;
DataType e;
ListNode *p;
for(i=1;i<=ListLength(B);i++)
{
p=Get(B,i);
if(p)
{
pos=LocatePos(*A,p->data);
if(pos>0) DeleteList(*A,pos,&e);
}
}
}
using namespace std;
int main()
{
int i;
DataType a[]={6,7,9,14,37,45,65,67};
DataType b[]={3,7,11,34,45,89};
LinkList A,B,C;
ListNode *p;
InitList(&A);
InitList(&B);
InitList(&C);
for(i=1;i<=sizeof(a)/sizeof(a[0]);i++)
{
if(InsertList(A,i,a[i-1])==0)
{
printf("位置不合法");
return 0 ;
}
}
for(i=1;i<=sizeof(b)/sizeof(b[0]);i++)
{
if(InsertList(B,i,b[i-1])==0)
{
printf("位置不合法");
return 0;
}
}
printf("A中的元素有%d个\n",ListLength(A));
for(i=1;i<=ListLength(A);i++)
{
p=Get(A,i);
if(p)
printf("%4d",p->data);
}
printf("\n");
printf("单链表B中的元素有 %d个:\n",ListLength(B));
for(i=1;i<=ListLength(B);i++)
{
p=Get(B,i);
if(p)
printf("%4d",p->data);
}
printf("\n");
DelElem(&A,B);
printf("将在A中出现B的元素删除后,现在A 中的元素还有%d个:\n",ListLength(A));
for(i=1;i<=ListLength(A);i++)
{
p=Get(A,i);
if(p)
printf("%4d",p->data);
}
return 0;
}