目录
❀顺序表
❀初始化
❀插入
❀删除
❀查找
❀链表
❀求表长
❀查找
❀插入
❀删除
❀逆置
线性表
- 线性表是n个数据元素的有限序列:(a1,a2,a3……an)。
- 表中有且只有一个开始节点;有且仅有一个终端节点。除开始节点外,每个节点都有一个前驱节点;出最后一个节点外,每个节点都有一个后继节点。
- 线性表具有以下三个特点:
1.同一性。有同一种数据类型的元素组成,每一个元素都是相同的数据类型。
2.有穷性。线性表由有限个数据元素组成,表程度就是表中数据元素的个数。
3.有序性。线性表相邻元素之间存在线性关系。- 线性表的运算
1.InitList(L)。线性表的初始化,构建一个空的线性表。
2.ListLength(L)。求线性表的长度,返回线性表中数据元素的个数。
3.GetElem(L,i,x)。用x返回线性表中第i个数据元素的值。
4.LocationElem(L,x)。按值查找,确定元素x在L中的位置。
5.ListInsert(L,i,x)。插入操作,在L中第i个位置之前插入x,L的长度加1.
6.ListDelete(L,i)。删除操作。删除L中第i个元素,L的长度减1。
7.ListEmpty(L)。判断L是否为空列表。空返回TRUE,非空返回FALSE。
8.ClearList(L)。将已知的线性表L置为空表。
9.DestoryList(L)。销毁线性表L。
线性表的线性存储
1.顺序表
顺序表的存储结构描述
#define MAXSIZE <线性表的最大长度>
tepedef struct
{
EleType else[MAXSIZE];
int length; //线性表长度
}Seqlist;
//为了使线性表中数据元素的位序保持一致,不使用下标为0的单元
顺序表的基本运算
1.初始化
void Init_SeqList(SeqList* L)
{
L->length = 0;
}
2.插入
操作步骤:
①将an~ai按照从后向前依次向下移动,将新元素插入空出的第i个位置
②修改表长
int Insert_SeqList(SeqList *L,int i,ElemType x)
{
int j;
if(L->length == MAXSIZE-1)//检验表空间是否已满
{
printf("表满");
return OVERFLOW;
}
if(i<1 || i>L->length+1)//检验插入位置是否正确
{
printf("位置错");
return ERROR;
}
for( j=L->length;j>=i;j++)
{
L->elem[i+1] = L->elem[i];
}
L->elem[i] = x;
L->length++;//修改表长
return TRUE;//插入成功,返回结果
}
3.删除
操作步骤:
①将a(i+1)~an依次向上移动
②将线性表的长度减1
int Delete_SeqList(SeqList* L,int i,ElemType* e)
{
int j;
if(i<1 || i>L->length)//检验空表删除位置的合法性
{
printf("不存在第i个元素");
reutrn ERROR;
}
*e = L->elem[i];//将删除的第i个元素存储
for(j=i;j<L->length;j++)
{
L->elem[i] = L->elem[i+1];
}
L->length--;//线性表的长度减1
return TRUE;//删除成功
}
4.查找
操作步骤
①从线性表的第一个元素a1依次向后查找元素和x作比较,直至找到后返回位置,如果查找到L->length、还没有找到x,则返回FALSE。
int Location_SeqList(Seqlist* L,ElemType x)
{
int i=1;
while(i<=L->length && i->elem[i]!= x)
{
i++;
}
if(i>L->length)
{
return FALSE;//查找失败
}
return i;//返回元素x的位置
}
2.链表
单链表的描述
1.链表是通过一组任意位置的存储单元来存储线性表中的数据元素,对于每个元素ai,除了存储本身的信息外,还必须包含直接后继元素信息的位置。
2.链表中的每个节点都包含两个域:数据域、指针域。
3.头结点、头指针:为了操作方便,在单链表的第一个节点之前添加一个附加节点,称为“头结点”。头结点的数据域可以存储标题、标称信息等,也可以不存储任何信息,其指针域存储链表的第一个节点的首地址,头结点由指针变量指向。由于最后一个节点没有后继节点,因此最后一个节点的指针域为空(NULL)。
单链表的定义
typedef struct node
{
DateType date;//数据域
struct node* next;//指针域
}Lnode;*LinkList;
单链表的基本运算
1.建立单链表
①头插法建立单链表
头插法建立单链表是指在链表的头部插入节点建立单链表,实现方法如下:
①申请一个头节点,并将头节点的指针域置为空。
②依次读入数据元素,如果不是结束标志-1,则继续申请节点。
③将新节点插入链表的头节点之后,将接下来的节点插入到最后一个节点之前。数据读入顺序与逻辑表中的元素顺序正好相反。
LinkList Creat_LinkList1() { LinkList H = (LinkList)malloc(sizeof(LNode)); //创建头节点 H->next = NULL; LNode *s; int x; scanf("%d",&x); while(x!=-1) { s = (LinlList)malloc(sizeof(LNode)); s->date = x; s->next = H->next; H->next = s; scanf(%d",&x); } return H; }
②尾插法建立单链表
①尾插法建立单链表是指在单链表的尾部插入节点,所以新增一个指针来指向链表中的尾节点,方便新节点插入链表的尾部。
②数据读入顺序和逻辑表中的顺序一致。
//尾插法建立单链表 LinkList Creat_LinkList2() { LinkList H = (LinkList)malloc(sizeof(LNode));//创建头节点 H->next = NULL; LNode *s,*r = H; int x; scanf("%d",&x); while(x!=-1) { s = (LinkList)malloc(sizeof(LNode)); s->date = x; r->next = s; r = s; scanf("%d",&x); } r->next = NULL;//尾节点 return H; }
2.求表长
操作步骤:
①设置一个指针p和计数器count,初始化p指向头节点H,count为0.
②若p节点还有后继节点,则p向后移动,计数器+1.(线性表的长度不包含头节点)。
③直到p-next == NULL为止,返回计数器,即为链表的长度
int Length_LinkList(LinkList) { LNode* p = H;//使指针p指向头节点,统计的链表长度不包含头节点 int count = 0; while(p->next!=NULL) { p = p->next; count++; } return count; }
3.查找
①按序号查找
Get_LinkList(H,k)
操作步骤:从链表的第一个节电起判断当前节点是否为第k个,若是返回,否则继续查找,直到结束返回空。
LinkList Get_LinkList(L,k) { LNode* p = H; int count = 0; while(p->next!=NULL && count<k) { count++; p = p->next; } if(count == k) { return p; } return NULL;//链表中没有第k个节点 }
②按值查找
操作步骤:从第一个元素节点起,判断当前值是否为x,若是返回该节点的指针,否二继续向后查找,直到表结束返回空。
LNode* Locate(LinkList H,DateType x) { LinkList p = H; while(p->next != NULL && p->date != x) { p = p->next; } return p; }
4.插入
①说明:p为待插入节点前面的节点,s指向待插入的节点,将s指向的节点插入到p指向节点的后边。
操作步骤:
s->next = p->next; p->next = s;
②说明:p为待插入节点后面的节点,s指向待插入的节点,将s指向的节点插入到p指向节点的前面。
操作步骤:找到p指向节点的前驱指针q,将s指向的节点插入到q指向的节点的后边。
q = H; while(q->next != p) { q = q->next; } s->next = q->next; q->next = s;
总结:将新节点s插入到第i个节点的位置上,实现步骤如下:
- 查找第i-1个节点,若存在继续,否则返回空。
- 创建新节点
- 新节点的指针域指向第原本位置上的第i个节点。
- 第i-1个节点的指针域指向新节点
int Insert_LinkList(LinkList H,int i,DateType x) { Lnode *p,*s; p = Get_LinkList(H,i-1);//查找第i-1个节点 if(!p)//如果没有找到底i-1个节点 { return NULL; } else { s = (LinkList)malloc(sizeof(LNode));//申请新节点 s->date = x; s->next = p->next;//新节点插入第i-1个节点后 p->next = s; return TRUE;//插入成功 } }
5.删除
删除链表中的第i个节点,操作步骤:
①找到第i-1和第i个节点,若存在继续,否则返回空。
②-1节点的指针域指向i+1节点。
③释放第i个节点的空间。
int Del_LinkList(LinkList H,int i) { LinkList p,q; p = Get_ListList(H,i-1); if(p==NULL) { printf("第i-1个节点不存在"); return ERROR; } else if(p->next = NULL) { printf("第i个节点不存在"); returnERROR; } else { q = p->next;//q是待插入节点 p->next = q } }
6.逆置
依次取原链表中的每个节点,将其作为第一个节点插入新链表中,指针p指向当前节点,p为空时结束。
void Reverse(LinkList H) { Lnode *p,*q; p = H->next; H->next = NULL;//将尾节点置为空 while(p) { q = p; p = p->next; q->next = H->next;//头插法建立单链表 H->next = q; } }
7.单链表中删除重复节点
实现步骤:用指针p指向第一个节点,从它的直接后继开始找与其值相同的节点删除,p指向下一个节点,p指向最后一个节点时结束。
void pur_LinkList(LinkList H) { Lnode *p,*q,*r; p =H->next; if(!p) { while(p->next) { q = p; while(q->next) { if(q->next->date == p->date) { r = q->next;//使指针r指向待删除的节点 q->next = r->next; free(r); } else { q = q->next; } } p = p->next;//将指针p向后移动,继续从其直接后继节点查找重复节点删除 } } }
8.求两个单链表集合的差集
实现步骤:假设单链表A用LA表示,单链表B用LB表示,求A-B的差值:对于LA链表中的每个元素,在链表LB中查找,若存在与额相同的元素,则从LA中将其删除。
void Difference(LinikList LA,LinkList LB) { Lnode *p,*q,*r,*pre; pre = LA; p = LA->next;//p指向表中的某一节点,pre始终指向p的前驱 while(!p) { q = LB->next; while(q != NULL && q->date != p->date) { q = q->next; } if(q!=NULL) { r = p; pre->next = r->next; p = p->next; free(r); } else { pre = p; p = p->next; } } }
循环链表
在单链表的的基础上,将其最后一个节点的指针域指向该链表头节点,使链表头尾相连构成单循环链表。实际中多采用尾指针rear表示单循环链表。
1.将HB连接到HA构成单循环链表。
实现步骤:
①查找HA的尾节点,将HA尾结点的指针域置为HB的开始节点。
②释放HB的头结点,将HB的尾结点的指针域置为HA的头结点。
p = rearA -> next; //保存HA的头结点 rearA -> next = rearB->next->next; //将HA尾结点的指针域改为HB的开始节点 free(rearB -> next); //释放HB链表的头结 rearB -> next = p; //将HB的尾结点的指针域指向HA的头结点
双向链表
一个节点拥有两个指针,分别指向该节点的前驱结点和后继节点,头节点的前驱结点为尾结点,尾结点的后继节点为头结点。
定义方法:
typedef struct dlnode { DateType date; struct dlnode *prior,*next; };
1.双链表中插入节点
设p指向某节点,s指向待插入到p节点前的新节点。
实现步骤:
①将s节点的piror指针修改为p的piror指针值。
②将p前驱指针的next指针修改为s指针指向的节点。
③将p的piror指针修改为s指针值。
④将s的next指针修改为p指针值。
图示:
/* p指向某节点 s指向待插入到p节点前面的节点 */ s->prior= p->piror; p->prior->next = s; s->next = p; p->prior = s;
2.双链表中删除节点
设p指向待删除的节点。
实现步骤:
①将p指针前驱结点的next指针置为p指针指向节点的next指针值。
②将p指针后继节点的prior指针置为p指针指向节点的prior指针值。
③释放p指针指向节点的空间。
图示:
p->prior->next = p->next; p->next->prior = p->prior; free(p);