链表与线性表

二、线性表

线性结构:线性表、栈、队列、串和数组

顺序表

特点:逻辑上相邻的数据元素,其物理次序也是相邻的。可以做到随机存取,按照下标取元素

线性表的应用:多项式的运算、稀疏多项式的运算,图书管理系统

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

#define OK 		1
#define ERROR   0
#define TRUE	1
#define FALSE	0
#define INFEASIBLE 	-1
#define OVERFLOW	-2

#define MAXSIZE 100

typedef int Status;   //定义函数类型名

typedef int ElemType;//定义ElemType类型

typedef struct {
	ElemType* elem;  //线性表数据存储空间基址 
	int length;
}SqList;// LIST为用户定义的线性表类型




//初始化空线性表
Status InitList(SqList& L) {
	L.elem = (ElemType*)malloc(MAXSIZE * sizeof(ElemType));
	if (L.elem == NULL) {
		return ERROR;
	}
	L.length = 0;
	return OK;
}
Status ClearList(SqList& L) {
	L.length = 0;
	return OK;


}

//求出线性表长度
int ListLength(SqList L) {

	return L.length;

}

//向线性表指定位置插入一个新元素
Status ListInsert(SqList &L, int pos, ElemType e) {
	//pos为插入的(逻辑)位置,e为待插入的数据元素。插入成功则返回1;否则函数返回值为0。
	if ((pos < 1) || (pos>L.length+1)) return 0;
	if (L.length == MAXSIZE) return 0;
	
	for (int j = L.length - 1; j >= pos-1; j--) {
		L.elem[j + 1] = L.elem[j];
	}
	L.elem[pos - 1] = e;
	L.length++;
	
	return OK;
}

//从线性表中删除指定位序的元素
Status ListDelete(SqList& L, int pos)
{//pos为删除的(逻辑)位置,用e返回被删元素。删除成功则返回1;否则函数返回值为0。
	int n;
	int j;
	n = ListLength(L);
	if (pos<1 || pos>L.length) {
		return 0;
	}
	
	for (size_t j =n-1; j > pos - 1; j--) {
		L.elem[j] = L.elem[j + 1];	
	}
	n--;
	return OK;


}

//获取顺序表中指定位置上的数据元素 
Status GetElem(SqList L, int pos, ElemType& e) {
	//pos为指定位置,e用于返回找到的数据元素,如果表空,则返回ERROR;
	int j;
	if ((pos < 1) || (pos > L.length)) {
		return 0;
	}
	e= L.elem[pos-1];
	return e;
}

//从线性表中查找元素,返回第一个与指定值匹配元素位置
int LocateElem(SqList L, ElemType e) {
	//e为待查找的数据元素
	for (size_t i=0;i<L.length;i++){
		if (L.elem[i] == e) {
			return i+1;
		}
	}
	return 0;

}

//遍历输出线性表
Status TraverseList(SqList L) {
	
	for (size_t i = 0; i < L.length; i++)
	{
		printf("%5d", L.elem[i]);
	}

	return 1;
}

// 集合并运算LA=LA∪LB
Status Union(SqList& La, SqList Lb) {
	int m, n;
	ElemType e;
	m = ListLength(La);
	n = ListLength(Lb);
	for (int i = 1; i <= n; i++) {
		GetElem(Lb, i,e);
		if (!LocateElem(La, e)) {
			
			ListInsert(La, ++m, e);
			
		}
		
	}
	
	return 0;
}

// 集合交运算LA=LA ∩LB
Status Intersection(SqList& La, SqList Lb) {
	SqList Lc;
	InitList(Lc);
	int m;
	int n;
	int k;
	ElemType e;
	m = ListLength(La);
	n = ListLength(Lb);
	k = ListLength(Lc);
	for (size_t i = 1; i <= n; i++) {
		GetElem(Lb, i, e);
		if (LocateElem(La, e)) {
			//Lc.length++;
			ListInsert(Lc, ++k, e);
		}
	}
	ClearList(La);
	for (size_t i = 0; i < Lc.length; i++) {
		ListInsert(La, i + 1, Lc.elem[i]);

	}
	return 0;
}

// 集合差运算LA=LA-LB
Status Difference(SqList& La, SqList Lb) {
	int m, n;
	int k;
	ElemType e;
	SqList Lc;
	InitList(Lc);
	k = ListLength(Lc);
	m = ListLength(La);
	n = ListLength(Lb);
	for (size_t i = 1; i <= m; i++) {
		GetElem(La, i, e);
		if (!LocateElem(Lb, e)) {
			ListInsert(Lc, ++k, e);
		}
	}
	ClearList(La);
	for (size_t i = 0; i < Lc.length; i++) {
		ListInsert(La, i + 1, Lc.elem[i]);

	}
	return 0;
}

