关于线性链表的一些操作

    线性链表是数据结构中的第一个概念, 也是最基本的概念。如果对线性链表的操作不熟悉,就说明你对指针、算法等不甚了解,或者说对C语言的精髓、算法的初步都未入门。下文给出的一个线性表的示例,给大家演示线性表的操作,让大家熟悉对指针、链表的操作。该程序中大部分的代码都是标准操作,各种数据结构相关的教科书中都有,不过采用的不一定是C语言而已,但不是很难,所以不加任何介绍,只是在程序中给出响应的注释。不过有一段特别的代码,就是将链表倒置的代码

void  List_Reverse(List L)

    该函数的功能就是将线性表倒置。大家别小看这么一个操作,如果是顺序表(数组),这个操作是相当简单的,但是对于链表,可得想好了,否则,上机调试越调越乱〔其实所有的链表操作都是如此,如果事先没有想好就上机,除了浪费时间好像没有多大的意义〕。当然链表倒置操作方法不止一种,我们在此采用一个类似递归的的思想(别看见递归就头疼,你当我没说过递归)。

    链表倒置,我们将链表看做两个表,LA和LB。其中LA是原表,LB是已经将LA前面的一部分已经倒置的线性表。我们操作的过程用语言描述就是一句话:将LA的第一个结点插入到LB的最前面。所以操作过程分开写就是:
1) 将LA指向当第一个结点插入到LB的第一个结点
2) 将LB指向刚插入的结点
3)  LA后移动一个
    这样循环操作直至LA指向空

    当然实际操作中考虑到是否有头结点(程序中是使用头结点的),我们把原代码贴出来,然后逐一解释

void  List_Reverse(List L)
{
    List p 
= L, q = L->
next;
    
while (q != NULL)    
{
        L
->next = q->
next;
        q
->next =
 p;
        
if (q->next ==
 L)
            q
->next =
 NULL;
        p 
=
 q;
        q 
= L->
next;
    }

    L
->next = p;
}

p=L, q=L->next;   该操作是相当于q为LA,p为LB;
while(q!=NULL) 表示当LA不为空,也就是还有有效结点时继续循环
    L->next = q->next; 将q的下一个结点插入到L的第一个结点(第0个为头结点)
    q->next = p; 重新接好链表(否则链表就断了)
    if(q->next==L)  q->next = NULL; 不用看,这肯定是放在最后的,实际上也就是插入的第一个结点后要将“下一位”赋空,否则会死得很惨的。
    p = q; 
    q = L->next; 重新赋值,也就是保证q总是在最开始,q是新表的第一个结点
我们可以看下图

下面是程序代码,以及运行结果

#include  < string .h >
#include 
< malloc.h >

#pragma  once
#define  MAXINFOLEN 128

typedef 
struct  _ElemType {
    
int  m_nKey; // 关键字
    char m_sInfo[MAXINFOLEN]; // 消息
}
 ElemType;
void  Elem_Print(ElemType  * e);


//  Houjian TANG @ 20070330
typedef  struct  _NodeType
{
    ElemType 
*elem;  // 节点元素指针
    struct _NodeType *next; // 下一个节点
}
 NodeType,  * List;

typedef 
int  ( * COMPARE)(ElemType  * e1, ElemType  * e2);

int  compare_key(ElemType  * e1, ElemType  * e2);
int  compare_info(ElemType  * e1, ElemType  * e2);



//  打印一个节点
void  LNode_Print(NodeType  * e);
//  打印一个链表
void  List_Print(List L);
//  初始化一个带头结点的链表,返回链表的头
List List_Init();
//  将元素e插入到链表L的pos位置处,如果pos<0或非常大,则插入到最后
void  List_Insert(List  L,  int  pos, ElemType  * e);
//  删除链表L的pos处的节点,如果pos值非常大或者pos<0,返回失败
//  删除成功返回true,并将被删除的元素放到e指向的单元中(e!=NULL)
bool  List_Delete(List L,  int  pos, ElemType  * e);
int   List_Locate(List L, COMPARE compare, ElemType  * e);
List List_GetNode(List L, 
int  pos);
bool  List_Delete(List L,  int  pos, ElemType  * e);
void  List_Destroy(List L);
void  List_Reverse(List L);
void  List_Test();

