记录学习算法与数据结构(C语言版)week 2---链式表示

目录

一、单链表的定义

二、单链表的基本运算

(1)、单链表的建立

(2)、单链表的查找运算

(3)、单链表的插入运算

(4)、单链表的删除运算


对线性表顺序存储时,如果需要频繁的进行插入与删除操作则运行的时间效率就不够理想。所以,我们提出链式结构的存储线性表,称为链表

一、单链表的定义

在顺序表中,一个重要的特点就是连续的存储单元依次存放线性表的结点,因此结点的顺序与数据原先的顺序一致,我们称其为逻辑和物理上相邻,但是这却对内存空间的分配与使用提出更加严格的要求。但是链表不会这样。链表使用一组任意的存储单元来存放线性表中的元素,为了使数据原先的逻辑关系不丢失,在每个元素的存储结点还应该指示其后续结点的地址,这个信息称为指针。

 由此我们给出链表的结点的结构:

数据域指针域
datanext

该图中结点只有一个指针域,称为单链表,但有时候需要我们构建有多个指针的链表,如:双链表、十字链表等。

关于链表结点的C语言描述如下:


/*单链表结点描述 
typedef struct node
{
	datatype data;
	struct node *next;
}linklist;
linklist *head,p
*/
//上述链表结点定义了一个结构体node,该结构体包含了两个域,数据域data和指针域*next

注:参考<stdlib.h>库函数,以下是几个常用函数

(1)、sizeof(x):计算变量x的长度,返回整数

(2)、malloc(m):开辟m字节长度的地址空间,并返回这段空间的首地址

(3)、free(p):释放指针p所指变量的存储空间

 二、单链表的基本运算

 (1)、单链表的建立

//将全局变量及函数提前说明:
#include<stdio.h>
#include<stdlib.h>
typedef struct node {
     datatype         data;               //数据域
     struct node   *next;               //指针域
}linklist *head, *p, *q;          //一般需要3个指针变量
int m ;                                   // 数据元素的个数
int m=sizeof(linklist);         /* 结构类型定义好之后,每个变量的长度就固定了,m求一次即可 */ 
//单链表的读取(或修改)
//单链表中想取得第i个元素,必须从头指针出发寻找(顺藤摸瓜),不能随机存取 
datatype Get(linklist *L, int i)
{ p=L->next; j=1;
  while(   j<i   ){p=p->next; ++j;}
  if(!p||j>i)return NULL;
  e=p->data;
  return e;
}

动态建立单链表主要有前插法后插法两种

/*)
(1)、前插法:
linklist *CREATLIST()
{
	char ch;
	linklist *head,*p;
	head=NULL;
	ch=getchar();
	while(ch!="$")
	{
		s=malloc(sizeof(linklist));
		s->data=ch;
		s->next=head;
		head=s;
		ch=getchar();
	}
	rewturn head;
}

(2)、后插法:
linklist *CREATLIST()
{
    linklist *head,*p,*s;
    char ch;
    ch=getchar();
    head=malloc(sizeof(linklist));
    head->data=ch;
    p=head;
    ch=getchar();
    while(ch!='$')
    {
        s=malloc(sizeof(linklist));
        s->data=ch;
        p->next=s;
        p=s;
        ch=getchar();
    }
    p->next=NULL;
    return head;
}

 (2)、单链表的查找运算

/*
(1)、按序号查找:
linklist *GET(head,i)
{
	int j;
	linklist *P;
	p=head;j=0;   //从头开始扫描 
	while((p->next!=NULL)&&(j<i))
	{
		p=p->next;    //扫描下一个结点 
		j++;         //已经扫描的结点计数器 
	}
	if(i==j)    //找到了第i个结点 
	{
		return p;
	}
	else      //找不到,i<=0或i>n 
	{
		return NULL;
	}
}
(2)、按值查找:
linklist *LOCATE(head,key)
{
	linklist *p;    //从开始结点比较 
	p=head->next;
	while(p!=NULL)
	{
		if(p->data!=key)
		{
			p=p->next;    //没找到继续循环 
		}
		else
		{
			break;     //找到节点key,退出循环 
		}
	}
	return p;
}
*/

 (3)、单链表的插入运算

1、前插法:(即:在链表中(*p)结点前面插入一个元素。)
INSERTBEFORE(head,p,x)
{
	linklist *s,*q;
	s=malloc(sizeof(linklist));   //定义新结点*s
	S->data=x;
	q=head;    //从头指针开始
	while(q->next!=p)
	{
		q=q->next;
	}
	S->next=p;     //查找*p的前驱节点*q 
	q->next=s;     //将新结点*s插入到*p前 
}
2、后插法:(即:在链表中(*p)结点后面插入一个元素。)
void INSERTAFTER( linklist * p, datatype x)
{
 linklist *s;
 s=(LinkList *)malloc(sizeof(linklist));
 s->data=x;
 s->next=p->next;
 p->next=s;
}
因为后插算法的时间复杂度是O(1),而前插算法的执行时间与位置P有关,平均时间复杂度为O(n);
因此想改善前插的时间性能,可以在*p之后插入新结点*s,然后交换*s和*p的值。假设*p的值是a ,新结点的值是x,从而改进前插进程
代码如下:
INSERTBEFORE1(p,x)
{
	linklist *s;
	s=malloc(sizeof(linklist));
	s->data=p->data;
	s->next=p->next;
	p->data=x;
	p->next=s;
}

 (4)、单链表的删除运算

datatype DeleteAfter ( linklist *p )
{
 linklist *q; 
 q=p->next;
 p->next=q->next;
 x=q->data;
 free(q);
 return x;
}

本博客仅仅为记录本周上课学习内容,代码若有瑕疵请私信@我

我会修改并改正,谢谢!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值