数据结构与算法 线性表

目录

一、前言

二、定义(顺序表与单链表)

三、单链表相关操作

一、前言

线性表有两种存储方式,一是顺序存储,二是链式存储。

1、顺序存储

 2、链式存储

这两种存储方式各有优略,我们可以根据实际情况选择对应的存储方式。 下面,着重分析两种存储的定义和相关操作。

二、定义(顺序表与单链表)

实际中,我们会遇到各种场景,比如学生的信息存储或者图书馆书籍存储,这些需要用到数据结构。那么下面直接以图书馆的书籍为例子进行定义。

1、首先使用顺序存储的方式定义了书籍的结构体,下面定义静态分配空间方式和动态分配空间的方式的结构体。

#include<stdio.h>
#include<stdlib.h>
const int MaxSize = 12;
typedef struct books{
    int id;           // 书籍的ISBN
    int price;        // 书籍的价格,假设为整数
}book;

typedef struct Jing{  // 静态分配存储空间 
	book elem[MaxSize];
	int length;
}JingSqList;
typedef struct Dong{  // 动态分配存储空间 
	book *elem;
	int length;
}DongSqList;

int main()
{
	JingSqList l1;  // 静态 

	DongSqList l2;  // 动态 

	/* 给l2的elem动态分配空间方式一 */
	l2.elem = (book *)malloc(sizeof(book)*MaxSize); 
	free(l2.elem);  // 释放空间 

	/* 给l2的elem动态分配空间方式二 */
	l2.elem = new book();
	delete l2.elem; // 释放空间 

	return 0;
} 

2、下面采用链式存储定义书籍结构体:

#include<stdio.h>
#include<stdlib.h>
typedef struct books{
    int id;           // 书籍的ISBN
    int price;        // 书籍的价格,假设为整数
}book;

typedef struct lianshi{ 
	book elem;
	struct lianshi * next;
}LNode;
void InitList(LNode * &L){ // 采用指针引用的方式初始化链表 
	L = (LNode *)malloc(sizeof(LNode));
	L->next = NULL;
}
int main()
{
	LNode * l;
	InitList(l); 
	return 0;
} 

三、单链表相关操作

对链表的相关操作(初始化链表清空链表销毁链表获取链表的第i个元素查找某个元素在位置i插入元素删除第i个节点建立链表(分头插法/尾插法)合并2个有序链表)。由于顺序表的操作和数组类似,比较简单,就不分析了,下面着重实现链表的这些操作。

先进行相关的定义,后面就直接展示操作的函数了:

#include<stdio.h>
#include<stdlib.h>
typedef struct books{
    int id;           // 书籍的ISBN
    int price;        // 书籍的价格,假设为整数
}book;

typedef struct lianshi{ 
	book elem;
	struct lianshi * next;
}LNode;

int main()
{
    int i = 3;
	int n = 12;
	book e;
	bool sucess;
	e.id = 001; e.price = 122;
	LNode * la, * lb, * lc;
	InitList(la);InitList(lb);   // 初始化链表
	ClearList(la);               // 清空链表 
	DestroyList(lb);             // 销毁链表 
	insert(la,i,e);              // 在第i个位置插入元素e 
	sucess = getElem(la, i, e);  // 获得链表中第i个元素的内容 
	Delete(la,i);                // 删除第i个节点 
	CreListHead(la, n);          // 头插法建立链表 
	CreListRear(lb, n);          // 尾插法建立链表 
	hebingList(la, lb, lc);      // 合并两个有序链表
	return 0;
} 

1、初始化链表

void InitList(LNode * &L){ // 采用指针引用的方式初始化链表 
	L = (LNode *)malloc(sizeof(LNode));
	L->next = NULL;
}

2、清空链表

void ClearList(LNode * &L){  // 清空链表 
	LNode * p,* q;
	p = L->next; // 保留头节点,从l->next开始释放
	while(p){
		q = p->next;  // q指向下一个节点 
		free(p);      // 释放p节点 
		p = q;        // 继续下个节点 
	} 
	L->next = NULL; 
}

3、销毁链表

