线性表笔记

本文详细讲解了顺序表和链表的定义、特点,对比了它们在查找、插入、删除操作的时间效率,并深入剖析了链表的动态性和顺序表的存储密度。同时涵盖了链表和顺序表的优缺点以及实例代码,帮助读者理解这两种常见数据结构的实际应用.
摘要由CSDN通过智能技术生成

定义

线性表(List) :由零个或多个数据元素组成的有限序列。

这里需要强调几个关键的地方:

  • 首先它是一个序列,也就是说元素之间是有个先来后到的。
  • 若元素存在多个,则第一个元素无前驱,而最后一个元素无后继,其他元素都有且只有一个前驱和后继。
  • 另外,线性表强调是有限的,事实上无论计算机发展到多强大,它所处理的元素都是有限的。

顺序表(线性表的顺序存储结构)的特点

(1)利用数据元素的存储位置表示线性表中相邻数据元素之间的削后大系,即线性表的逻辑结构与存储结构一致
(2)在访问线性表时,可以快速地计算出任何一个数据元素的存储地址。因此可以粗略地认为,访问每个元素所花时间相等
这种存取元素的方法被称为随机存取法

顺序表的操作算法分析

时间复杂度
查找、插入、删除算法的平均时间复杂度为O(n)
空间复杂度
显然,顺序表操作算法的空间复杂度S(n)=O(1)
(没有占用辅助空间)

顺序表优缺点

​ 优点:

  • 存储密度大(结点本身所占存储量/结点结构所占存储量)

  • 可以随机存取表中任一 元素

    缺点:

  • 在插入、删除某一元素时,需要移动大量元素

  • 浪费存储空间

  • 属于静态存储形式,数据元素的个数不能自由扩充

顺序表代码