int  main()
{
    List_Test();
    
return 0;
}



void  List_Test()
{
    List L;
    ElemType e;
    
int i = 0;

    L 
= List_Init();
    
// 建立5个节点的链表
    printf("Create a link with 5 nodes: ");
    
for (i=0; i<5; i++)    {
        e.m_nKey 
= i;
        sprintf(e.m_sInfo, 
"Elem Node %d", i);
        List_Insert(L, i, 
&e);
    }

    List_Print(L);

    printf(
"Reverse this link: ");
    List_Reverse(L);
    List_Print(L);

    printf(
"Call Search(e.m_nKey==3): ");
    e.m_nKey 
= 3;
    i 
= List_Locate(L, compare_key, &e);
    
if (i >= 0)    {
        printf(
"founded! p = ");
        LNode_Print(List_GetNode(L, i));
        printf(
" ");
        printf(
"Delete this node: ");
        List_Delete(L, i, 
&e);
        List_Print(L);
    }

    
else    {
        printf(
"Not founded! ");
    }


    printf(
"Call Search(e.m_sInfo=='Elem Node 4'): ");
    sprintf(e.m_sInfo, 
"Elem Node 4");
    i 
= List_Locate(L, compare_info, &e);
    
if (i >= 0)    {
        printf(
"founded! p = ");
        LNode_Print(List_GetNode(L, i));
        printf(
" ");
        printf(
"Delete this node: ");
        List_Delete(L, i, 
&e);
        List_Print(L);
    }

    
else    {
        printf(
"Not founded! ");
    }


    e.m_nKey 
= 30;
    sprintf(e.m_sInfo, 
"an other node");
    printf(
"Insert a node = (%d, '%s') ",
        e.m_nKey, e.m_sInfo);
    List_Insert(L, 
2&e);
    List_Print(L);

    List_Destroy(L);
}



void  LNode_Print(NodeType  * e)
{
    printf(
"{%pH:  || e=", e);
    Elem_Print(e
->elem);
    printf(
"] next->%pH)", e->next);
}


void  List_Print(List L)
{
    printf(
"// ------------------------------ ");
    
while ((L = L->next) != NULL)    {
        LNode_Print(L);
        printf(
" ");
    }

    printf(
"------------------------------ // ");
}


//  分配头节点
List List_Init()
{
    List L 
= (NodeType *)malloc(sizeof(NodeType));
    L
->next = NULL;
    L
->elem = (ElemType *)malloc(sizeof(ElemType));
    
// L->elem = NULL;
    
//L->elem->m_nKey = 0;
    
//L->elem->m_sInfo[0] = 0;
    return L;
}