void DestroyList(LNode * &L){  // 销毁单链表 
	LNode * p;
	while(L){
		p = L;        // 从头节点开始释放空间 
		L = L->next;  // 指向下一个节点 
		free(p);
	}
}

4、获取链表第i个元素

bool getElem(LNode * L, int i, book &e){ // 获得单链表中第i个元素的内容 
	LNode * p = L->next;
	int j = 1;
	while(p && j < i){
		p = p->next;
		j++;
	} 
	if(!p || j > i) // 不存在第i个元素 
		return false;
	e = p->elem;    // 找到后并存储于引用的e中 
	return true;
}

5、查找某个元素

LNode * FindElem(LNode * L,book &e){  // 查找某个元素,返回指针 
	LNode * p = L->next;
	while(p && p->elem.id != e.id)
		p = p->next;
	return p;
}

6、在位置i插入元素

bool insert(LNode * &L,int i,book e){ // 在i的位置插入e 
	LNode * p = L;
	int j = 0;
	while(p && j < i - 1){
		p = p->next;
		j++;
	}
	if(!p || j > i - 1)return false;
	LNode * s = (LNode *)malloc(sizeof(LNode));
	s->elem = e;
    /* 在p与p->next节点之间插入s */ 
	s->next = p->next;  // 把s放大到p的下个节点的前面 
	p->next = s;        // 把s放到p后面 
	return true;
}

7、删除第i个节点

bool Delete(LNode * &L,int i){ // 删除第i个节点 
	LNode * p = L;
	int j = 0;
	while(p->next && j < i - 1){
		p = p->next;
		j++;
	}
	if(!p->next || j > i - 1)
		return false;
	LNode * q = p->next;   // 临时保存即将被删除的节点q,以便释放 
	p->next = q->next;    // 把即将被删除节点的后续接到前面的节点 
	free(q); 			  // 释放节点q 
	return true; 
}

8、建立链表(头插法 & 尾插法)

void CreListHead(LNode * &L, int n){ // 头插法建立链表 
	L = (LNode *)malloc(sizeof(LNode));
	L->next = NULL;
	for(int i = 0;i < n;++i){
		LNode * p = (LNode *)malloc(sizeof(LNode));
		scanf("%d%d",&p->elem.id,&p->elem.price);
		p->next = L->next;  // 插到首元节点前面 
		L->next = p;        // 新节点p接到头节点L后面 
	}
} 
void CreListRear(LNode * &L, int n){ // 尾插法建立链表 
	L = (LNode *)malloc(sizeof(LNode));
	L->next = NULL;
	LNode * r = (LNode *)malloc(sizeof(LNode));  // 始终有一个尾指针 
	for(int i = 0;i < n;++i){
		LNode * p = (LNode *)malloc(sizeof(LNode));
		p->next = NULL;
		scanf("%d%d",&p->elem.id,&p->elem.price);
		r->next = p;  // 插入到链表尾部 
		r = p;        // r指针一直指着尾部 
	}
}

9、合并两个有序链表(La和Lb)

开始需要有pa、pb分别指向La和Lb的首元节点(pa = La->next,pb = Lb->next),我们新建一个表头Lc。让Lc接到La处,同样有个pc指向Lc(Lc = La,pc = Lc。此处注意和pa、pb初始化不同

比较谁的数据小,就把其接到pc(如pc->next = pa)后面,然后让pc = pc->next,再让小的那个指针往后移动到下个节点(如pa = pa->next),直到某个链表所有元素都插入到了Lc。

 最后把剩下的部分接到pc后面。代码如下:

void hebingList(LNode * &La,LNode * &Lb,LNode * &Lc){  // 合并两个有序链表 
	LNode *pa = La->next;  // La的尾节点 
	LNode *pb = Lb->next;  // Lb的尾节点 
	LNode *pc = Lc = La;   // 用La的头节点作为Lc的头节点
	while(pa && pb){
		if(pa->elem.id <= pb->elem.id){
			pc->next = pa;
			pc = pa;
			pa = pa->next;
		}
		else{
			pc->next = pb;
			pc = pb;
			pb = pb->next;
		}
		pc->next = pa ? pa : pb;  // 把剩余的部分接到pc后面
		free(Lb); // 释放Lb的头节点 
	}  
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值