数据结构(C语言版)02---链表

链表:

声明:LNode*   LinkList在链表里面这两个是等价的;

#include<stdio.h>
#include<stdlib.h> 
typedef int Elemtype;
typedef struct LNode{
	Elemtype data;
	struct LNode* next;
}LNode,*LinkList;

链表打印函数:

 //打印
 void Print(LinkList L){
 	L=L->next;
 	while(L){
 		printf("%3d",L->data);
 		L=L->next;
	}
	printf("\n");
 } 

头插法新建链表:

定义链表头指针--》头结点申请空间--》scanf读取第一个值--》while循环读取

//头插法建立新链表
 LinkList list_head(LinkList&L){
 	LNode *s;int x;
 	L=(LinkList)malloc(sizeof(LNode));//带头结点的链表
	L->next=NULL;
	scanf("%d",&x);
	while(x!=9999){
		s=(LinkList)malloc(sizeof(LNode));
		s->data=x;
		s->next=L->next;
		L->next=s;
		scanf("%d",&x);
	} 
	return L;
 }

 int main(){
 	LinkList L;
 	list_head(L);
 	Print(L);
 	return 0;
 }

 头插法:带头结点的链表,头结点的位置是不动的,头插法新建链表,每次添加的新节点是放在第一个结点前,并非头结点前。所以输出是逆序的。

cin:3 3 7 8 9999
cout:8  7  3  3

申请空间:申请空间malloc返回的是void* 指针,因此我们需要强制转化为(LNode*),但是空间的大小必须是结构体的大小才可以,所以写法是(即前面有幸后无形)

s=(LNode*)malloc(sizeof(LNode));
或者
s=(LinkList)malloc(sizeof(LNode));

尾插法:

 

LinkList tail_insert(LinkList&L){
 	int x;
 	L=(LNode*)malloc(sizeof(LNode));//带头结点的链表
 	LNode* s;LNode* r=L;
	scanf("%d",&x);
	while(x!=9999){
		s=(LinkList)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;
		r=s;
		scanf("%d",&x);
	} 
	r->next=NULL;
	return L;
 } 

 尾插法新建链表,需要使用一个辅助指针r ,始终指向尾部,从而避免每次尾插都需要从头开始。

使得复杂度为0(1)

结点顺序,同输入顺序相同。

cin:11 2 45 9999
cout: 11  2 45

 查找:按值查找,按序查找     时间复杂度都是0(n)

//按序号查找,返回第i个 
 LinkList GetElem(LinkList L,int i){
 	if(i==0) return L;
 	if(i<0)	return NULL;
 	int j=1;
 	LNode*p=L->next;
 	while(p&&j<i){
 		p=p->next;
 		j++;
	 }
	if(!p)return NULL;
	return p;
 } 
 //按值查找
 LinkList GetNum(LinkList L,int a){
 	LNode *p=L->next;
 	while(p&&p->data!=a){
 		if(p->data==a) return p;
 		p=p->next;
	}
	return NULL;
 } 

//main()函数插入
LNode* elem=GetElem(L,2);
 	if(elem)	
		printf("%d ",elem->data);
	else printf("NULL ");
	
 	LNode* num=GetNum( L,3);
 	if(num) 
	 	printf("%d",num->data);
	else printf("NULL ");

  注意:

1、按位置查找时,头结点一般不放值,所以按值查找从第一个结点遍历。头结点是位置 0,头结点之后的结点,是第一个结点。如果链表内元素是3,4,5,6,7,那么我们最多只能查第5个结点
2、单链表只能从前往后遍历,不能像顺序表那样拿某个位置可以直接到达,顺序表的按位置获取元素时间复杂度是0(1),但是链表位置查找的时间复杂度是 0(n),链表按值查找的时间复杂度是 O(n)                                                                                                    

插入 &删除  主要就是断链问题

//在第i个位置插入元素 
 bool insert_i(LinkList &L,int i,int a){
 	if(i<1) return false;
	LNode *pre=GetElem(L,i-1);
	if(!pre) return false; 
	LNode *p=(LNode*)malloc(sizeof(LNode));
	p->data=a;
	p->next=pre->next;
	pre->next=p;
	
	return true;
 } 
  //在第i个位置删除元素 
 bool delete_i(LinkList &L,int i){
 	if(i<0) return false;
	LNode *pre=GetElem(L,i-1);
	if(!pre) return false;
	LNode *p=pre->next;
	pre->next=p->next;
	free(p);
	return true;
 } 

//main()插入
bool insert=insert_i(L,2, 3);
	if(insert)	
		Print(L);
	else printf("NULL ");
	
	bool delet=delete_i(L,2);
	if(delet)	
		Print(L);
	else printf("NULL ");
cin:1 2 3 4 5 6 7 8 9999
cout:  1  2  3  4  5  6  7  8
  1  3  2  3  4  5  6  7  8
  1  2  3  4  5  6  7  8

注意:

1.往第i个位置插人,首先我们需要 GetElern 两数,拿到第i-1 个位置元素的地址,这样我们才能把要插人的元素放到 i-1 元素的后面,从而成为第i个元素


2.链表有5个元素时,我们只能插人到 1-6 位置,不能插人到第 10个位置了。可以通过 GetElem() 函数实现:获取第 i-1 个元素的地址时,如果返回的是 NULL,代表插人位置i不合法,这时我们不进行插人,所以不会给新结点申请空间

作业:王道OJ | 课时11作业 (lgwenda.com) 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值