线性表

顺序线性表

 

线性表的抽象数据类型

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;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值