/*
Project: sequence_list(数据结构-顺序表)
Date:    2018/09/12  20191012修改 添加Reverse  20200819修改 添加ClearList
Author:  Frank Yu
CreateList(SqList &L,int n) 参数:顺序表L,顺序表长度n 功能:创建长度为的顺序表 时间复杂度:O(n)
InitList(SqList &L) 参数:顺序表L 功能:初始化 时间复杂度:O(1)
InsertList(SqList &L,int i,ElemType e) 参数:顺序表L,位置i,元素e 功能:位置i处插入元素e 时间复杂度:O(n)
ListDelete(SqList &L,int i) 参数:顺序表L,位置i 功能:删除位置i处元素 时间复杂度:O(n)
LocateElem(SqList L,ElemType e) 参数:顺序表L,元素e 功能:返回第一个等于e的元素的位置 时间复杂度:O(n)
Reverse(SqList &L) 参数:顺序表L 倒置函数 将原顺序表直接倒置
PrintList(SqList L) 参数:顺序表L 功能:遍历L,并输出
SplitSort(SqList &L) 参数:顺序表L 功能:分开奇偶,并分开排序
ClearList(SqList &L) 参数:顺序表L 功能:清空顺序表
*/
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define MaxSize 100
using namespace std;
//顺序表数据结构
typedef struct
{
	int data[MaxSize];//顺序表元素
	int length;            //顺序表当前长度
}SqList;
//***************************基本操作函数*******************************//
//初始化顺序表函数,构造一个空的顺序表
int InitList(SqList &L)
{
	memset(L.data, 0, sizeof(L));//初始化数据为0
	L.length = 0;                //初始化长度为0
	return 0;
}
//创建顺序表函数 初始化前n个数据
bool CreateList(SqList &L, int n)
{
	if (n<0 || n>MaxSize)false;//n非法
	for (int i = 0; i<n; i++)
	{
		//scanf("%d", &L.data[i]);
		cin>>L.data[i];
		L.length++;
	}
	return true;
}
//插入函数 位置i插入数据 i及之后元素后移  1=<i<=length+1
bool InsertList(SqList &L, int i, int e)
{
	if (i<1 || i>L.length + 1) //判断位置是否有效
	{
		printf("位置无效!!!\n");
		return false;
	}
	if (L.length >= MaxSize)//判断存储空间是否已满
	{
		printf("当前存储空间已满!!!\n");
		return false;
	}
	for (int j = L.length; j >= i; j--)//位置i及之后元素后移
	{
		L.data[j] = L.data[j - 1];
	}
	L.data[i - 1] = e;
	L.length++;
	return true;
}
//删除函数 删除位置i的元素 i之后的元素依次前移
bool  ListDelete(SqList &L, int i)
{
	if (i<1 || i>L.length)
	{
		printf("位置无效!!!\n");
		return false;
	}
	for (int j = i; j <= L.length - 1; j++)//位置i之后元素依次前移覆盖
	{
		L.data[j - 1] = L.data[j];
	}
	L.length--;
	return true;
}
//查找函数 按位置从小到大查找第一个值等于e的元素 并返回位置
int LocateElem(SqList L, int e)
{
	for (int i = 0; i<L.length; i++)//从低位置查找
	{
		if (L.data[i] == e)
			return i + 1;
	}
	return 0;
}
//倒置函数 将原顺序表直接倒置
void Reverse(SqList &L)
{
	if (L.length)
		for (int i = 0; i<L.length - 1 - i; i++)
		{
			int t = L.data[i];
			L.data[i] = L.data[L.length - 1 - i];
			L.data[L.length - 1 - i] = t;
		}
}
//奇偶分开并排序
void SplitSort(SqList &L)
{
	int Even = 0;
	int Odd = L.length - 1;
	int i = 0;
	int j = L.length - 1;
	bool flag = false;
	if (L.length)
		for (; i < j; i++, j--)
		{
			while (L.data[i] % 2 != 0)i++;
			while (L.data[j] % 2 == 0)j--;
			if (L.data[i] % 2 == 0 && L.data[j] % 2 != 0&&i<j)
			{
				int temp = L.data[i];
				L.data[i] = L.data[j];
				L.data[j] = temp;
				flag = true;
			}
			if(!flag) //没有交换
			{
				Even = L.length - 1;//全奇数
				Odd = 0; //全偶数
			}
		}
	if (flag)
	{
		for(int i=0;i<L.length;i++)
			if (L.data[i] % 2 == 0)
			{
				Odd = i;
				Even = i - 1;
				break;
			}
	}
	sort(L.data, L.data + Even + 1);
	sort(L.data + Odd, L.data + L.length);
}
//清空顺序表
void ClearList(SqList &L) {
	L.length = 0;
}
//********************************功能函数*****************************************//
//输出功能函数 按位置从小到大输出顺序表所有元素
void PrintList(SqList L)
{
	printf("当前顺序表所有元素:");
	for (int i = 0; i<L.length; i++)
	{
		printf("%d ", L.data[i]);
	}
	printf("\n");
}
//创建顺序表函数
void Create(SqList &L)
{
	int n; bool flag;
	L.length = 0;
	printf("请输入要创建的顺序表长度(>1):");
	scanf("%d", &n);
	printf("请输入%d个数(空格隔开):", n);
	flag = CreateList(L, n);
	if (flag) {
		printf("创建成功!\n");
		PrintList(L);
	}
	else printf("输入长度非法!\n");

}
//插入功能函数 调用InsertList完成顺序表元素插入 调用PrintList函数显示插入成功后的结果
void Insert(SqList &L)
{
	int place; int e; bool flag;
	printf("请输入要插入的位置(从1开始)及元素:\n");
	scanf("%d%d", &place, &e);
	flag = InsertList(L, place, e);
    if (flag)
	{
		printf("插入成功!!!\n");
		PrintList(L);
	}
}
//删除功能函数 调用ListDelete函数完成顺序表的删除 调用PrintList函数显示插入成功后的结果
void Delete(SqList &L)
{
	int place; bool flag;
	printf("请输入要删除的位置(从1开始):\n");
	scanf("%d", &place);
	flag = ListDelete(L, place);
	if (flag)
	{
		printf("删除成功!!!\n");
		PrintList(L);
	}
}
//查找功能函数 调用LocateElem查找元素
void Search(SqList L)
{
	int e; int flag;
	printf("请输入要查找的值:\n");
	scanf("%d", &e);
	flag = LocateElem(L, e);
	if (flag)
	{
		printf("该元素位置为:%d\n", flag);
	}
	else
		printf("未找到该元素!\n");
}
//菜单
void menu()
{
	printf("********1.创建                        2.插入*********\n");
	printf("********3.删除                        4.查找*********\n");
	printf("********5.倒置                        6.分奇偶排序***\n");
	printf("********7.输出                        8.清空*********\n");
	printf("********9.退出                              *********\n");
}
int main()
{
	SqList L; int choice;
	InitList(L);
	while (1)
	{
		menu();
		printf("请输入菜单序号:\n");
		scanf("%d", &choice);
		if (9 == choice) break;
		switch (choice)
		{
		case 1:Create(L); break;
		case 2:Insert(L); break;
		case 3:Delete(L); break;
		case 4:Search(L); break;
		case 5:Reverse(L); break;
		case 6:SplitSort(L); break;
		case 7:PrintList(L); break;
		case 8:ClearList(L); break;
		default:printf("输入错误!!!\n");
		}
	}
	return 0;
}


