一、链表的概念
链表:是用一组地址任意的存储单元存放线性表的各个数据元素,通过保存直接后继的存储位置来表示元素之间的逻辑关系;
结点:是链表的基本存储单位,每个结点在链表中使用一块连续的存储空间,而相邻结点之间不必使用连续的存储空间;
结点由数据域和指针域构成。
表中所有的数据元素都分别保存在具有相同数据结构的结点中,结点与数据元素是一一对应。
头指针:以线性表中第一个数据元素的存储地址作为线性表的地址,称作线性表的头指针。
头结点:有时为了操作方便,在第一个结点之前虚加一个“头结点”,不存放数据元素,以指向头结点的指针为链表的头指针。
二、单链表
单链表的节点定义:
typedef int elemtype; typedef struct LNode { elemtype data; struct LNode *next; }LinkList,*pLinkList;
|
(一)带头结点的单链表
头结点的数据域可以不存任何信息,也可根据需要存储线性表的长度等附加信息;
头结点的指针域指向第一个结点(第一个元素的存储位置);
单链表的头指针指向头结点;
若单链表为空,则头结点的指针域为“空”。
带头结点的单链表的基本操作:
#include<stdio.h> #include<stdlib.h> //单链表存储结构(一个节点的结构)
typedef int elemtype; typedef enum { OK, //0
TRUE, //1
FALSE, //2
ERROR, //3
OVERFLOW//4
}Status;
typedef struct LNode { elemtype data; struct LNode *next; }LinkList,*pLinkList;
/*带头节点的单链表初始化*/ void InitList(pLinkList L) { L=(pLinkList)malloc(sizeof(elemtype)); if(!L) exit(OVERFLOW); L->next = NULL; }
/*销毁带头节点的单链表*/ void DestroyList(pLinkList L) { pLinkList q; while(L)//直到L=NULL
{ q = L->next; free(L); L = q; } }
/*将带头结点的单链表重置为空表,只留一个头结点*/ void ClearList(pLinkList L) { pLinkList p = L->next; L->next = NULL; DestroyList(p); }
/*判断带头结点的单链表是否为空表,是返回TRUE,否返回FALSE*/ Status ListEmpty(pLinkList L) { if(L->next) return FALSE; else return TRUE; }
/*返回带头节点单链表中数据元素的个数*/ int ListLength(pLinkList L) { int i=0; pLinkList p; p = L->next; while(p) { i++; p = p->next; } return i; }
/*当第i个元素存在时,从带头结点的单链表中返回第i个元素到e中,并返回ok,否则返回error*/ Status GetElem(pLinkList L,int i,elemtype *e) { int j = 1; pLinkList p = L->next; while(p && i>j)//P指向第i个元素的位置
{ j++; p = p->next; } if(!p || j>i)//i大于表长或i<1;
return ERROR; *e = p->data; return OK; }
/*在带头结点的单链表中的第i个位置之前插入元素e*/ Status ListInsert(pLinkList L,int i,elemtype e) { int j = 0;//计数器
pLinkList s,p = L;//p指向表头
while(p && j<i-1)//由于是单向链表,必须先寻找到i-1个位置
{ j++; p = p->next; } if(!p || j>i-1)//i大于(表长+1)或小于1
return ERROR; s = (pLinkList)malloc(sizeof(LinkList)); s->data = e; s->next = p->next; p->next = s; return OK; }
/*从带头节点的单链表中,删除第i个元素,并由e返回其值*/ Status ListDelete(pLinkList L,int i,elemtype *e) { int j = 0; pLinkList s,p = L; while(p->next && j<i-1) //p指向第i-1个位置
{ j++; p = p->next; } if(!(p->next) || j>i-1) return ERROR; s = p->next; p->next = s->next; *e = s->data; free(s); return OK; }
/*若cur_e是带头结点单链表内的数据元素,且不是第一个,则用pre_e返回它的前驱*/ Status PriorElem(pLinkList L,elemtype cur_e,elemtype *pre_e) { pLinkList q,p=L->next; while(p->next) { q = p->next; if(q->data == cur_e) { *pre_e = p->data; return OK; } p = q; } return OK; }
/*若cur_e是带头结点单链表内的数据元素,且不是最后一个,则用next_e返回他的后继*/ Status NextElem(pLinkList L,elemtype cur_e,elemtype *next_e) { pLinkList p=L->next; while(p->next) { if(p->data == cur_e) { *next_e = p->next->data; return OK; } p = p->next; } return ERROR; }
/*返回带头结点的单链表内第一个与e满足compare()关系的数据元素的的为序*/ int LocateElem(pLinkList L,elemtype e,Status(*compare)(elemtype,elemtype)) { int i=0; pLinkList p = L->next; while(p) { i++; if(compare(p->data,e)) return i; p = p->next; } return -1; }
/*依次对带头结点单链表中的每一个元素数据调用visit()函数*/ void ListTraverse(pLinkList L,void(*visit)(elemtype *)) { pLinkList p = L->next; while(p) { visit(&(p->data)); p = p->next; } }
|
其他操作:
/*用键盘输入N个元素,从表头插入这N个元素(逆位序),建立带头结点的单链表*/ void CreateList(pLinkList L,int n) { int i; pLinkList p; L=(pLinkList)malloc(sizeof(LinkList)); L->next = NULL; printf("请输入%d个数据\n",n); for(i=0;i<n;i++) { p=(pLinkList)malloc(sizeof(LinkList)); scanf("%d",&p->data); p->next = L->next; L->next = p; } }
/*用键盘输入N个元素,从表尾插入这N个元素(正位序),建立带头节点的单链表*/ void CreateList1(pLinkList L,int n) { int i; pLinkList p,q; L=(pLinkList)malloc(sizeof(LinkList)); L->next = NULL; q = L; printf("请输入%d个数据\n",n); for(i=0;i<n;i++) { p=(pLinkList)malloc(sizeof(LinkList)); scanf("%d",&p->data); q->next = p; q = p; } p->next = NULL; }
/*带头结点单链表的归并 单链线性表La和Lb的元素按值非递减排列 归并La和Lb得到新单链表Lc,其元素也按值非递减排列 摧毁了La,Lb,得到了Lc */ void MergeList_L(LinkList*La, LinkList*Lb, LinkList*Lc) { pLinkList pa=La->next,pb=Lb->next,pc; //pa、pb指向表A、B的第一个结点
Lc=pc=La; //用La的头结点作为Lc的头结点
while(pa && pb) { if (pa->data<=pb->data) { pc->next=pa; pc=pa; pa=pa->next; } else { pc->next=pb; pc=pb; pb=pb->next; } }//循环退出时一个单链表已经归并完
pc->next=pa?pa:pb; //插入剩余段
free(Lb); //释放Lb的头结点
Lb = NULL; //Lb不再指向任何节点
}
|
转载于:https://blog.51cto.com/lhqvip/543323