void  List_Insert(List L,  int  pos, ElemType  * e)
{
    List p 
= L, lTmp;
    
int i;

    
// 如果是负数,则插入到最后
    if (pos < 0{
        
while (p->next != NULL)  // 该循环是将tail指向列表的末尾
            p = p->next;
    }

    
// 查找的pos个位置
    for (i=0; i<pos; i++)    {
        
if (p->next == NULL) // 如果已经到了末尾,就不继续了
            break;
        p 
= p->next;
    }

    
// 先申请链表结点
    lTmp = (NodeType *)malloc(sizeof(NodeType));
    
// 再分配链表结点的内容
    lTmp->elem = (ElemType *)malloc(sizeof(ElemType));
    
*(lTmp->elem) = *e;

    
// 注意下面这两行,实现了链表的连接
    lTmp->next = p->next; 
    p
->next = lTmp;
}


bool  List_Delete(List L,  int  pos, ElemType  * e)
{
    List p 
= L, q = NULL;
    
int i = 0;
    
if (pos < 0)
        
return false;
    
for (i=0; i<pos; i++){
        
if (p->next->next == NULL)
            
return false;
        p 
= p->next;
    }


    
// 下面这两句是去掉q所指向的元素
    q = p->next;
    p
->next = q->next;
    
if (e != NULL)
        
*= *(q->elem);

    
// 注意一定要释放
    free(q->elem);
    q
->next = NULL;
    q
->elem = NULL;
    free(q);
    
return true;
}


void  List_Destroy(List L)
{
    List p 
= L;
    
while (L != NULL) {
        p 
= L;
        L 
= L->next;
        free(p
->elem);
        p
->next = NULL;
        p
->elem = NULL;
        free(p);
    }

}


int  List_Locate(List L, COMPARE compare, ElemType  * e)
{
    
int i = 0;
    L 
= L->next;
    
while (L != NULL)    {
        
if (compare(L->elem, e) == 0)
            
return i;
        L 
= L->next;
        i 
++;
    }

    
return -1;
}



void  Elem_Print(ElemType  * e)
{
    printf(
"{%03d: '%s'}", e->m_nKey, e->m_sInfo);
}



List List_GetNode(List L, 
int  pos)
{
    L 
= L->next;
    
while (L != NULL)    {
        pos 
--;
        
if (pos < 0)
            
return L;
        L 
= L->next;
    }

    
return NULL;
}


void  List_Reverse(List L)
{
    List p 
= L, q = L->next;
    
while (q != NULL)    {
        L
->next = q->next;
        q
->next = p;
        
if (q->next == L)
            q
->next = NULL;
        p 
= q;
        q 
= L->next;
    }

    L
->next = p;
}


int  compare_key(ElemType  * e1, ElemType  * e2)
{
    
return e1->m_nKey - e2->m_nKey;
}

int  compare_info(ElemType  * e1, ElemType  * e2)
{
    
return strcmp(e1->m_sInfo, e2->m_sInfo);
}



/*
运行结果:
// ------------------------------
{0x4F1EF0: elem={0: 'Elem Node 0'}, next=0x4F1E00}
{0x4F1E00: elem={1: 'Elem Node 1'}, next=0x4F1D10}
{0x4F1D10: elem={2: 'Elem Node 2'}, next=0x4F1C20}
{0x4F1C20: elem={3: 'Elem Node 3'}, next=0x4F1B30}
{0x4F1B30: elem={4: 'Elem Node 4'}, next=0x0}
------------------------------ //
// ------------------------------
{0x4F1B30: elem={4: 'Elem Node 4'}, next=0x4F1C20}
{0x4F1C20: elem={3: 'Elem Node 3'}, next=0x4F1D10}
{0x4F1D10: elem={2: 'Elem Node 2'}, next=0x4F1E00}
{0x4F1E00: elem={1: 'Elem Node 1'}, next=0x4F1EF0}
{0x4F1EF0: elem={0: 'Elem Node 0'}, next=0x0}
------------------------------ //
founded!
p = {0x4F1C20: elem={3: 'Elem Node 3'}, next=0x4F1D10}
// ------------------------------
{0x4F1B30: elem={4: 'Elem Node 4'}, next=0x4F1D10}
{0x4F1D10: elem={2: 'Elem Node 2'}, next=0x4F1E00}
{0x4F1E00: elem={1: 'Elem Node 1'}, next=0x4F1EF0}
{0x4F1EF0: elem={0: 'Elem Node 0'}, next=0x0}
------------------------------ //
--------------------------------
{0: 'ElemType 0'}
{1: 'ElemType 1'}
{2: 'ElemType 2'}
{3: 'ElemType 3'}
{4: 'ElemType 4'}
{5: 'ElemType 5'}
{6: 'ElemType 6'}
{7: 'ElemType 7'}
{8: 'ElemType 8'}
{9: 'ElemType 9'}
--------------------------------
{9: 'ElemType 9'}
{8: 'ElemType 8'}
{7: 'ElemType 7'}
{6: 'ElemType 6'}
{5: 'ElemType 5'}
{4: 'ElemType 4'}
{3: 'ElemType 3'}
{2: 'ElemType 2'}
{1: 'ElemType 1'}
{0: 'ElemType 0'}
Found! ElemType is : {6: 'ElemType 6'}


*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值