赞
踩
链式存储结构
与链式存储结构相关的术语
1、结点:数据元素的存储映像。由数据域和指针域两部分组成
2、链表:n个结点由指针链组成一个链表
3、单链表、双链表、循环链表
4、头指针、头结点和首元结点
5、链表可分为带头结点和不带头结点
在链表中设置头结点有什么好处?
头结点的数据域内装的是什么?
链表(链式存储结构)的特点
单链表的定义和表示
typedef struct LNode//声明结点的类型和指向结点的指针类型
{
ElemType date;//结点的数据域
struct LNode *next;//结点的指针域
}LNode,*LinkList;//LinkList为指向结构体LNode的指针类型
LinkList L;
LNode *p;
也可以LinkList p;
p=L;
s=L->next;
p=p->next;
单链表的初始化
判断链表是否为空
单链表的销毁
清空链表
链表仍然存在,但链表中无元素,成为空链表(头指针和头结点仍然在)
算法思路
依次释放所有结点,并将头结点指针域设置为空
求单链表的表长
取值–取单链表中第i个元素的内容
按值查找–根据指定数据获取该数据所在的位置(地址)
插入–在第i个结点前插入值为e的新结点
s->next=p->next;
p->next=s;
删除–删除第i个结点
单链表的查找、插入、删除算法的时间效率分析
建立单链表:头插法–元素插入在链表头部,也叫前插法
建立单链表:尾插法–元素插入在链表尾部,也叫后插法
#include<iostream> using namespace std; typedef struct student { int id; struct student* next; }LNode,*linklist; int InitList(linklist& L)//初始化一个空链表- { L = new LNode;//或L=(linklist)malloc(sizeof(LNode)); L->next = NULL; return 0; } int ListEmpty(linklist L)//判断是否为空 { if (L->next == NULL)//为空 return 0; else return 1; } void DestroyList(linklist& L)//销毁链表 { LNode* p; while (L) { p = L;//将p指向头结点 L = L->next;//指向下一个 delete p; } } void ClearList(linklist& L) //清空链表 { LNode* p, * q; p = L->next;//p指向首元结点 while (p)//没到表尾 { q = p->next;//q指向p的下一个结点 delete p;//释放p p = q;//p指向下一个结点 } L->next = NULL;//将头结点的指针域置空 } int ListLength(linklist L)//获取链表长度 { linklist p; p = L->next;//p指向第一个结点 int i = 0; while (p)//遍历单链表,统计结点数 { i++; p = p->next; } return i;//返回统计的个数i } int GetElem(linklist L, int i, int& e)//获取链表中某个位置的元素 { LNode* p; p = L->next;//p指向首元结点 int j = 1;//初始化 while (p && j < i)//向后扫描,直到p指向第i个元素或者p为空 { p = p->next; ++j; } if (!p || j > i)//第i个元素不存在 return -1; e = p->id;//取第i个元素的数据域的值 return 1; } LNode* LocateElem(linklist L, int e)//查找某个元素的地址 { LNode* p; p = L->next;//p指向首元结点 while (p && p->id != e)//没到尾部并且没找到值为e的结点 { p = p->next; } return p;//返回找到的结点 } int LocateELem(linklist L, int e)//根据指定数据查看该数据的位置序号 { LNode* p; p = L->next;//p指向首元结点 int j = 1;//初始化计数变量 while (p && p->id != e)//未到尾部且未找到值为e的结点 { p = p->next; j++; } if (p) return j;//找到返回位置序号 else return 0;//没找到返回0 } int ListInsert(linklist& L, int i, int e)//在指定位置插入数据 { linklist p = L;//将p指向头结点 int j = 0;//初始化计数参数 while (p && j < i - 1)//寻找第i-1个结点,p指向i-1个结点 { p = p->next; ++j; } if (!p || j > i-1)//i大于表长+1或者小于1,插入位置非法 return -1; else { linklist s; //InitList(s); s = new LNode;//生成新结点s s->id = e;//将结点s的数据域置为e s->next = p->next; p->next = s; return 1; } } int ListDelete(linklist& L, int i,int &e)//删除第i个位置的元素 { linklist p= L; //InitList(p); //p = L; int j = 0;//初始化计数变量 while (p->next && j < i - 1)//寻找第i个结点,并使p指向其前驱,p指向第i-1个结点 { p = p->next; ++j; } if (!(p->next) || j > i - 1)//删除位置不合理 { return -1; } linklist q; q = p->next;//q指向第i个结点,临时保存被删结点的地址以备释放 p->next = q->next;//改变删除结点前驱结点的指针域 e = q->id;//保存删除结点的数据域 delete q;//释放删除结点的空间 return 1; } void CreateListHead(linklist& L, int n)//头插 { InitList(L);//先建立一个带头结点的单链表 for (int i = n; i > 0; i--) { linklist p;//生成新结点p p = new LNode; cin >> p->id;//输入元素值scanf(&p->id) p->next = L->next;//插入到表头 L->next = p; } } void CreateListTail(linklist& L, int n)//尾插 { InitList(L); LNode* r;//新建一个尾指针r r = L;//将其指向头结点 for (int i = 0; i < n; ++i) { LNode* p; p = new LNode;//生成新结点 cin >> p->id;//输入元素值 p->next = NULL;//将新插入的结点的指针域置空 r->next = p;//插入到末尾 r = p;//r指向新的尾结点 } } void DeleteLinkList(LinkList& L, int e)//删除单链表中某个元素为e的所有结点 { Lnode* p, * q;//定义一前一后两个指针 p = new Lnode; q = new Lnode; p = L->next;//p指向首元结点 q = L;//q指向头结点 while (p)//未到末尾 { if (p->date == e)//查看是否为e { q->next = p->next;//用q暂存p的下一个结点的地址 free(p);//释放 p = q->next;//将p从删除结点的前一个结点指向后面一个 } q = p;//让q指向p p = p->next;//p后移一个 } } void PrintLinkList(LinkList L)//输出单链表中的值 { Lnode* p; p = new Lnode; p = L->next;//将p指向首元结点 while (p)//非空 { cout << p->date << " "; p = p->next; } } int main() { linklist L; InitList(L); int i=ListLength(L); cout <<"插入前元素个数为:" << i << endl; CreateListHead(L, 6); i = ListLength(L); cout << "头插后元素个数为:" << i << endl; cout << "头插后元素遍历:" << " "; for (int j = 1; j < 7; j++) { int e_id; GetElem(L, j,e_id); cout << e_id << " "; } cout << endl; ClearList(L); CreateListTail(L, 5); i = ListLength(L); cout << "尾插后元素个数为:" << i << endl; cout << "尾插后元素遍历:" << " "; for (int j = 1; j < 6; j++) { int e_id; GetElem(L, j, e_id); cout << e_id << " "; } cout << endl; ListInsert(L, 3, 89); for (int j = 1; j < 7; j++) { int e_id; GetElem(L, j, e_id); cout << e_id << " "; } cout << endl; int e_IDD; int result=ListDelete(L, 2, e_IDD); cout << "result=" << result << endl; for (int j = 1; j < 7; j++) { int e_id; GetElem(L, j, e_id); cout << e_id << " "; } cout << endl; return 0; }
循环链表
p!=L
或 p->next!=L
带尾指针的循环链表合并(将Tb合并在Ta之后)
p=Ta->next;
Ta->next=Tb->next->next;
delete Tb->next;
Tb->next=p;
//带尾指针的循环链表合并(将Tb合并在Ta之后)
linklist Connect(linklist Ta, linklist Tb)//假设Ta,Tb都是非空的单循环链表
{
LNode* p;
p = Ta->next;//p存表头节点
Ta->next = Tb->next->next;//Tb表头连接到Ta表尾
delete Tb->next;//释放Tb表头结点
Tb->next = p;//修改指针
return Tb;
}
双向链表
typedef struct DulNode
{
Elemtype date;//Elemtype是数据类型
struct DulNode* prior, * next;
}DulNode,*DuLinkList;
双向循环链表
双向链表结构的对称性
p->prior->next=p=p->next->peior
双向链表的插入
int ListInsertDul(DuLinkList& L, int i, Elemtype e)//在带头结点的双向链表L中第i个位置之前插入元素e { DuLinkList p; if (!(p = GetElemDul(L, i)))//找到第i个元素,将p指向它,若没找到,返回-1 return -1; DuLinkList s; s = new DulNode;//新建一个结点 s->date = e;//给新结点数据域赋值 s->prior = p->prior; p->prior->next = s; s->next = p; p->prior = s; return 1; }
双向链表的删除
int ListDeleteDul(DuLinkList& L, int i, Elemtype& e)//删除带头结点的双向循环链表L的第i个元素,并用e返回
{
DuLinkList p;
if (!(p = GetElemDul(L, i)))//找到第i个元素,将p指向它,若没找到,返回-1
return -1;
e = p->date;//将要删除的结点的数据域保存到e中
p->prior->next = p->next;
p->next->prior = p->prior;
free(p);//释放结点
return 1;
}
链式存储结构的优点
链式存储结构的缺点
存储密度
单链表、循环链表和双向链表的时间效率比较
顺序表和链表的比较
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。