1

#include <iostream>
using namespace std;
typedef struct Lnode {
	int data;
	struct Lnode* next;
}Lnode, * LinkList;
Lnode *p;
void initList(LinkList &L, int n) {
	L = new Lnode;
	LinkList a;
	L->next == NULL;
	a = L;
	int i;
	for ( i = 0; i < n; i++) {
		p = new Lnode;
		cin >> p->data;
		p->next = NULL;
		a->next = p;
		a = p;
	}
	a->next = NULL;
}
int Insert(LinkList &L) {
	int d, j = 0, k;
	cin >> k >> d;
	while (L && j < k) {
		L = L->next;
		j++;
	}
	if (!L || j > k)
		return 0;
	p = new Lnode;
	p->data = d;
	p->next = L->next;
	L->next = p;
	return 1;
}
int Delete(LinkList& L) {
    p = new Lnode;
	int k, j = 0;
	cin >> k;
	while (L->next && (j < k - 1)) {
		L = L->next;
		j++;
	}
	if (!(L->next) || (j > k - 1))
		return 0;
	p = L->next;
	L->next = p->next;
	return 1;
}
int main() {
	int n;
	cin >> n;
	LinkList L;
	LinkList L1;
	initList(L, n);
	int m;
	cin >> m;
	while (m--) {
		L1 = L;
		int m1;
		cin >> m1;
		if (m1 == 0)
			Insert(L1);
		else
			Delete(L1);
	}
	L1 = L->next;
	while (L1) {
		cout << L1->data << " ";
		L1 = L1->next;
	}
	delete L1;
	delete L;
	return 0;
}

单链表的查找、插入、删除算法时间效率分析

查找:
因线性链表只能顺序存取,即在查找时要从头指针找起,查找的时间复杂度为O(n)。
插入和删除:
因线性链表不需要移动元素,只要修改指针,一般情况下时间复杂度为0(1)。

单链表和双向链表的时间效率的比较

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9EkkNiU3-1629105715881)(C:\Users\不负良人\Desktop\学习资料\截图\QQ截图20210812171714.png)]

链式存储结构的优点:

  • 结点空间可以动态申请和释放;
  • 数据元素的逻辑次序靠结点的指针来指示,插入和删除时不需要移动数据元素。