// 有序表合并LC=LA+LB
Status MergeList(SqList La, SqList Lb, SqList& Lc) {
	ElemType *pc;
	ElemType *pa;
	ElemType* pb;
	ElemType* pc_last;
	ElemType* pa_last;
	ElemType* pb_last;
	Lc.length = La.length + Lb.length;
	Lc.elem = new ElemType[Lc.length];
	pc = Lc.elem;
	pa = La.elem;
	pb = Lb.elem;
	pb_last = Lb.elem + Lb.length - 1;
	pa_last = La.elem + La.length - 1;
	while (pa <= pa_last && pb <= pb_last) {
		if (*pa <= *pb) { *pc = *pa; pc++; pa++; }
		else *pc++ = *pb++;

	}
	while (pa <= pa_last) *pc++ = *pa++;//LA到达表尾,依次将LA剩余元素插入LC

	while (pb <= pb_last)*pc++ = *pb++;//LB到达表尾,依次将LB剩余元素插入表尾
	return 0;
}

Status Purge(SqList& Lc) {
	int m;
	int k;
	ElemType e;
	SqList l;
	InitList(l);
	k = ListLength(l);
    m = ListLength(Lc);
	for (int i = 0; i < m; i++) {
		
		
		if (Lc.elem[i] == Lc.elem[i + 1] ) {
			ListInsert(l, ++k, Lc.elem[i]);
			i = i + 2;
		}
		if (Lc.elem[i] != Lc.elem[i + 1]) {
			ListInsert(l, ++k, Lc.elem[i]);
			
		}
			}
	ClearList(Lc);
	for (size_t i = 0; i < l.length; i++) {
		ListInsert(Lc, i + 1, l.elem[i]);

	}
	return 0;
}
//主函数 
int main() {
	SqList LA, LB, LC;				//定义顺序表变量
	ElemType Array1[] = { 2,8,27,39,66,77,89 };		//顺序表LA的元素 
	ElemType Array2[] = { 6,18,27,59,65,77,89,120,140 };//顺序表LB的元素 
	ElemType item;
	int i;

	//0.数据准备
	//0-1初始化线性表LA,LB

	InitList(LA);
	InitList(LB);
	InitList(LC);
	for (size_t i = 0; i < 7; i++) {
		ListInsert(LA, i+1, Array1[i]);
	}
	for (size_t i = 0; i < 9; i++) {
		ListInsert(LB, i+1, Array2[i]);
	}

		//0-2生成顺序表LA,LB


		//0-3输出顺序表表元素
	printf("\n");
	printf("LA=");
	TraverseList(LA);
	 printf("\n");
	printf("LB=");
	TraverseList(LB);

		//1. 计算LA=LA∪LB,并输出结果
	Union(LA, LB);
	printf("\n");
	printf("LA=");
	TraverseList(LA);

		//2.计算LA=LA ∩LB,并输出结果
	ClearList(LA);
	
	for (size_t i = 0; i < 7; i++) {
		ListInsert(LA, i+1, Array1[i]);
	}

	Intersection(LA, LB);
	printf("\n");
	printf("LA=");
	TraverseList(LA);

		//3.计算LA=LA-LB,并输出结果
	ClearList(LA);

	for (size_t i = 0; i < sizeof(Array1) / sizeof(Array1[0]); i++) {
		ListInsert(LA, i+1, Array1[i]);
	}
	Difference(LA, LB);
	printf("\n");
	printf("LA=");
	TraverseList(LA);
		//4.有序表合并LC=LA+LB,并输出结果
	ClearList(LA);

	for (size_t i = 0; i < sizeof(Array1) / sizeof(Array1[0]); i++) {
		ListInsert(LA, i, Array1[i]);
	}
	MergeList(LA, LB, LC);
	printf("\n");
	printf("LC=");
	TraverseList(LC);
		//5.去掉LC重复多余的元素 ,并输出结果
	Purge(LC);
	printf("\n");
	printf("LC=");
	TraverseList(LC);

		return 1;
}#include<stdio.h>`
`#include<stdlib.h>`

`#define TRUE 1`
`#define FALSE 0`
`#define OK 1`
`#define ERROR -1`

`#define initsize 4`
`#define addsize 2`

`typedef int status;`
`typedef int ElemType;`

`typedef struct //结构体构建`
`{`
    `ElemType *elem;     //储存空间基址`
    `int len;         //表的当前长度`
    `int size;       //当前分配的存储容量`
`} Line;`


`status LineInit(Line *L)  //构造一个空的线性表
{
    (*L).elem = (ElemType *)malloc(initsize*sizeof(ElemType));      //根据存储空间基址类型开辟空间`
    `if((*L).elem==NULL)
        exit (FALSE);       //分配失败
    (*L).len=0;         //空表的长度为0`
    `(*L).size=initsize;     //初始储存容量`
    `return OK;`
