数据结构3_线性表 _单链表的基本操作及实现

数据结构3_线性表_2

总览:

总览

线性表:

线性表是具有相同数据类型的n(n>=0)个数据元素的有序序列,其中n为表长,当n=0时线性表是一个空表。若用L命名线性表,其一般表示为:
L = ( a 1 , a 2 , a 3 , a 4 , ∗ ∗ ∗ , a n ) L = (a1,a2,a3,a4,***,an) L=(a1,a2,a3,a4,,an)
a1为表头元素,an为表尾元素,除了an其他元素都有唯一的直接后继,除了a1其他元素都有唯一前驱。

线性表的特性:

  1. 表中元素个数有限;
  2. 表中元素具有逻辑上的顺序性,表中元素有先后次序;
  3. 表中元素都是数据元素,每个元素都是单个元素;
  4. 表中元素的数据类型都相同,意味着每个元素占有相同大小的存储空间;

2 链式存储:

2.1 单链表:

定义:顺序表的链式存储称为单链表,它是通过一组任意的存储单元存储线性表中的数据元素,为了建立起数据元素之间的线性关系,对于每个链表结点,除存放元素自身的信息外,还需要存放一个指向其后继的指针,

链表

存放数据的单元称为数据域,存放地址的单元称为指针域;

结构体定义:

typedef struct Lnode{	
	ElemType data; 
	struct Lnode *next;
}LNode,*LinkList;//Lnode是节点类型 *Linklist是节点指针,顺序访问时通过指针按序访问

通过把若干个结点连接在一起就形成了一个单链表:

链表

利用单链表可以解决顺序表需要大量存储单元的缺点,但单链表附加指针域,也存在浪费空间的缺点;

由于单链表的元素离散地分布在存储空间内,所以单链表是非随机存取(不能下标访问)的存储结构;

有时为了操作方便,还会给链表增加一个不存放数据的头结点(也可以存放表长的信息),头结点的指针域指向线性表的第一个元素;

头结点

头指针和头结点:头指针永远指向链表的第一个结点,不论有没有头结点,头结点是带头链表的第一个结点,结点内部通常不存储信息;

2.1.1 单链表的基本操作:
2.1.1.1 初始化:

单链表的初始化是指构建一个空表。先创建一个空结点,不存放数据,然后令其指针域为空;

bool InitList_L(LinkList &L){
	L = new Lnode; //生成一个新节点作为头节点
	if(!L) return false;
	L -> next = NULL;
	return true;
}
2.1.1.2 建立单链表:

创建单链表分为头插法尾插法两种,头插法是指每次将新结点插入到头结点之后,其创建的单链表和数据输入的顺序正好相反,因此也称为逆序建表;尾插法是指每次把新结点链接到链表的尾部,其创建的单链表和数据输入顺序一致,因此也称为正序建表

2.1.1.2.1 头插法:

头插法

代码实现:

/*头插法(逆序建表)*/
void CreateList_H(LinkList &L){
	int n;
	LinkList s;
	L = new LNode;
	L -> next = NULL;//初始化一个带头结点的空链表,同上
	cout<<"请输入元素个数n:"<<endl;
	cin>>n;
	cout<<"请依次输入n个元素:"<<endl;
	while(n--){
		s = new LNode;//初始化一个空结点 c++用new分配内存空间,c用malloc,见上节
		cin>>s->data;//给s数据域赋值
		s->next = L->next;//把L的指针域赋值给S的指针域,也就是将本来L的后继变为S的后继
		L->next = s;//L的后继变为s,插入结束
	}
}

时间复杂度O(n)

2.1.1.2.2 尾插法:

尾插法

代码实现:

/*尾插法(正序建表)*/
void CreatList_R(LinkList &L){	
	int n;
    LinkList s, r;
    L = new Lnode;
    L -> next = NULL; //初始化头节点
    r = L;
    cout<<"请输入元素个数n:"<<endl;
    cin>>n;
    cout<<"请依次输入n个元素:"<<endl;
    while(n--){
		s = new LNode; 
        cin >> s->data;
        s -> next = NULL; //新建立的节点为尾结点
        r -> next = s;//前任尾节点的指针域指向新尾结点
        r = s; //记录当前的尾结点
    }
}

时间复杂度O(n)

2.1.1.3 按序取值:

从单链表的第一个结点出发,顺指针逐个往下搜索,知道找到第i个结点为止,否则返回最后一个结点的指针null

LinkList GetElem(LinkList L, int i){
    /*也可以写成LNode *GetElem(LinkList L, int i)*/
	int j = 1; //计数
    LinkList p = L -> next;
    if(i == 0) return L;
    if(i < 1) return NULL;
    while(p && j<i){
        p = p->next;
        j++;
    }
    return p;
}

时间复杂度O(n)

2.1.1.4 插入结点:

插入

类似头插法的操作,请自行实现;

实现代码片段:

p = GetElem(L, i-1);
s -> next = p -> next;
p -> next = s;

插入到给定节点后操作的时间复杂度为O(1),若如上操作需找到i-1结点,则为O(n)

2.1.1.5 删除结点:

删除结点

实现代码片段:

p = GetElem(L, i-1);
q = p -> next;
p -> next = q -> next;
//free(q) 如果时c语言开辟的内存需要手动释放

时间复杂度O(n)

还有一种方法也可:

/*p为待删除结点*/
q = p -> next;
p -> data = q -> data;
p -> next = q -> next;
//free(q)
2.1.1.6 单链表习题:

设线性表L=(a1,a2,a3,a4,***,an)采用带头结点的单链表保存,表定义如本节定义;

设计出空间复杂度为O(1),时间复杂度尽可能低的算法,重新排列列表,得到线性表L=(a1,an,a2,a(n-1),a3,a(n-2)),给出算法的设计思想和时间复杂度,并用c/c++实现;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值