链式存储结构的缺点:

  • 存储密度小,每个结点的指针域需额外占用存储空间。当每个结点的数据域所占字节不多时,指针域所占存储空间的比重显得很大。
  • 链式存储结构是非随机存取结构。对任一 结点的操作都要从头指针依指针链查找到该结点,这增加了算法的复杂度。

顺序表和链表的比较

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YtXLGzq0-1629105715885)(C:\Users\不负良人\Desktop\学习资料\截图\QQ截图20210812172919.png)]

#include<iostream>
using namespace std;
typedef struct Lnode{
int data;
struct Lnode* next;
}Lnode,*LinkList;
Lnode *p;
void initlist(LinkList &L){
    L=new Lnode;
LinkList a;
L->next=NULL;
a=L;
p=new Lnode;
    while(cin>>p->data&&p->data>=0){
        p->next=NULL;
        a->next=p;
        a=p;
        a->next=NULL;
        p=new Lnode;
    }
}
int a(LinkList &L){
int length=0;
while(L){
    length++;
    L=L->next;}
return length;
}
void select(LinkList &L,int k,int length){
int i=0;
   while(i<length-k){
    L=L->next;
    i++;
   }
   cout<<L->data;
}
int main(){
int k,length=0;
cin>>k;
LinkList L;
LinkList L1;
initlist(L);
L1=L;
length=a(L1);
if(k<=0||k>length-1){
    cout<<"NULL"<<endl;

}
else
select(L,k,length);
delete L;
delete L1;
return 0;
}

顺序表的合并及排序代码

#include<cstring>
#include<iostream>
#define max 100
using namespace std;
typedef struct{
int data[max];
int length=0;
}sqlist;

//void initlist(sqlist &L){
//memset(L.data,0,sizeof(L));
//L.length=0;
//}

void Insert(sqlist &L,int n){
    int i;
for(i=0;i<n;i++){
    cin>>L.data[i];
    L.length++;
}
}

void hebing(sqlist &L1,sqlist &L2){
int n=L1.length;
int m=L2.length;
int i,j,t;
bool flag;
for(i=0;i<m;i++){
        flag=true;
    for(j=0;j<n;j++){
        if(L2.data[i]==L1.data[j]){
                flag=false;
        }
    }
        if(flag){
            n++;
            L1.length++;
            L1.data[n-1]=L2.data[i];
                }
}
cout<<n<<endl;
for(i=0;i<n;i++){
    cout<<L1.data[i]<<" ";
}
}
void sort(sqlist &L){
int n=L.length;
int i,t,j;
for(i=0;i<n-1;i++){
    for(j=i+1;j<n;j++){
        if(L.data[i]>L.data[j]){
            t=L.data[i];
            L.data[i]=L.data[j];
            L.data[j]=t;
        }
    }
}
cout<<endl;
 cout<<n<<endl;
for(i=0;i<n;i++){
    cout<<L.data[i]<<" ";
}
}
int main()
{
    int n,m;
    cin>>n;

    sqlist L1;
    sqlist L2;
//    initlist(L1);
//     initlist(L2);
     Insert(L1,n);
     cin>>m;
     Insert(L2,m);
     hebing(L1,L2);
     sort(L1);
    return 0;
}

链表的合并及排序代码

#include<iostream>
using namespace std;
typedef struct Lnode{
int data;
struct Lnode *next;
}Lnode,*LinkList;
Lnode *p1,*p2,*p3,*p,*q;
void initlist(LinkList &L,int n){
L=new Lnode;
L->next=NULL;
LinkList a;
L->data=0;
a=L;
int i;
for(i=0;i<n;i++){
        p=new Lnode;
    cin>>p->data;
    L->data++;
p->next=NULL;
a->next=p;
a=p;
}
a->next=NULL;
}
/**
5 96 745 9646 65 654
6 894 559 4696 749 996 7894
*/
void Sort(LinkList &L){
int i,j,t,n;
n=L->data;
cout<<n<<endl;
LinkList a;
a=L;
for(i=1;i<=n-1;i++){
        p=new Lnode;
        a=a->next;
        p=a->next;
        for(j=i;j<=n-1;j++){
                if(a->data<=p->data){
                   p=p->next;
                }
                else{
                    t=a->data;
                    a->data=p->data;
                    p->data=t;
                    p=p->next;
                }
        }
}
}


