数据结构:线性表(链表)

前天停电摆一天,昨天琐事忙一天,寄。

线性表:

 线性表(List):线性的,依次的,一列

较复杂的线性表中数据元素可以有若干个数据项组成。

两种实现方法:数组(顺序存储)和链表(链式存储),显然,链表实现更加具有效率。

下面我们讨论链表的线性表实现:

链表中第一个结点(Node)的存储位置叫做头指针,最后一个指针指向NULL(无后继指针)。

 头指针前存在头结点,一般存储公共信息。

 

头指针与头结点: 

 逻辑示意图(非内存存储方式!):

 结点由存放数据元素的数据域和存放后继元素地址的指针域组成。

代码实现:

1.建立单链表

typedef struct Node{
	int value;
	struct Node* next;
}*Link;
//Link=(strcut) Node*

1.1头插法:

void CreatLinkHead(Link head,int lenth){

	Link newNode;
	head=(Link)malloc(sizeof(struct Node));
	head->next=NULL;

	while(lenth--){
		newNode=(Link)malloc(sizeof(struct Node));
		newNode->value=rand()%100+1;
		newNode->next=head->next;
		head->next=newNode;
	
	}
}

1.2尾插法:

void CreatLinkRear(Link head, int lenth) {

	Link rear, newNode;
	head = (Link)malloc(sizeof(struct Node));
	head->next = NULL;
	rear = head;

	while (lenth--) {
		newNode = (Link)malloc(sizeof(struct Node));
		newNode->value = rand() % 100 + 1;
		newNode->next = rear->next;
		rear->next = newNode;
		rear = newNode;
	}
	rear->next = NULL; //也许可以不要?毕竟每次循环结束时rear->next始终为NULL

}

2.遍历

void TraverseList(Link head) {

	Link p = head->next;

	while (p) {
		printf("%d ", p->value);
		p = p->next;
	}
	puts("");
}

3.插入:

int InsertList(Link L, int pos, int e) {

	int j = 1;
	Link p/*pointer*/, s/*newNode*/;
	p = L;

	while (p && (j < pos)) {
		p = p->next;
		++j;
	}//找寻此位置,且只需找到此位置的前驱即可,因为前驱包含指向后驱的指针

	if (!p || j > pos) return 0;/*ERROR,不存在此位置*/
//存在则插入
	s = (Link)malloc(sizeof(struct Node));
	s->value = e;
	s->next = p->next;
	p->next = s;

	return 1;/*OK,成功插入*/

}

4.删除:


int ListDelete(Link L, int pos, int* e/*记录删除的数据的值*/) {
	int j = 1;
	Link p, q/*temp*/;
	p = L;

	while (p->next && j < pos) {
		p = p->next;
		++j;
	}//这里和插入不同,判断条件p变为p->next
//原因为插入无需保证p的后驱不为空,而删除需要保证p的后驱不为空
	if (!(p->next) || j > pos) return 0;

	q = p->next;//将p的后驱单独拿出(复制)
	p->next = q->next;//如果不需要知道所删除的数据,那么这三行可以改为如下代码
//	p->next=p->next->next;//然而这行代码无法释放p->next所占用的内存
	*e = q->value;
	
	free(q);

	return 1;
}

 5.释放单链表

int ClearList(Link L) {
	
	Link p, q;
	p = L->next;
	
	while (p) {
		q = p->next;
		free(p);
		p = q;
	}
	/*
	  显然,以下代码不可行
	  free(p);
	  p=p->next;
	  已经释放p后,如何再通过p寻找它的后继呢?须知free(p)包含释放数据域和指针域。
	 */
	L->next = NULL;
	
	return 1;

}

 总代码:

#include<stdio.h>
#include<stdlib.h>

typedef struct Node {
	int value;
	struct Node* next;
}*Link;
//Link=(strcut) Node*

