顺序线性表
线性表的抽象数据类型
InitList(*L):初始化操作,建立一个空的线性表L
ListEmpty(L):判断线性表是否为空表,若为空表,则返回true,否则返回false
ClearList(*L):将线性表清空
GetElem(L,i,*e):将线性表L中的第i个位置元素值返回给e
LocateElem(L,e):在线性表L中查找与给定值e相等的元素,如果查找成功,返回该元素在表中序号表示成功;否则,返回0表示失败
ListInsert(*L,i,e):在线性表L中第i个位置插入新元素e
ListDelete(*L,i,*e):删除线性表L中的第i个元素,并用e返回其值
ListLength(L):返回线性表L中的元素个数
集合的并集
void unionL(List *La,List Lb)//La表示A的集合,Lb表示B的集合,求并集
{
int La_len,Lb_len,i;
ElemType e;
La_len=ListLength(*La);
Lb-len=ListLength(Lb);
for(i=1;i<=Lb_len;i++)
{
GetElem(Lb,i,&e);
if(!LocateElem(*La,e))
{
ListInsert(La,++La_len,e);//++La_len表示La_len的值先增1,然后再传递给函数
}
}
}
得到一个值
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef int Status;
//Status 是函数的类型,其值是函数结果状态代码,如ok 等
//初始条件,顺序线性表L已存在,1<=i<=ListLength(L)
//操作结果,用e返回L中第i个数据元素的值
Status GetElem(SqList L,int i,ElemType *e)
{
if(L.length==0||i<1||i>L.length)
{
return ERROR;
}
*e=L.data[i-1];
return OK;
}
插入
Status ListInsert(SeqList *L,int i,ElemType e)
{
int k;
if(L->length==MAXSIZE)//顺序线性表已经满
{
return ERROR;
}
if(i<1||i>L->length+1)
{
return ERROR;
}
if(i<=L->length)//若插入数据位置不在表尾
{
//将要插入位置数据元素向后移一位
for(k=L->length-1;k>=i-1;k--)
{
L->data[k+1]=l->data[k];
}
}
L->data[i-1]=e;//将新元素插入,在第i个位置插入,即数组的i-1
L->length++;
return OK;
}
删除
//删除L的第i个数据元素,并用e返回其值,L的长度-1
Status ListDelete(SeqList *L,int i,ElemType *e)
{
int k;
if(L->length==0)
{
return ERROR;
}
if(i<1||i>L->length)
{
return ERROR;
}
*e=L->data[i-1];
if(i<=L->length)
{
for(k=i;k<=L->length;k++)
{
L->data[k-1]=L->data[k];
}
}
L->length--;
return OK;
}
单链表
typedef struct Node
{
ElemType data;//数据域
struct Node* next;//指针域
}Node;
typedef struct Node* LinkList;//相当于LinkList=Node*
单链表得到一个值
Status GetElem(LinkList L,int i,ELemType *e)//用e返回L中第i个数据元素的值
{
int j;
LinkList p;
p=p->next;
j=1;
while(p&&j<i)//当p不为空,且j<i
{
p=p->next;
++j;
}
if(!p||j>i)//这种情况代表查找失败:第一:当p为空退出循环,!p代表真;第二:j>i
{
return ERROR;
}
*e=p->data;
return OK;
}
单链表插入
typedef struct Node
{
ElemType data;
struct Node *next;
}Node;
typedef struct Node* LinkList;
//在L中第i个位置之前插入新的数据元素e,L的长度+1
Status ListInsert(LinkList *L,int i,ElemType e)
{
int j;
LinkList p,s;
p=*L;
j=1;
while(p&&j<i)
{
p=p->next;
++j;
}
if(!p||j>i)
{
return ERROR;
}
s=(LinkList)malloc(sizeof(Node));
s->next=p->next;
p->next=s;
return OK;
}
单链表删除
//删除L的第i个数据元素,并用e返回其值,L的长度-1
Status ListDelete(Linklist *L,int i,ElemType *e)
{
int j;
LinkList p,q;
p=*L;
j=1;
while(p->next&&j<i)
{
p=p->next;
++j;
}
if(!(p->next)||j>i)
{
return ERROR;
}
q=p->next;
p->next=q->next;
*e=q->data;
free(q);
return OK;
}
头插法建立单链表
void CreatListHead(LinkList *L,int n)//头插法建立单链表
{
LinkList p;
int i;
srand(time(0));//初始化随机数种子
*L=(LinkList)malloc(sizeof(Node));
(*L)->next=NULL;
for(i=0;i<n;i++)
{
p=(LinkList)malloc(sizeof(Node));//生成新节点
p->data=rand()%100+1;//%100产生0~99,+1则为1~100
p->next=(*L)->next;
(*L)->next=p;
}
}
尾插法建立单链表
void CreatListTail(LinkList *L,int n)//尾插法建立单链表
{
LinkList p,r;
int i;
srand(time(0));
*L=(LinkList)malloc(sizeof(Node));
r=*L;
for(i=0;i<n;i++)
{
p=(Node*)malloc(sizeof(Node));
p->data=rand()%100+1;
r->next=p;
r=p;//画画图就懂了
}
r->next=NULL;
}
单链表的整表删除
Status ClearList(LinkList *L)
{
LinkList p,q;
p=(*L)->next;
while(p)
{
q=p->next;
free(p);
p=q;
}
(*L)->next=NULL;
return OK;
}
单链表逆转
刚开始的时候,链表就是头结点,重要
typedef struct Node *PtrToNode;
struct Node {
ElementType Data; /* 存储结点数据 */
PtrToNode Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */
List Reverse(List L)
{
List p,q;
p=L;
L=NULL;
while(p)
{
q=p;
p=p->Next;
q->Next=L;
L=q;
}
return L;
}
若线性表需要频繁查找,很少进行插入和删除操作时,宜采用顺序存储结构
若需要频繁插入和删除时,宜采用单链表结构
静态链表
1、数组的第一个元素,即下标为0的那个元素的cur(游标)就存放备用链表的第一个结点的下标
2、数组的最后一个元素,即下标为MAXSIZE-1的cur(游标)则存放第一个有数值的元素的下标,相当于单链表的头结点的作用
3、有数据的最后一个对应的游标应该为0
静态链表存储结构
#define MAXSIZE 1000
typedef struct
{
ElemType data;//数据
int cur;//游标cursor
}Component,SraticLinkList[MAXSIZE};
静态链表的插入操作
//对静态链表进行初始化相当于初始化数组
Status InitList(StaticLinkList space)
{
int i;
for(i=0;i<MAXSIZE-1;i++)
space[i].cur=i+1;
space[MAXSIZE-1].cur=0;
return OK;
}
int Malloc_SLL(StaticLinkList space)//获得空闲分量的下标
{
int i=space[0].cur;
if(space[0].cur)
space[0].cur=space[i].cur;
//把i的下一个分量用来作为备用,结合图就比较好理解了
return i;
}
//正式插入操作,第i个元素之前插入
Status ListInsert(StaticLinkList L,int i,ElemType e)
{
int j,k l;
k=MAX_SIZE-1;//数组的最后一个元素,该题为999
if(i<1||i>ListLength(L)+1)
{
return ERROR;
}
j=Malloc_SLL(L);
if(j)
{
L[j].data=e;
for(l=1;l<=i-1;l++)
{
k=L[k].cur;//L[k].cur=1
}
L[j].cur=L[k].cur;//看图即可理解,该节视频在第10节
L[k].cur=j;
return OK;
}
return ERROR;
}
静态链表的删除
//删除在L中的第i个数据元素
Status ListDelete(StaticLinkList L,int i)
{
int j,k;
if(i<1||i>ListLength(L))
{
return ERROR;
}
k=MAX_SIZE-1;
for(j=1;j<=i-1;j++)
{
k=L[k].cur;
}
j=L[k].cur;
L[k].cur=L[j].cur;
Free_SLL(L,j);
return OK;
}
void Free_SLL(StaticLinkList space,int k)
//将下标为k的空闲结点回收到备用链表
{
space[k].cur=space[0].cur;space[0].cur=k;}//返回L中的数据个数int ListLength(StaticLinkList L){int j=0;int i=L[MAXSIZE-1].cur;while(i){i=L[i].cur;j++;}return j;}
找到静态链表的中间值
Status GetMidNode(LinkList L,ElemType *e)
{
LinkList search,mid;
mid=search=L;
while(search->next!=NULL)
{
//search移动的速度是mid的2倍
if(search->next->next!=NULL)
{
search=search->next->next;
mid=mid->next;
}
else
{
search=search->next;
}
}
*e=mid->data;
return OK;
}
循环链表
1.并不是说循环链表一定要有头结点
2.循环链表与单链表的差别在于判别空链表的条件上:单链表判断head->next是否为null,循环链表判断head->next是否等于head.
typedef struct CLinkList//链表存储结构的定义
{
int data;
struct CLinkList *next;
}node;
初始化循环链表
void ds_init(node **pNode)//初始化循环链表
{
int item;
node *temp;
node *target;
printf("输入结点的 值,输入0完成初始化\n");
while(1)
{
scanf("%d",&item);
fflush(stdin);
if(item==0)
return ;
if((*pNode)==NULL)//循环链表中只有一个结点
{
*pNode=(node*)malloc(sizeof(struct CLinkList));
if(!(*pNode))
exit(0);
(*pNode)->data=item;
(*pNode)->next=*pNode;
}
else
{
//找到next指向第一个结点的结点
for(target=(*pNode);target->next!=(*pNode);target=target->next);
//生成一个新的结点
temp=(node*)malloc(sizeof(struct CLinkList));
if(!temp)
exit(0);
temp->data=item;
temp->next=*pNode;
target->next=temp;
}
}
循环链表插入结点
//参数:链表的第一个结点,插入的位置
void ds_insert(node **pNode,int i)
{
node *temp;
node *target;
node *p;
int item;
int j=1;
printf("输入要插入的结点的值:");
scanf("%d",&item);
if(i==1)
{
//新插入的结点作为第一个结点
temp=(node *)malloc(sizeof(struct CLinkList));
if(!temp)
exit(0);
temp->data=item;
//寻找最后一个结点
for(target=(*pNode);target->next!=(*pNode);target=target->next);
temp->next=(*pNode);
target->next=temp;
*pNode=temp;
}
else
{
target=*pNode;
for(;j<i-1;++j)
{
target=target->next;
}
temp=(*node)malloc(sizeof(struct CLinkList));
if(!temp)
exit(0);
temp->data=item;
p=target->next;
target->next=temp;
temp->next=p;
}
}
循环链表删除结点
void ds_delete(node **pNode,int i)//删除结点
{
node *target;
node *temp;
int j=1;
if(i==1)//删除的是第一个结点
{
//找到最后一个结点
for(target=*pNode;target->next!=*pNode;target=target->next);
temp=*pNode;
*pNode=(*pNode)->next ;
target->next=*pNode;
free(temp);
}
else
{
target=*pNode;
for(;j<i-1;j++)
{
target=target->next;
}
temp=target->next;
target->next=temp->next;
free(temp);
}
}
循环链表返回结点所在位置
int ds_search(node *pNode,int elem)//返回结点所在位置
{
node *target;
int i=1;
for(target=pNode;target->data!=elem&&target->next!=pNode;++i)
{
target=target->next;
}
if(target->next=pNode)//表中不存在该元素
return 0;
else
return i;
}
用循环链表实现约瑟夫问题
//n个人围圈报数,报m出列,最后剩下的是几号?
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int data;
struct node *next;
}node;
node *create(int n)
{
node *p=NULL,*head;
head=(node*)malloc(sizeof(node));
p=head;
node *s;
int i=1;
if(0!=n)
{
while(i<=n)//注意这每循环一次就新产生一个s,结合画图就比较好理解了
{
s=(node *)malloc(sizeof(node));
s->data=i++;//为循环链表初始化,第一个结点为1,第二个结点为2
p->next=s;
p=s;
}
s->next=head->next;//表示指向第一个结点
}
free(head);
return s->next ;
}
int main()
{
int n=41;
int m=3;
int i;
node *p=create(n);
node *temp;
m=n%m;//m在这里等于2
while(p!=p->next )
{
for(i=1;i<=m-1;i++)
{
p=p->next;
}
printf("%d->",p->next->data);
temp=p->next;//删除第m个结点
p->next=temp->next;
free(temp);
p=p->next;
}
printf("%d\n",p->data);
return 0;
}
判断单链表中是否有环
1.使用p,q两个指针,P总是往前走,但q每次都从头开始走,对于每个结点,看p走的步数是否和q一样。如图,当p从6走到3时,用了6步,此时q从head出发,则只需两步就到3,因而步数不等,出现矛盾,存在环
2.使用p,q两个指针,P每次向前走一步,q每次向前走两步,若存在某个时候p==q,则存在环
1比较步数的方法
int HasLoop1(LinkList L)//比较步数的方法
{
LinkList cur1=L;//定义结点cur1
int posl=0;//curl的步数
while(cur1)//cur1结点存在
{
LinkList cur2=L;//定义结点cur2
int pos2=0;//cur2的步数
while(cur2)//cur2结点不为空
{
if(cur2==cur1)
{
if(pos1==pos2)
break;//走过的步数一样,说明没有环
else
{
printf("环的位置在第%d个结点处,\n\n",pos2);
return 1;//有环并退出
}
}
cur2=cur2->next;
pos2++;
}
cur1=cur1->next;
pos1++;
}
return 0;
}
2利用快慢指针的方法
int HasLoop2(LinkList L)//利用快慢指针的方法
{
int step1=1;
int step2=2;
LinkList p=L;
LinkList q=L;
while(p!=NULL&&q!=NULL&&q->next!=NULL)
{
p=p->next;
if(q->next!=NULL)
q=q->next->next;
printf("p:%d,q:%d\n",p->data,q->data);
if(p==q)
return 1;
}
return 0;
}
魔术师发牌问题
//魔术师发牌问题
#include<stdio.h>
#include<stdlib.h>
#define CardNumber 13
typedef struct node
{
int data;
struct node *next;
}seqList,*linklist;
linklist CreateLinkList()
{
linklist head =NULL;
linklist s,r;
int i;
r=head;
for(i=1;i<=CardNumber;i++)
{
s=(linklist)malloc(sizeof(seqList));
s->data=0;
if(head==NULL)
head=s;
else
r->next=s;
r=s;
}
r->next=head;
return head;
}
//发牌顺序计算
void Magician(linklist head)
{
linklist p;
int j;
int CountNumber=2;
p=head;
p->data=1;//第一张牌放1
while(1)
{
for(j=0;j<CountNumber;j++)
{
p=p->next;
if(p->data!=0)
{
p->next;
j--;
}
}
if(p->data==0)
{
p->data=CountNumber;
CountNumber++;
if(CountNumber==14)
break;
}
}
}
//销毁工作
void DestoryList(linklist *list)
{
linklist ptr=*list;
linklist buff[CardNumber];
int i=0;
while(i<CardNumber)
{
buff[i++]=ptr;
ptr=ptr->next;
}
for(i=0;i<CardNumber;++i)
free(buff[i]);
*list=0;
}
int main()
{
linklist p;
int i;
p=CreateLinkList();
Magician(p);
printf("按如下顺序排列:\n");
for(i=0;i<CardNumber;i++)
{
printf("黑桃%d ",p->data);
p=p->next;
}
DestoryList(&p);
return 0;
}
双向链表结点结构
typedef struct DualNode
{
ElemType data;
struct DualNode *prior;
struct DualNode *next;
}DualNode,*DuLinkList;
双向链表插入
s->next=p;
s->prior=p->prior;
p->prior->next=s;
p->prior=s;
双向链表的删除
p->prior->next=p->next;
p->next->prior=p->prior;
free(p);
双向链表的应用之26字母
#include <stdio.h>
#include <stdlib.h>
#define ok 1
#define ERROR 0
typedef char ElemType ;
typedef int Status;
typedef struct DualNode
{
ElemType data;
struct DualNode *prior;
struct DualNode *next;
}DualNode,*DuLinkList;
Status InitList(DuLinkList *L)
{
DualNode *p,*q;
int i;
*L=(DuLinkList)malloc(sizeof(DualNode));
if(!(*L))
{
return ERROR;
}
(*L)->next=(*L)->prior=NULL;
p=(*L);
for(i=0;i<26;i++)
{
q=(DualNode *)malloc(sizeof(DualNode));
if(!q)
{
return ERROR;
}
q->data='A'+i;
q->prior=p;
q->next=p->next;
p->next=q;
p=q;
}
p->next=(*L)->next;
(*L)->next->prior=p;
return ok;
}
void Caesar(DuLinkList *L,int i)
{
if(i>0)
{
do
{
(*L)=(*L)->next;
}while(--i);
}
if(i<0)
{
do
{
(*L)=(*L)->next;
}while(++i);
}
}
int main()
{
DuLinkList L;
int i,n;
InitList(&L);
printf("请输入一个整数:");
scanf("%d",&n);
printf("\n");
Caesar(&L,n);
for(i=0;i<26;i++)
{
L=L->next;
printf("%c",L->data);
}
printf("\n");
return 0;
}