void hebing(LinkList &L1,LinkList &L2,LinkList &L3){
    p1=new Lnode;
    p2=new Lnode;
    p3=new Lnode;
p1=L1->next;p2=L2->next;
L3=L1;
p3=L3;
while(p1&&p2){
    if(p1->data<=p2->data){
        p3->next=p1;
        p3=p1;
        p1=p1->next;
    }
    else{
        p3->next=p2;
        p3=p2;
        p2=p2->next;
    }
}
 p3->next=p1?p1:p2;
 delete L2;
}int main(){
    int n,m;
LinkList L1;
LinkList L2;
LinkList L3;
cin>>n;
initlist(L1,n);
cin>>m;
initlist(L2,m);
Sort(L1);
Sort(L2);
hebing(L1,L2,L3);
L3=L3->next;
while(L3){
    cout<<L3->data<<" ";
    L3=L3->next;
}
delete L1;
delete L2;
delete L3;
}

多项式运算

#include<iostream>
using namespace std;
typedef struct lnode{
float coef;
int expn;
struct lnode *next;
}lnode,*linklist;
lnode *p;
void initlist(linklist &L,int n){
L=new lnode;
L->next=NULL;
linklist a;
a=L;
int i;
for(i=0;i<n;i++){
        p=new lnode;
    cin>>p->coef>>p->expn;
    a->next=p;
    a=p;
}
a->next=NULL;
}
void hebing(linklist &L1,linklist &L2,linklist &L3){
    L3=new lnode;
    L3->next=NULL;
linklist La;
linklist Lb;
linklist Lc;
La=L1->next;
Lb=L2->next;
Lc=L3;
while(La&&Lb){
       p=new lnode;
    if(La->expn>Lb->expn){
       p->coef=La->coef;
       p->expn=La->expn;
        La=La->next;
    }
    else if(La->expn<Lb->expn){
       p->coef=Lb->coef;
       p->expn=Lb->expn;
        Lb=Lb->next;
    }
    else if(La->expn==Lb->expn){
        p->coef=(La->coef+Lb->coef);
        p->expn=La->expn;
        La=La->next;
        Lb=Lb->next;
    }
Lc->next=p;
Lc=p;
}
while (La) {//a没完
        p = new lnode;
        p->coef = La->coef;
        p->expn = La->expn;
        Lc->next = p;
        Lc = p;
        //cout<<Lc->left<<" "<<Lc->up<<endl;
        La = La->next;
    }
    while (Lb) {//b没完
        p = new lnode;
        p->coef = Lb->coef;
        p->expn = Lb->expn;
        Lc->next = p;
        Lc = p;
        //cout<<Lc->left<<" "<<Lc->up<<endl;
        Lb = Lb->next;
    }
    Lc->next=NULL;
}
void del(linklist &L){
linklist p1=L;
p=p1;
while(p1->next){
        p=p1->next;
    if(p->coef==0){
        p1->next=p->next;
    }
    else
        p1=p1->next;
}
}
void print(linklist& L) {
    linklist Lt = L->next;
    if (!Lt) cout << "0 0" << endl;
    else {
        while (Lt->next) {
            cout << Lt->coef << " " << Lt->expn << " ";
            Lt = Lt->next;
        }
        cout << Lt->coef << " " << Lt->expn << endl;
    }


}
int main(){
linklist L1;
linklist L2;
linklist L3;
int n,m;
cin>>n;
initlist(L1,n);
cin>>m;
initlist(L2,m);
hebing(L1,L2,L3);
del(L3);
print(L3);

delete L1;
delete L2;
delete L3;
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值