`}`

`status LineInsert(Line *L,int i,ElemType e)    //线性表末插入数据`
`{`
    `ElemType *newbase;      //开辟新的空间`
    `ElemType *p;        //定义指针
    int j;
    if(i<1 || i>(*L).len+1)`
        `return FALSE;`
    `if((*L).len == (*L).size)//线性表满`
    `{`
        `newbase=(ElemType *)realloc((*L).elem,((*L).size+addsize)*sizeof(ElemType));        //开辟新空间`
        `if(!newbase)`
            `exit (FALSE);       //开辟失败,退出`
        `(*L).elem=newbase;      //指针指向新开辟的空间
        (*L).size=(*L).size+addsize;
    }
    //插入数据
    p=(*L).elem;`
    `for(j=0; j<(*L).len-i+1; j++)`
        `*(p+(*L).len-j)=*(p+(*L).len-j`

return OK;}`

`Status ListInsert(Sqlist &L ,int i,ElemType e){`//表中插入

`if ((i<1)|| (i>L.length+1)) return error;`

`if(L.length==MAXSIZE) return error;`

`for (j=L.length-1;j>=i-1;j--){`

`L.elem[j+1]=L.elem[j];`

`L.elem[i-1]=e;`

`++L.length;`

`return ok;`

`}`

`}`

`status LineDelete(Line *L,int i,ElemType *e)//删除数据
{
    int j;
    if(i<1 || i>(*L).len)`
        `return FALSE;`
    `*e=*((*L).elem+i-1);
    for(j=0; j<(*L).len-i; j++)`
        `*((*L).elem+i-1+j)=*((*L).elem+i+j);`
    `(*L).len--;`
    `return OK;`
`}`


`status LineDisplay(Line L)  //展示表中原有的数据`
`{`
    `int i;`
    `for(i=0; i<L.len; i++)`
    `{`
        `printf("%5d",*(L.elem+i));`
    `}`
    `printf("\n");`
    `return OK;`
`}`


`status LineLenth(Line L)   //返回当前表长`
`{`
    `return L.len;`
`}`


`status LineEmpty(Line *L)       //清空列表
{
    (*L).len=0;`
    `return OK;`
`}`


`status LineDestory(Line *L)         //释放内存
{
    free((*L).elem);`
    `(*L).elem=NULL;
    (*L).len=0;`
    `(*L).size=0;`
    `return OK;`
`}`


`status ElemGet(Line L,int i,ElemType *e)        //获取新的元素`
`{`
    `if(i<1 || i>L.len)`
        `return FALSE;`
    `*e=*(L.elem+i-1);`
    `return OK;`
`}`

`int main()`
`{`
    `Line L;`
    `ElemType i,e;`
    `LineInit(&L);  //初始化`
    `for(i=0; i<initsize+5; i++) //插入一些测试数据`
       `{`
        `LineInsert(&L,1,i);`
       `}`
    `printf("current number is\n");`
    `LineDisplay(L);//显示线性表的内容`
    `LineDelete(&L,2,&e);//删除其中一个数据`
    `printf("after delete No.2\n");`
    `LineDisplay(L);//显示线性表的内容`
    `ElemGet(L,3,&e);//获取其中一个数据`
    `printf("ElemGet No.3 is %d\n",e);`
    `LineInsert(&L,5,34);//再次插入测试数据`
    `printf("after add No.5\n");`
    `LineDisplay(L);`
    `LineEmpty(&L);//清空线性表的内容`
    `LineDestory(&L);//销毁这个线性表`
    `return 0;`
`}`



#### 链表

线性表链式存储结构:用一组任意的存储单元存储线性表的数据元素。在存储了本身的信息之外,还需要存储一个指示其直接后继的信息。这两部分信息组成数据元素组成数据元素Ai的存储映像,称为节点。存储元素信息的域被称为数据域,存储直接后继存储地址位置的域被称为指针域。指针域中存储的信息被称为指针或链。

链表:单链表,循环链表,双向链表,二叉链表,十字链表,邻接表,邻接多重表。

链表中逻辑上相邻的两个数据元素其物理存储位置不要求相邻。(非顺序映像或链式映像,单链表可以由头指针唯一确定)

