线性表的定义:具有相同特性的数据元素的一个有限序列。该序列中所含元素的个数叫做线性表长度。
定义:L=(a1,a2,a3....an)
其中为a1表头元素,为an表尾元素
线性表的顺序存储结构
其直接将线性表的逻辑结构映射到存储结构上
***********************************************
例:线性表La,Lb分别表示集合A,B,求A = AUB。
void Union(List &La, List Lb) { // 算法2.1// 将所有在线性表Lb中但不在La中的数据元素插入到La中int La_len,Lb_len,i;ElemType e;La_len &#61; ListLength(La); // 求线性表的长度 Lb_len &#61; ListLength(Lb);for (i&#61;1; i<&#61;Lb_len; i&#43;&#43;) {GetElem(Lb, i, e); // 取Lb中第i个数据元素赋给eif (!LocateElem(La, e, equal)) // La中不存在和e相同的数据元素ListInsert(La, &#43;&#43;La_len, e); // 插入
}
} // union
例&#xff1a;
void MergeList(List La, List Lb, List &Lc) { // 算法2.2// 已知线性表La和Lb中的元素按值非递减排列。// 归并La和Lb得到新的线性表Lc&#xff0c;Lc的元素也按值非递减排列。int La_len, Lb_len;ElemType ai, bj; int i&#61;1, j&#61;1, k&#61;0;InitList(Lc);La_len &#61; ListLength(La); Lb_len &#61; ListLength(Lb);while ((i <&#61; La_len) && (j <&#61; Lb_len)) { // La和Lb均非空
GetElem(La, i, ai);GetElem(Lb, j, bj);if (ai <&#61; bj) {ListInsert(Lc, &#43;&#43;k, ai);&#43;&#43;i;} else { ListInsert(Lc, &#43;&#43;k, bj);&#43;&#43;j;}}while (i <&#61; La_len) {GetElem(La, i&#43;&#43;, ai); ListInsert(Lc, &#43;&#43;k, ai);}while (j <&#61; Lb_len) {GetElem(Lb, j&#43;&#43;, bj); ListInsert(Lc, &#43;&#43;k, bj);}
} // MergeList
***********************************************
线性表的顺序表示和实现
//---------------------线性表的顺序存储类型描述------------------------
#define MAXSIZE 50
typedef struct
{ElemType date[MAXSIZE];int length;
}SqList;
//---------------------线性表的的动态分配顺序存储结构--------------------
#define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量
#define LISTINCREMENT 10 //线性表存储空间的分配增量
typedef struct{ElemType * elem ; //存储空间基址int length ; //当前长度int listsize ; //当前分配存储容量&#xff08;以sizeof&#xff08;ElemType&#xff09;为单位&#xff09;
}SqList;
//-------------------构造一个空的线性表L&#xff08;以动态的方式&#xff09;-------------------
Status InitList_Sq(SqList &L) { // 算法2.3// 构造一个空的线性表L。L.elem &#61; (ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));if (!L.elem) return OK; // 存储分配失败L.length &#61; 0; // 空表长度为0L.listsize &#61; LIST_INIT_SIZE; // 初始存储容量return OK;
} // InitList_Sq
常用基本运算集合
初始化
创建
销毁
是否为空
求线性表的长度
输出线性表
求线性表中某个元素的值
按元素值查找
插入运算(一般是前插)
顺序表位序从1开始,因此要注意将逻辑位序转化为物理位序
线性表插入、删除算法时间复杂度为O(n) [注&#xff1a;一般实现]
----------------------------------------------------------------------------------------------------------------
例&#xff1a;有一个顺序表A。设计一个算法&#xff0c;删除所有元素值在[x,y]之间的所有元素&#xff0c;要求算法时间复杂度为O(n),空间复杂度为O(1)
实现&#xff1a;以A表为基础重新构建一个表。
例&#xff1a;有一个顺序表L&#xff0c;假设元素类型ElemType为整型&#xff0c;并且所有元素均不相等。设计一个算法&#xff0c;以第一个元素为分界线&#xff0c;将所有小于它的元素移到该元素前面&#xff0c;将所有大于它的元素移到该元素的后面。
实现1&#xff1a;从两边向中间交替查找不满要求的元素进行交换
实现2&#xff1a;保留第一个元素的值&#xff0c;然后从右边前左边查到不满要求的元素&#xff0c;并将其设置到第一个元素位置 ... ...&#xff08;变化基准位置(原来第一个元素的位置),从而将缺省出的基准位用于存放找到的数值&#xff09;
//---------------------在顺序线性表L的第i个元素之前插入新的元素e-------------------------
Status ListInsert_Sq(SqList &L, int i, ElemType e) { // 算法2.4// 在顺序线性表L的第i个元素之前插入新的元素e&#xff0c;// i的合法值为1≤i≤ListLength_Sq(L)&#43;1ElemType *p;if (i <1 || i > L.length&#43;1) return ERROR; // i值不合法if (L.length >&#61; L.listsize) { // 当前存储空间已满&#xff0c;增加容量ElemType *newbase &#61; (ElemType *)realloc(L.elem,(L.listsize&#43;LISTINCREMENT)*sizeof (ElemType));if (!newbase) return ERROR; // 存储分配失败L.elem &#61; newbase; // 新基址L.listsize &#43;&#61; LISTINCREMENT; // 增加存储容量
}ElemType *q &#61; &(L.elem[i-1]); // q为插入位置for (p &#61; &(L.elem[L.length-1]); p>&#61;q; --p) *(p&#43;1) &#61; *p;// 插入位置及之后的元素右移*q &#61; e; // 插入e&#43;&#43;L.length; // 表长增1return OK;
} // ListInsert_Sq
//--------------------在顺序线性表L中删除第i个元素&#xff0c;并用e返回其值-------------------------
Status ListDelete_Sq(SqList &L, int i, ElemType &e) { // 算法2.5// 在顺序线性表L中删除第i个元素&#xff0c;并用e返回其值。// i的合法值为1≤i≤ListLength_Sq(L)。ElemType *p, *q;if (i<1 || i>L.length) return ERROR; // i值不合法p &#61; &(L.elem[i-1]); // p为被删除元素的位置e &#61; *p; // 被删除元素的值赋给eq &#61; L.elem&#43;L.length-1; // 表尾元素的位置for (&#43;&#43;p; p<&#61;q; &#43;&#43;p) *(p-1) &#61; *p; // 被删除元素之后的元素左移--L.length; // 表长减1return OK;
} // ListDelete_Sq
//--------------------在顺序线性表L中查找第1个值与e满足compare()的元素的位序------------
int LocateElem_Sq(SqList L, ElemType e,Status (*compare)(ElemType, ElemType)) { // 算法2.6// 在顺序线性表L中查找第1个值与e满足compare()的元素的位序。// 若找到&#xff0c;则返回其在L中的位序&#xff0c;否则返回0。int i;ElemType *p;i &#61; 1; // i的初值为第1个元素的位序p &#61; L.elem; // p的初值为第1个元素的存储位置while (i <&#61; L.length && !(*compare)(*p&#43;&#43;, e)) &#43;&#43;i;if (i <&#61; L.length) return i;else return 0;
} // LocateElem_Sq
//--------------------已知顺序线性表La和Lb的元素按值非递减排列---------------------------
void MergeList_Sq(SqList La, SqList Lb, SqList &Lc) { // 算法2.7// 已知顺序线性表La和Lb的元素按值非递减排列。// 归并La和Lb得到新的顺序线性表Lc&#xff0c;Lc的元素也按值非递减排列。ElemType *pa,*pb,*pc,*pa_last,*pb_last;pa &#61; La.elem; pb &#61; Lb.elem;Lc.listsize &#61; Lc.length &#61; La.length&#43;Lb.length;pc &#61; Lc.elem &#61; (ElemType *)malloc(Lc.listsize*sizeof(ElemType));if (!Lc.elem)exit(OVERFLOW); // 存储分配失败pa_last &#61; La.elem&#43;La.length-1;pb_last &#61; Lb.elem&#43;Lb.length-1;while (pa <&#61; pa_last && pb <&#61; pb_last) { // 归并if (*pa <&#61; *pb) *pc&#43;&#43; &#61; *pa&#43;&#43;;else *pc&#43;&#43; &#61; *pb&#43;&#43;;}while (pa <&#61; pa_last) *pc&#43;&#43; &#61; *pa&#43;&#43;; // 插入La的剩余元素while (pb <&#61; pb_last) *pc&#43;&#43; &#61; *pb&#43;&#43;; // 插入Lb的剩余元素
} // MergeList
线性表的链式表示和实现
//--------------线性表的单链表存储结构---------------------
typedef struct LNode{ElemType data;struct LNode *next;
}LNode, *LinkList;
对于带头节点的单链表而言
插入结点&#xff1a;s->next &#61; p->next; (插入S,先找到前一个节点p)
p->next &#61; s;
删除结点: p->next &#61; p->next->next;(先找到前一个节点p)
--------------------------------------------------------------
例&#xff1a;有一个带头结点的单链表L&#61;{a1,b1,a2,b2,a3,b3,...,an,bn},设计一个算法将其拆分成两个带头结点的单链表L1和L2&#xff0c;L1&#61;{a1,a2,a3...an},L2&#61;{bn,bn-1,...b1}.要求L1使用L的头结点
注&#xff1a;链表的插入分头插和尾插
例&#xff1a;有一个带头结点的单链表L&#xff0c;设计一个算法使其元素递增有序。
问&#xff1a;带头结点的单链表与不带头结点的单链表有何区别&#xff1f;
答&#xff1a;带头结点单链表可以在头节点中加入一些附加信息&#xff0c;并且有利于实现各种运算&#xff08;删除和插入&#xff09;。
//----------------------取第i个值-----------------------------------------
Status GetElem_L(LinkList &L,int i, ElemType &e) { // 算法2.8// L为带头结点的单链表的头指针。// 当第i个元素存在时&#xff0c;其值赋给e并返回OK&#xff0c;否则返回ERROR
LinkList p;p &#61; L->next; int j &#61; 1; // 初始化&#xff0c;p指向第一个结点&#xff0c;j为计数器while (p && j// 顺指针向后查找&#xff0c;直到p指向第i个元素或p为空p &#61; p->next; &#43;&#43;j;}if ( !p || j>i ) return ERROR; // 第i个元素不存在e &#61; p->data; // 取第i个元素return OK;
} // GetElem_L
//----------------在带头结点的单链线性表L的第i个元素之前插入元素e--------
Status ListInsert_L(LinkList &L, int i, ElemType e) { // 算法2.9// 在带头结点的单链线性表L的第i个元素之前插入元素e
LinkList p,s;p &#61; L; int j &#61; 0;while (p && j
} // LinstInsert_L
//---------在带头结点的单链线性表L中&#xff0c;删除第i个元素&#xff0c;并由e返回其值--------
Status ListDelete_L(LinkList &L, int i, ElemType &e) { // 算法2.10// 在带头结点的单链线性表L中&#xff0c;删除第i个元素&#xff0c;并由e返回其值
LinkList p,q;p &#61; L;int j &#61; 0;while (p->next && j
} // ListDelete_L
//------逆位序输入&#xff08;随机产生&#xff09;n个元素的值&#xff0c;建立带表头结点的单链线性表L-----
void CreateList_L(LinkList &L, int n) { // 算法2.11// 逆位序输入&#xff08;随机产生&#xff09;n个元素的值&#xff0c;建立带表头结点的单链线性表L
LinkList p;int i;L &#61; (LinkList)malloc(sizeof(LNode));L->next &#61; NULL; // 先建立一个带头结点的单链表for (i&#61;n; i>0; --i) {p &#61; (LinkList)malloc(sizeof(LNode)); // 生成新结点p->data &#61; random(200); // 改为一个随机生成的数字(200以内)p->next &#61; L->next; L->next &#61; p; // 插入到表头
}
} // CreateList_L
//-----------------有序合并链表----------------------------------------
void MergeList_L(LinkList &La, LinkList &Lb, LinkList &Lc) {// 算法2.12// 已知单链线性表La和Lb的元素按值非递减排列。// 归并La和Lb得到新的单链线性表Lc&#xff0c;Lc的元素也按值非递减排列。
LinkList pa, pb, pc;pa &#61; La->next; pb &#61; Lb->next;Lc &#61; pc &#61; La; // 用La的头结点作为Lc的头结点while (pa && pb) {if (pa->data <&#61; pb->data) {pc->next &#61; pa; pc &#61; pa; pa &#61; pa->next;}else { pc->next &#61; pb; pc &#61; pb; pb &#61; pb->next; }}pc->next &#61; pa ? pa : pb; // 插入剩余段free(Lb); // 释放Lb的头结点
} // MergeList_L
//--------------线性表的静态单链表存储结构------------------------
#define MAXSIZE 100
typedef struct
{ElemType data; //数据域int cur; //游标域&#xff0c;指示下一个元素在数组中的位置
}component&#xff0c;StaticList[MaxSize];
静态链表是借助一维数组来描述链表。数组中的一个分量表示一个结点&#xff0c;同时使用游标(cur)代替指针以指示结点在数组中的相对位置&#xff08;游标为-1时表示相对应的结点为空&#xff09;.数组中的0分量可以看成头结点&#xff0c;其指针域指示静态链表的第一个结点&#xff0c;并将最后一个元素的指针域0构成循环结构
这种存储结构需预先分配一个较大空间&#xff0c;但是在进行线性表插入和删除操作时不需移动元素&#xff0c;仅需要修改“指针”&#xff0c;因此仍然具有链式存储结构的主要优点。
对于静态链表的初始化&#xff0c;一定要将其它没有元素的结点的.next设为-1&#xff0c;并将下标为[0].next设为0
对于静态链表可视为一个带头节点的循环链表&#xff0c;_StaticList[0]为其头结点&#xff0c;对于插入操作一般都先查找到前一个结点(前插),另对于新的插入项一定要存在下.next为-1的位置上。
另对于删除时要考虑链表是否为空表&#xff0c;对于插入要考虑是否表满
同样静态也有不带头节点的&#xff0c;类似于不带头节点的循环链表
同样可以构造类似于循环双链表的静态链表
等等总之灵活多样但一般不存在单链表式的静态链表
双链表
双链表的创建与单链表相似&#xff0c;只不过每个结点多了个PRIOR指针域
typedef struct DLNode{ElemType data;struct DLNode *prior;struct DLNode *next;
}DLNode, *DuLinkList;
双链表亦可分头插和尾插
特点(对称性)&#xff1a;
p->next->prior &#61; p;
p->prior->next &#61; p;
//-------------在带头结点的双链循环线性表L的第i个元素之前插入元素e--------------
Status ListInsert_DuL(DuLinkList &L, int i, ElemType e) { //算法2.18// 在带头结点的双链循环线性表L的第i个元素之前插入元素e&#xff0c;// i的合法值为1≤i≤表长&#43;1。
DuLinkList p,s;if (!(p &#61; GetElemP_DuL(L, i))) // 在L中确定第i个元素的位置指针preturn ERROR; // p&#61;NULL, 即第i个元素不存在if (!(s &#61; (DuLinkList)malloc(sizeof(DuLNode))))return ERROR;s->data &#61; e;s->prior &#61; p->prior;p->prior->next &#61; s;s->next &#61; p;p->prior &#61; s;return OK;
} // ListInsert_DuL
//--------------删除带头结点的双链循环线性表L的第i个元素-----------------
Status ListDelete_DuL(DuLinkList &L, int i, ElemType &e) {//算法2.19// 删除带头结点的双链循环线性表L的第i个元素&#xff0c;i的合法值为1≤i≤表长
DuLinkList p;if (!(p &#61; GetElemP_DuL(L, i))) // 在L中确定第i个元素的位置指针preturn ERROR; // p&#61;NULL, 即第i个元素不存在e &#61; p->data;p->prior->next &#61; p->next;p->next->prior &#61; p->prior;free(p); return OK;
} // ListDelete_DuL
循环链表
分为带头结点的循环单链表和循环双链表。
其判断结尾条件是&#xff1a;p->next &#61;&#61; L(头结点)
因此头结点也连在整个循环链表中
针对于其初始化&#xff1a;
L->prior &#61; L;
L->next &#61; L;
一般为解决特殊问题还存在不带头结点的循环单链表和循环双链表(如约瑟夫环)
--------------------------------------------------------------------------------
一元多项式的表示及相加
//-------输入m项的系数和指数&#xff0c;建立表示一元多项式的有序链表P------------
void CreatPolyn(PLinkList &P, int m) { // 算法2.22// 输入m项的系数和指数&#xff0c;建立表示一元多项式的有序链表P
PLink h, q, s;PElemType e;int i;InitList(P); h &#61; GetHead(P);e.coef &#61; 0.0; e.expn &#61; -1;SetCurElem(h, e); // 设置头结点for (i&#61;1; i<&#61;m; &#43;&#43;i) { // 依次输入m个非零项// scanf ("%f,%d\n",&e.coef, &e.expn);e.coef &#61; (float)(random(1, 90) &#43; random(10)/10.0);if (random(2)) e.coef &#61; -e.coef;e.expn&#61;e.expn&#43;random(1,10); //产生随机的数据&#xff0c;但是expn值是递增的if (!LocateElem(P, e, q, cmp)) { // 当前链表中不存在该指数项if (MakeNode(s,e)) InsFirst(q, s); // 生成结点并插入链表if(q&#61;&#61;P.tail) P.tail&#61;s;} else i--; // 如果没有产生插入&#xff0c;则将i值减1
}
} // CreatPolyn
//---------打印输出一元多项式---------------
Status PrintfPoly(PLinkList P) {int i&#61;0;PLink q&#61;P.head->next;while (q) {if (fabs(q->data.coef) > 0.005) {if (i>0) {if (q->data.coef>0.005) printf(" &#43; ");else printf(" - ");printf("%.2f", fabs(q->data.coef));} else printf("%.2f", q->data.coef);if (q->data.expn>&#61;1) printf("x");if (q->data.expn>1) printf("^%d", q->data.expn);}q&#61;q->next;if (&#43;&#43;i % 6 &#61;&#61; 0) printf("\n ");}printf("\n");return OK;
}
//-------------多项式加法-----------------
void AddPolyn(PLinkList &Pa, PLinkList &Pb) { // 算法2.23// 多项式加法&#xff1a;Pa &#61; Pa&#xff0b;Pb&#xff0c;利用两个多项式的结点构成"和多项式"。
PLink ha,hb,qa,qb;PElemType a, b, temp;float sum;ha &#61; GetHead(Pa); // ha和hb分别指向Pa和Pb的头结点hb &#61; GetHead(Pb);qa &#61; NextPos(Pa,ha); // qa和qb分别指向La和Lb中当前结点qb &#61; NextPos(Pb,hb);while (qa && qb) { // Pa和Pb均非空a &#61; GetCurElem (qa); // a和b为两表中当前比较元素b &#61; GetCurElem (qb);switch (Compare(a,b)) {case -1: // 多项式PA中当前结点的指数值小ha &#61; qa;qa &#61; NextPos (Pa, qa);break; case 0: // 两者的指数值相等sum &#61; a.coef &#43; b.coef ;if (sum !&#61; 0.0) { // 修改多项式PA中当前结点的系数值temp.coef&#61;sum;temp.expn&#61;a.expn;SetCurElem(qa, temp) ;ha &#61; qa;} else { // 删除多项式PA中当前结点
DelFirst(ha, qa);FreeNode(qa);}DelFirst(hb, qb);FreeNode(qb);qb &#61; NextPos(Pb, hb);qa &#61; NextPos(Pa, ha);break;case 1: // 多项式PB中当前结点的指数值小
DelFirst(hb, qb);InsFirst(ha, qb); qb &#61; NextPos(Pb, hb);ha &#61; NextPos(Pa, ha);break;} // switch} // whileif (!Empty(Pb)) Append(Pa, qb); // 链接Pb中剩余结点FreeNode(hb); // 释放Pb的头结点
} // AddPolyn
数据结构实验——线性表&#xff0c;链表
----------------------------
http://pan.baidu.com/share/link?shareid&#61;2216128142&uk&#61;186843953
源文件&#xff0c;实验报告分享。