线性表List
说明
本系列文章用于简明的记录数据结构基础知识点,以方便快速地温故知新。有时间,将会整理相关的C++和C语言下的实现程序和相关应用的记录。
总览
链表
链表三类型
- Simple Linked List −单链表,单向链表
- Doubly Linked List − 双向链表
- Circular Linked List − 循环链表
Simple Linked List
单链表可视化如下一个节点链,其中每个节点指向下一个节点。
如上图所示,以下是三个要点:
链表包含一个最开始的链接元素称为head(表头节点)。(思考:为什么要增加表头节点?)
节点含有两个域:数据域和指针域(指向下一个节点)。
- 最后一个节点指向NULL,以表示结束。
C++实现思路
链表是由节点node组成,所以基本元素是节点(node)。
第一步,我们先定义一个节点类Link,作为基础,而从上面我知道节点包含两个域,则节点类Link的数据成员包含,存储数据的element,和指向下一个节点的指针next。
第二步,定义链表LList类,数据成员包含节点类Link。成员函数包含基本的insert和remove操作等。
C实现思路
第一步,我们先定义一个节点结构struct node,和上面一样,数据成员包含,存储数据的element,和指向下一个节点的指针next。
然后,使用struct node为基础,构建一个链表。
struct Node;
typedef struct Node *PtrToNode;
typedef PtrToNode List;
typedef PtrToNode Position;
struct Node
{
ElementType Element;
Position Next;
};
基本操作
两大重要操作:insert和remove操作。
insert
想象一下,我们插入一个节点(NewNode)在A (LeftNode) 和C (RightNode)节点之间:
C语言实现版本:Insert函数在链表L元素P之后插入新元素X
void Insert( ElementType X, List L, Position P )
{
Position TmpCell;
/* 1*/ TmpCell = malloc( sizeof( struct Node ) );
/* 2*/ if( TmpCell == NULL )
/* 3*/ FatalError( "Out of space!!!" );
/* 4*/ TmpCell->Element = X;
/* 5*/ TmpCell->Next = P->Next;
/* 6*/ P->Next = TmpCell;
}
/* END */
remove
我们插入一个节点(TaegetNode)在A (LeftNode) 和C (RightNode)节点之间:
链表C语言实现的完整程序例子
下面是list.h
文件:
typedef int ElementType;
/* START: fig3_6.txt */
#ifndef _List_H
#define _List_H
struct Node;
typedef struct Node *PtrToNode;
typedef PtrToNode List;
typedef PtrToNode Position;
List MakeEmpty( List L );
int IsEmpty( List L );
int IsLast( Position P, List L );
Position Find( ElementType X, List L );
void Delete( ElementType X, List L );
Position FindPrevious( ElementType X, List L );
void Insert( ElementType X, List L, Position P );
void DeleteList( List L );
Position Header( List L );
Position First( List L );
Position Advance( Position P );
ElementType Retrieve( Position P );
#endif /* _List_H */
/* END */
下面是list.c
文件:
#include "list.h"
#include <stdlib.h>
#include "fatal.h"
/* Place in the interface file */
struct Node
{
ElementType Element;
Position Next;
};
List
MakeEmpty( List L )
{
if( L != NULL )
DeleteList( L );
L = malloc( sizeof( struct Node ) );
if( L == NULL )
FatalError( "Out of memory!" );
L->Next = NULL;
return L;
}
/* START: fig3_8.txt */
/* Return true if L is empty */
int
IsEmpty( List L )
{
return L->Next == NULL;
}
/* END */
/* START: fig3_9.txt */
/* Return true if P is the last position in list L */
/* Parameter L is unused in this implementation */
int IsLast( Position P, List L )
{
return P->Next == NULL;
}
/* END */
/* START: fig3_10.txt */
/* Return Position of X in L; NULL if not found */
Position
Find( ElementType X, List L )
{
Position P;
/* 1*/ P = L->Next;
/* 2*/ while( P != NULL && P->Element != X )
/* 3*/ P = P->Next;
/* 4*/ return P;
}
/* END */
/* START: fig3_11.txt */
/* Delete from a list */
/* Cell pointed to by P->Next is wiped out */
/* Assume that the position is legal */
/* Assume use of a header node */
void
Delete( ElementType X, List L )
{
Position P, TmpCell;
P = FindPrevious( X, L );
if( !IsLast( P, L ) ) /* Assumption of header use */
{ /* X is found; delete it */
TmpCell = P->Next;
P->Next = TmpCell->Next; /* Bypass deleted cell */
free( TmpCell );
}
}
/* END */
/* START: fig3_12.txt */
/* If X is not found, then Next field of returned value is NULL */
/* Assumes a header */
Position
FindPrevious( ElementType X, List L )
{
Position P;
/* 1*/ P = L;
/* 2*/ while( P->Next != NULL && P->Next->Element != X )
/* 3*/ P = P->Next;
/* 4*/ return P;
}
/* END */
/* START: fig3_13.txt */
/* Insert (after legal position P) */
/* Header implementation assumed */
/* Parameter L is unused in this implementation */
void
Insert( ElementType X, List L, Position P )
{
Position TmpCell;
/* 1*/ TmpCell = malloc( sizeof( struct Node ) );
/* 2*/ if( TmpCell == NULL )
/* 3*/ FatalError( "Out of space!!!" );
/* 4*/ TmpCell->Element = X;
/* 5*/ TmpCell->Next = P->Next;
/* 6*/ P->Next = TmpCell;
}
/* END */
#if 0
/* START: fig3_14.txt */
/* Incorrect DeleteList algorithm */
void
DeleteList( List L )
{
Position P;
/* 1*/ P = L->Next; /* Header assumed */
/* 2*/ L->Next = NULL;
/* 3*/ while( P != NULL )
{
/* 4*/ free( P );
/* 5*/ P = P->Next;
}
}
/* END */
#endif
/* START: fig3_15.txt */
/* Correct DeleteList algorithm */
void
DeleteList( List L )
{
Position P, Tmp;
/* 1*/ P = L->Next; /* Header assumed */
/* 2*/ L->Next = NULL;
/* 3*/ while( P != NULL )
{
/* 4*/ Tmp = P->Next;
/* 5*/ free( P );
/* 6*/ P = Tmp;
}
}
/* END */
Position
Header( List L )
{
return L;
}
Position
First( List L )
{
return L->Next;
}
Position
Advance( Position P )
{
return P->Next;
}
ElementType
Retrieve( Position P )
{
return P->Element;
}
下面的程序将对其进行测试:
#include <stdio.h>
#include "list.h"
void
PrintList( const List L )
{
Position P = Header( L );
if( IsEmpty( L ) )
printf( "Empty list\n" );
else
{
do
{
P = Advance( P );
printf( "%d ", Retrieve( P ) );
} while( !IsLast( P, L ) );
printf( "\n" );
}
}
main( )
{
List L;
Position P;
int i;
L = MakeEmpty( NULL );
P = Header( L );
PrintList( L );
for( i = 0; i < 10; i++ )
{
Insert( i, L, P );
PrintList( L );
P = Advance( P );
}
for( i = 0; i < 10; i+= 2 )
Delete( i, L );
for( i = 0; i < 10; i++ )
if( ( i % 2 == 0 ) == ( Find( i, L ) != NULL ) )
printf( "Find fails\n" );
printf( "Finished deletions\n" );
PrintList( L );
DeleteList( L );
return 0;
}