数据结构与算法之——线性表的链式存储结构

LinkedList.h

/* 线性表的链式存储结构 */
typedef int ElemType ;      //ElemType类型根据实际情况而定,这里假设为int
typedef struct Node
{
    ElemType data;  
    struct Node * next;
/* 线性表的链式存储结构 */
/* 线性表的链式存储结构 */
/* 线性表的链式存储结构 */
/* 线性表的链式存储结构 */
/* 线性表的链式存储结构 */
typedef int ElemType ;      //ElemType类型根据实际情况而定,这里假设为int
typedef struct Node
{
    ElemType data;
    struct Node * next;
}Node,*LinkedList;

#define OK 1
#define ERROR 0
typedef int Status;
/* 线性表通用操作  */
Status InitList(LinkedList *L);     //建立一个空的线性表L
Status ListEmpty(LinkedList L);     //若线性表为空返回true,否则返回false
Status ClearList(LinkedList *L);    //将线性表清空
Status GetElem(LinkedList L,int i,ElemType *e);     //将线性表L中第i个位置元素值返回给e
int LocateElem(LinkedList L,ElemType e);    //在线性表L中查找与给定值e相等的元素,如果查找>成功,返回该元素在表中序号表示成功;否则,返回0表示失败。
Status ListInsert(LinkedList *L,int i,ElemType e);      //在线性表L中的第i个位置插入新元素e
Status ListDelete(LinkedList *L,int i,ElemType *e);     //删除线性表L中第i个位置元素,并用e返回值值
int ListLength(LinkedList L);   //返回线性表L的元素个数

LinkedList.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "LinkedList.h"

int main(void)
{
	LinkedList L;
	InitList(&L);

	if(ListEmpty(L))
	{
		printf("是空的\n");
		ListInsert(&L,0,3);
		ListInsert(&L,1,13);
		ListInsert(&L,2,23);
		ListInsert(&L,2,33);
		ListInsert(&L,4,43);
		ListInsert(&L,5,53);
		ListInsert(&L,6,63);
		ListInsert(&L,7,73);
		ListInsert(&L,8,83);
		ListInsert(&L,9,93);
		ListInsert(&L,10,103);
		ListInsert(&L,11,113);
		ListInsert(&L,12,123);
	}
	printf("遍历所有元素:\n");
	int len = ListLength(L);
	LinkedList h;int j=0;
	h = L;
	while(h->next)
	{
		h = h->next;
		printf("[%d]%d,",j,h->data);
		j++;
	}
	printf("\n长度为%d\n",len);
	ElemType e;
	GetElem(L,2,&e);
	printf("索引2位置的元素是:%d\n",e);
	printf("查找53的索引位置是:%d\n",LocateElem(L,53));

	printf("删除第6位后\n");
	ElemType ee;
	ListDelete(&L,6,&ee);	
	len = ListLength(L);
	j = 0;
	h = L;
	while(h->next)
	{
		h = h->next;
		printf("[%d]%d,",j,h->data);
		j++;
	}

	printf("\n");


	return 0;
}

//建立一个空的线性表L
Status InitList(LinkedList *L)				
{
	*L = (LinkedList)malloc(sizeof(LinkedList));
	(*L)->next = NULL;
	(*L)->data = 0;
	return OK;		
}
//若线性表为空返回true,否则返回false
Status ListEmpty(LinkedList L)				
{
	return L->next == NULL;		
}
//将线性表清空
Status ClearList(LinkedList *L)			
{
	LinkedList p = (*L)->next,q;
	while(p)
	{
		q = p->next;
		free(p);
		p = q;
	}
	(*L)->next = NULL;	//头结点的指针域置空
	(*L)->data = 0;		//头结点的数据域表示长度变为0
	return OK;		
}
//将线性表L中第i个位置元素值返回给e
Status GetElem(LinkedList L,int i,ElemType *e)			
{
	int j=0;
	LinkedList p = L->next;//第一个结点
	while(p && j<i)
	{
		p = p->next;
		j++;
	}
	if(!p || j>i)
	{
		printf("第%d个结点不存在\n",i);
		return ERROR;
	}
	*e = p->data;
	return OK;		
}
//在线性表L中查找与给定值e相等的元素,如果查找成功,返回该元素在表中序号表示成功;否则,返回0表示失败。
int LocateElem(LinkedList L,ElemType e)			
{
	int j =0;
	LinkedList p = L->next;
	while(p)
	{
		if(p->data == e)
		{
			return j;
		}
		p = p->next;
		j++;
	}
	return ERROR;		
}
//在线性表L中的第i个位置插入新元素e
Status ListInsert(LinkedList *L,int i,ElemType e)		
{	
	int j=0;
	LinkedList p,s;		//s为新建的结点的指针
	p = *L;				//p指向表头结点
	while(p && j<i)
	{
		p = p->next;	//往后找
		j++;
	}
	if(!p || j>i)
	{
		printf("第%d个结点不存在!\n",i);
		return ERROR;
	}
	s = (LinkedList )malloc(sizeof(Node));
	s->data = e;
	s->next = p->next;
	p->next = s;
	(*L)->data ++;
	return OK;		
}
//删除线性表L中第i个位置元素,并用e返回值值
Status ListDelete(LinkedList *L,int i,ElemType *e)		
{
	LinkedList p = (*L)->next,q;
	int j = 0;
	while(p && j<i-1)
	{
		p = p->next;
		j++;
	}
	if(!(p->next) || j>i)
	{
		printf("第%d个结点不存在\n",i);
		return ERROR;
	}
	q = p->next;
	p->next = q->next;
	*e = q->data;
	free(q);
	return OK;		
}
//返回线性表L的元素个数
int ListLength(LinkedList L)			
{
	return L->data;		
}


总结:

线性表的查找、插入与删除时间复杂度都为O(n)

如果在不知道第i个元素的指针位置,单链表数据结构在插入和删除操作上,与线性表的顺序存储结构没有太大优势。但如果希望从第i个位置,插入10个元素,对于顺序存储结构意味着,每一次插入都需要移动n-1个元素,每次都是O(n)。则单链表只需在第一次时,找个第i个指针,此时为O(n),接下来只是简单地通过赋值移动指针而已,时间复杂度都是O(1)。显然对于插入或删除数据越频繁的操作,单链表的效率优势就越明显

单链表的整表创建与删除

LinkedList2.c

/* 单链表的整表创建与删除 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "LinkedList.h"

/* 随机产生n个元素的值,建立带头结点的单链表L(头插法) */
Status CreateListHead(LinkedList *L,int n);

/* 随机产生n个元素的值,建立带头结点的单链表L(尾插法) */
Status CreateListTail(LinkedList *L,int n);

void printList(LinkedList L);

/* 初始条件:链表已存在,操作结果:将L重置为空表 */
Status ClearList(LinkedList *L);

int main(void)
{
	LinkedList L;
	printf("头插法创建单链表:\n");
	CreateListHead(&L,10);
	printList(L);
	printf("清空后:\n");
	ClearList(&L);
	printList(L);
	
	printf("尾插法创建单链表:\n");
	CreateListTail(&L,10);
	printList(L);
	printf("清空后:\n");
	ClearList(&L);
	printList(L);

	return 0;
}

/* 随机产生n个元素的值,建立带头结点的单链表L(头插法) */
Status CreateListHead(LinkedList *L,int n)
{
	LinkedList p;
	int i;
	srand(time(0));		//初始化随机种子数
	*L = (LinkedList)malloc(sizeof(Node));
	(*L)->next = NULL;	//建立一个带头结点的单链表
	for(i=0;i<n;i++)
	{
		p = (LinkedList)malloc(sizeof(Node));	//生成新结点
		p->data = rand()%100+1;
		p->next = (*L)->next;
		(*L)->next = p;				//插入到表头
	
	}
	return OK;
}

/* 随机产生n个元素的值,建立带头结点的单链表L(尾插法) */
Status CreateListTail(LinkedList *L,int n)
{
	LinkedList p,r;
	int i;
	srand(time(0));		//初始化随机种子数
	*L = (LinkedList)malloc(sizeof(Node));
	(*L)->next = NULL;	//建立一个带头结点的单链表
	r = (*L);			//r指向尾部的结点
	for(i=0;i<n;i++)
	{
		p = (LinkedList)malloc(sizeof(Node));	//生成新结点
		p->data = rand()%100+1;
		r->next = p;							//插入到尾部
		r = p;									//重新指向尾部
	}
	r->next = NULL;								//表示当前链表结束
	return OK;
}

void printList(LinkedList L)
{
	LinkedList p = L->next;
	while(p)
	{
		printf("%d,",p->data);
		p = p->next;
	}
	printf("\n");
}



/* 初始条件:链表已存在,操作结果:将L重置为空表 */
Status ClearList(LinkedList *L)
{
	LinkedList p = (*L)->next,q;	//定义一个指向头结点的指针
	while(p)
	{
		q = p->next;				//找到下一个结点
		free(q);					//释放该结点
		p = q;						//指向下一下结点
	}
	(*L)->next = NULL;				//头结点指向为空
	return OK;
}

链式存储结构与顺序存储结构的优缺点

存储分配方式

时间性能

空间性能

·顺序存储结构用一段连续的存储单元依次存储线性表的数据元素

·单链表采用链式存储结构,用一组任意的存储单元存放线性表的无数

·查找

         ·顺序存储结构O(1)

         ·单链表O(n)

·插入和删除

·顺序存储结构需要平均移动表长一半的元素时间为O(n)

·单链表在找到某位置的指针后,插入和删除时仅为O(1)

·顺序存储结构需要分配存储空间。分大了浪费,分小了易发生上溢

·单链表不需要分配存储空间,只要有就可以分配,元素个数也不受限制

 

通过上面的对比,得出一些结论

·若线性表需要频繁查找,很少进行插入和删除时,宜采用顺序存储结构。若需要频繁插入和删除时,宜采用单链表结构。

·当线性表中的元素个数变化较大或根本不知道有多大时,最好采用单链表结构,这样可以不需要考虑存储空间的大小问题。而如果事先知道线性表的大致长度,这种用顺序存储结构效率会高很多。


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值