```C++
#include<iostream>
using namespace std;
class list {
public:
	int data;
	list* next;
	list* last;
	list* creatlist(list &L);
	list* getelem(list &L,int e);
	list* insert(list& L, int j,int e);
	list* destory(list &L,int i);
}L,*p1,*p2;
list* list::creatlist(list &L) {
	L.next = NULL;
	L.data = -1;
	L.last = NULL;
}
list* list::getelem(list& L,int e) {
	p1 = L.next;
	int j = 1;
	while (p1) {
		if (p1->data == e) {
			return p1;
		}
		else p1++;
	}

}
list* list::insert(list& L, int j, int e) {
	list* n;
	n = new list;
	n->data = e;
	p1 = L.next;
	int i = 0;
	while (p1 && i < j) {
		p1 = p1->next;
		i++;
	}
	n->next = p1->next;
	p1->next = n;
	delete n;
	return p1;
}
list* list::destory(list &L ,int n) {
	p1 = L.next;
	int j = 0;
	while (p1 && j < n - 1) {
		p1++;
		j++;
	}
	list* q;
	q = new list;
	q = p1->next;
	p1->next = p1->next->next;
	delete q;
	return p1;

}
int main() {

}

循环链表:

表中最后一个节点的指针域指向头指针,让整个链表形成一个环,从表中的任何一个节点出发都可以遍历到所有节点。

双向链表:指针域指向前驱节点和直接后继节点

顺序表和链表的比较

存储空间:顺序表的存储空间必须提前分配,元素个数扩充收到一定的影响,易造成存储空间浪费和空间溢出现象;

​ 链表不需要预先分配空间,只要内存空间允许,链表中的元素个数不受到限制。

存储密度:链表的每个节点除了设置数据域用来存储数据元素外,还要设置指针域,用来存储指示元素关系的指针,存储密度较小(数据元素本身所占用的存储量和整个节点结构所占据的存储量之比)

存储元素的效率:顺序表由数组实现按,是一种随机存储结构,取值的操作效率高

链表是一种顺序存储结构,按位置访问列表中的元素,只能从表头开始依次向后遍历链表,取值操作效率较低。

插入和删除操作:

对于链表,在确定插入和删除的位置后,插入和删除操作无需移动数据,只需要修改指针(时间复杂度为O(1))

对于顺序表,进行插入和删除时,平均需要移动表中近一半的节点,时间复杂度为O(n);

应用实例:

线性表的合并:

void MergeList(list &LA,list LB){//将所有在线性表LB中但不在LA中的数据元素插入到LA中

m=listlength(LA);

n=listlength(LB);//求线性表的长度

for (i=0;i<=n;i++){

Getelem(LB,i,e);//取LB中第i个数据元素赋值给e

if (!Located(La,e))//LA中不存在和e相同的元素

listinsert(LA,++m,e);//e插在LA的最后

}

}

有序表的合并:

void MergeList(Sqlist LA,Sqlist LB,Sqlist &LC){

//已知顺序有序表LA和LB的元素按值非递减排列

//归并LA和LB得到新的顺序有序表LC,LC的元素也按非递减排列

LC.length=LA.length+LB.length;//新表长度为待合并两表长度之和

LC.elem=new ElemType[LC.length];//未合并后的新表分配数组空间

pc=LC.elem;//指向新表的第一个元素

pa=LA.elem;

pb=Lb.elem;//pa,pb指向LA,LB的第一个元素

pa_last=LA.elem+LA.length-1;//

pb_last=LB.elem+LB.length-1;//指向LA,LB的最后一个元素

while(pa<=pa_last && pb<=pb_last){//LA,LB都未达到表尾

if (*pa<=*pb)*pc++=*pa++;//取两个表中较小的节点放入LC中

else *pc++=*pb++

}

while(pa<=pa_last) *pc++=*pa++;//LA到达表尾,依次将LA剩余元素插入LC

while(pb<=pb_last)*pc++=*pb++;//LB到达表尾,依次将LB剩余元素插入表尾

}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
链表表示线性表的优点包括: 1. 动态分配内存空间链表的长度可以根据需要动态增加或减少,不需要预先分配固定大小的内存空间。这样可以更灵活地管理内存,避免了顺序存储结构中固定长度可能导致的空间浪费或不足的问题。 2. 插入和删除元素高效:链表的插入和删除操作仅需要修改节点之间的指针,不需要移动其他元素。相比顺序存储结构,插入和删除元素的时间复杂度为O(1),效率更高。 3. 空间利用率高:链表节点只占用必要的存储空间,不像顺序存储结构那样需要预先分配一定大小的存储空间。这样可以更充分地利用内存空间,避免了固定长度可能引起的空间浪费。 4. 灵活性和扩展性强:链表可以在任意位置插入或删除节点,不受线性表长度限制。这使得链表适用于需要频繁插入、删除操作或者长度不确定的场景。 5. 不需要移动元素:由于链表中的节点通过指针连接,插入和删除操作仅需要修改指针指向,并不需要移动其他元素。这样可以避免顺序存储结构中大量元素的移动,提高了插入和删除操作的效率。 需要注意的是,链表的缺点包括相对较高的存储开销、访问元素的效率较低(需要遍历链表),以及对节点的随机访问不如顺序存储结构快速等。所以在选择链表作为线性表存储结构时,需要根据具体应用场景进行权衡和选择。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值