链表分类:按是否包含指向前继的指针可分为单链表和双向链表;按是否成环状可以分为循环链表和非循环链表。
由于连表示离散的分布在存储空间的,因此链表是非随机存取的,只能从某个特定节点开始遍历一次查找。
通常为方便操作,在链表第一个节点前附加一个头节点,头节点的指针与指向链表的第一个元素节点。
每个结构含有表元素和指向包含该元素后继的结构的指针。除了头节点,每一个结点都有唯一的前继。除最后一个结点,每一个结点都有一个后继。
插入:
删除:
struct LNode {
ElementType e;
PtrToLNode Next;
};
typedef struct LNode *PtrToLNode;
typedef PtrToLNode List;
List List_Init(void)
{
List L = (List)malloc(sizeof(LNode));
L->Next = NULL;
return L;
}
int List_IsEmpty(List L)
{
if (L->Next = NULL)
return 1;
else
return 0;
}
void List_Print(List L)
{
PtrToLNode p = L->Next;
while (p){
printf("%d\t", p->e);
p = p->Next;
}
printf("\n");
}
void List_Pre_Create(List L)//头插法建立单链表
{
ElementType x;
scanf("%d", &x);
while (x != 9999) {
PtrToLNode p = (PtrToLNode)malloc(sizeof(LNode));
p->e = x;
p->Next = L->Next;
L->Next = p;
scanf("%d", &x);
}
}
void List_Post_Create(List L)//尾差法建立单链表
{
ElementType x;
PtrToLNode p, r = L;
scanf("%d", &x);
while (x != 9999) {
p = (PtrToLNode)malloc(sizeof(LNode));
p->e = x;
r->Next = p;
r = p;
scanf("%d", &x);
}
r->Next = NULL;
}
PtrToLNode List_FindPre(List L, PtrToLNode r)//返回结点r的直接前继
{
PtrToLNode pre = L, p = pre->Next;
while (p != r) {
pre = p;
p = p->Next;
}
return pre;
}
int List_Length(List L)//求链表长度
{
int Length = 0;
PtrToLNode p = L->Next;
while (p) {
++Length;
p = p->Next;
}
return Length;
}
void List_Insert(List L, Position p, ElementType x)//在结点p处插入新节点
{
PtrToLNode pre = List_FindPre(L, p), s;
s = (PtrToLNode)malloc(sizeof(LNode));
s->e = x;
s->Next = p;
pre->Next = s;
}
PtrToLNode List_FindMid(List L)//返回中间元素结点
{
PtrToLNode p, r;
p = r = L->Next;
while (r->Next != NULL && r->Next->Next != NULL){
p = p->Next;
r = r->Next->Next;
}
printf("%d\n", p->e);
return p;
}
void List_Delete(List L, ElementType x)//删除节点
{
PtrToLNode pre = L, p = L->Next, temp;
while (p){
if (p->e != x) {
pre = p;
p = p->Next;
}
else{
temp = p->Next;
pre->Next = temp;
free(p);
p = temp;
}
}
}
void List_DeleteRepeat(List L)//删除有序链表中重复元素的结点
{
PtrToLNode pre = L->Next, p = pre->Next, temp;
while (p){
if (pre->e == p->e) {
temp = p->Next;
pre->Next = temp;
free(p);
p = temp;
}
else {
pre = p;
p = p->Next;
}
}
}
PtrToLNode List_Last_K(List L, int k)//返回倒数第K个结点
{
PtrToLNode p, r;
p = r = L;
if (k > List_Length(L)) {
printf("The k is Bigger Than L's Length!\n");
return NULL;
}
for (int i = 0; i < k; ++i)
r = r->Next;
while (r){
r = r->Next;
p = p->Next;
}
printf("%d\n", p->e);
return p;
}
/*若两单链表有公共结点,则从起始公共结点至尾结点两者均相同,因此将两链表尾部对齐,开始比较第一个相同结点即为起始公共结点*/
PtrToLNode List_CommonNode(List L1, List L2)//返回两单链表的公共起始节点
{
int Length1, Length2, dist;
PtrToLNode longlist, shortlist;
Length1 = List_Length(L1);
Length2 = List_Length(L2);
if (Length1 > Length2) {
longlist = L1->Next;
shortlist = L2->Next;
dist = Length1 - Length2;
}
else {
longlist = L2->Next;
shortlist = L1->Next;
dist = Length2 - Length1;
}
while (dist--)
longlist = longlist->Next;
while(longlist && longlist->e != shortlist->e){
longlist = longlist->Next;
shortlist = shortlist->Next;
}
PtrToLNode p = longlist;
while (p) {
printf("%d\n", p->e);
p = p->Next;
}
return longlist;
}
void List_Reverse(List L)//
{
PtrToLNode pre, p, r;
pre = L;
p = pre->Next;
r = p->Next;
p->Next = NULL;//将逆置后的p将成为尾结点,将其指针域置空
while (r) {
pre = p;
p = r;
r = r->Next;//遍历链表
p->Next = pre;//逆置
}
L->Next = p;//p结点将成为你逆置后的第一个节点,将头节点指向该节点
}
void List_Reverse1(List L)//利用头插法逆置链表 { PtrToLNode p, r; p = L->Next; L->Next = NULL; while (p) { r = p->Next; p->Next = L->Next; L->Next = p; p = r; } }
List List_Reverse1(List L, int m, int n)//逆置第m个结点至第n个结点结点 { List prefirst, first, p, r; prefirst = L; first = p = L->Next; for (int i = 1; i != m; ++i) { prefirst = p; p = p->Next; }//prefirst指向第m-1个结点 first = p;//first指向第m个结点 for (int i = m; i <= n; ++i) { r = p->Next; p->Next = prefirst->Next; prefirst->Next = p; p = r; }//利用头插法将m至n结点逆置 first->Next = p;//将first的指针域指向第n+1个结点 return L; }
双链表