void CreatLinkHead(Link head, int lenth) {

	Link newNode;
	head = (Link)malloc(sizeof(struct Node));
	head->next = NULL;

	while (lenth--) {
		newNode = (Link)malloc(sizeof(struct Node));
		newNode->value = rand() % 100 + 1;
		newNode->next = head->next;
		head->next = newNode;
	}

}

void CreatLinkRear(Link head, int lenth) {

	Link rear, newNode;
	head = (Link)malloc(sizeof(struct Node));
	head->next = NULL;
	rear = head;

	while (lenth--) {
		newNode = (Link)malloc(sizeof(struct Node));
		newNode->value = rand() % 100 + 1;
		newNode->next = rear->next;
		rear->next = newNode;
		rear = newNode;
	}
	rear->next = NULL; //也许可以不要?毕竟每次循环结束时rear->next始终为NULL

}

void TraverseList(Link head) {

	Link p = head->next;

	while (p) {
		printf("%d ", p->value);
		p = p->next;
	}
	puts("");
}

int InsertList(Link L, int pos, int e) {

	int j = 1;
	Link p/*pointer*/, s/*newNode*/;
	p = L;

	while (p && (j < pos)) {
		p = p->next;
		++j;
	}

	if (!p || j > pos) return 0;/*ERROR*/

	s = (Link)malloc(sizeof(struct Node));
	s->value = e;
	s->next = p->next;
	p->next = s;

	return 1;/*OK*/

}

int ListDelete(Link L, int pos, int* e/*记录删除的数据的值*/) {
	int j = 1;
	Link p, q/*temp*/;
	p = L;

	while (p->next && j < pos) {
		p = p->next;
		++j;
	}//这里和插入不同,判断条件p变为p->next
//原因为插入无需保证p的后驱不为空,而删除需要保证p的后驱不为空
	if (!(p->next) || j > pos) return 0;

	q = p->next;//将p的后驱单独拿出(复制)
	p->next = q->next;//如果不需要知道所删除的数据,那么这三行可以改为如下代码
//	p->next=p->next->next;//然而这行代码无法释放p->next所占用的内存
	*e = q->value;

	free(q);

	return 1;
}

int ClearList(Link L) {
	
	Link p, q;
	p = L->next;
	
	while (p) {
		q = p->next;
		free(p);
		p = q;
	}
	/*
	  显然,以下代码不可行
	  free(p);
	  p=p->next;
	  已经释放p后,如何再通过p寻找它的后继呢?须知free(p)包含释放数据域和指针域。
	 */
	L->next = NULL;
	
	return 1;
	
}

int main() {

	return 0;
}

 

另,单链表基本操作见下:

(5条消息) C语言单链表实现初始化、创建、增、删、查等基本操作(详细)_Qian_Qian_IT的博客-CSDN博客

 

 typedef详解请移步下面这篇文章:

(5条消息) C语言typedef的用法详解_风叶翩翩的博客-CSDN博客_typetef

单链表的闲谈可以看这篇博客:

(5条消息) 对单链表的理解_wjc96815的博客-CSDN博客_数组单链表难点

 

 

 数组模拟单链表感兴趣的可以自己去搜索下,这里不再展开。

循环链表:

 将尾指针指向头

改进:

 此时,rear->next->next==head->next

完成这两个循环链表的合并只需进行如下操作:

p = rearA->next;
rearA->next = rearB->next->next;
rearB->next = p;
free(p);

双向链表:


在单链表的每个结点中在设置一个指向其前驱的指针域。

1.双向链表的插入操作:

	Link p, s;
//	p->prior->next == p == p->next->prior; //三者相等
	//先解决前驱,再解决后继,并且两者交叉排列,这样的思路更连贯一些
	s->prior = p;
	s->next = p->next;
	p->next->prior = s;
	p->next = s;

2.删除操作:

    p->next->prior=p->prior;
	p->prior->next=p->next;
	free(p);
	//这里无需引入中间变量再进行free操作,可以直接释放
	

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值