链表相关

过去对于链表仅限于理论上的了解,但是对于其具体的实现没有深入学习,最近参加笔试遇到了挺多次,所以好好系统的复习下。
一、基本定义
链表是一种常见的数据结构,在内存中的存储是不连续的,常用malloc等函数动态随机分配空间,用指针相连。
链表用结构体来定义,指针部分定义为指向本结构体类型的指针类型。
每个元素包含两个部分:数据部分和指针部分。数据部分用来存放元素所包含的数据,指针部分用来指向下一个元素。最后一个元素的指针指向null,表示指向的地址为空。

二、单链表
每个结点只有一个指针指向下一个结点,末尾节点指针为空。
单链表的建立及遍历:

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
	
/*单向链表*/
struct Student/*建立学生信息结构体模型*/ 
{
    char cName[20];/*学生姓名*/
    int iNumber;/*学生学号*/
    struct student *next;/*指向本结构体类型的指针类型*/
};

int iCount;/*全局变量表示链表长度*/ 

struct Student *Create();/*创建链表函数声明*/ 
void print(struct Student *);/*遍历输出链表函数声明*/

int main()
{
    int insert_n=2;/*定义并初始化要插入的结点号*/
    int delete_n=2;/*定义并初始化要删除的结点号*/
    struct Student *pHead;/*声明一个指向学生信息结构体的指针作pHead为头结点传递*/
    pHead=Create();/*创建链表,返回链表的头指针给pHead*/
    print(pHead);/*将指针pHead传入输出函数遍历输出*/
    return 0; 
}

struct Student *Create()
{
    struct Student *pHead=NULL;/*初始化链表,头指针为空*/ 
    struct Student *pEnd,*pNew;
    iCount=0;/*初始化链表长度*/ 
    pEnd=pNew=(struct Student *)malloc(sizeof(struct Student));/*动态开辟一个学生信息结构体类型大小的空间,使得pEnd和pNew同时指向该结构体空间*/
    scanf("%s",pNew->cName);/*从输入流获取第一个学生姓名*/ 
    scanf("%d",&pNew->iNumber);/*从输入流获取第一个学生学号*/ 
    while(pNew->iNumber!=0)/*设定循环结束条件——学号不为0时*/ 
    {
        iCount++;/*链表长度+1,即学生信息个数+1*/ 
        if(iCount==1)/*如果链表长度刚刚加为1,执行*/ 
        {
            pNew->next=pHead;/*使指针指向为空*/
            pEnd=pNew;/*跟踪新加入的结点*/
            pHead=pNew;/*头结点指向首结点*/
        }
        else/*如果链表已经建立,长度大于等于2时,执行*/ 
        {
            pNew->next=NULL;/*新结点的指针为空*/
            pEnd->next=pNew;/*原来的结点指向新结点*/
            pEnd=pNew;/*pEnd指向新结点*/
        }
        pNew=(struct Student *)malloc(sizeof(struct Student));/*再次分配结点的内存空间*/
        scanf("%s",pNew->cName);/*从输入流获取第一个学生姓名*/ 
        scanf("%d",&pNew->iNumber);/*从输入流获取第一个学生学号*/ 
    }
    free(pNew);/*释放结点空间*/
    return pHead;/*返回创建出的头指针*/ 
}

void print(struct Student *pHead)
{
    struct Student *pTemp;/*定义指向一个学生信息结构体类型的临时指针*/ 
    int iIndex=1;/*定义并出事哈变量iIndex,用来标识第几个学生(信息)*/ 
    printf("总共%d个学生(信息):\n",iCount);
    pTemp=pHead;/*指针得到首结点的地址*/ 
    while(pTemp!=NULL)/*当临时指针不指向NULL时*/ 
    {
        printf("第%d个学生信息:\n",iIndex); 
        printf("姓名:%s",pTemp->cName); /*输出姓名*/
        printf("学号:%d",pTemp->iNumber);/*输出学号*/
        pTemp=pTemp->next;/*移动临时指针到下一个结点*/ 
        iIndex++;/*进行自加运算*/ 
    }
}		

主函数增加:

int main()
{
    int insert_n=2;/*定义并初始化要插入的结点号*/
    int delete_n=2;/*定义并初始化要删除的结点号*/
    struct Student *pHead;/*声明一个指向学生信息结构体的指针作pHead为头结点传递*/
    pHead=Create();/*创建链表,返回链表的头指针给pHead*/
    pHead=Insert(pHead,insert_n);/*将指针pHead和要插入的结点数传递给插入函数*/
    print(pHead);/*将指针pHead传入输出函数遍历输出*/
    Delete(pHead,delete_n);/*将指针pHead和要删除的结点数传递给删除函数*/
    print(pHead);/*将指针pHead传入输出函数遍历输出*/
    return 0; 
}

插入:

struct Student *Insert(struct Student *pHead,int number)
{
    struct Student *p=pHead,*pNew;/*定义pNew指向新分配的空间*/ 
    while(p&&p->iNumber!=number)
        p=p->next;/*使临时结点跟踪到要插入的位置(该实例必须存在学号为number的信息,插入其后,否则出错)*/ 
    printf("姓名和学号:\n");
    /*分配内存空间,返回该内存空间的地址*/ 
    pNew=(struct Student *)malloc(sizeof(struct Student));
    scanf("%s",pNew->cName);
    scanf("%d",&pNew->iNumber);
    pNew->next=p->next;/*新结点指针指向原来的结点*/
    p->next=pNew;/*头指针指向新结点*/
    iCount++;/*增加链表结点数量*/ 
    return pHead;/*返回头指针*/ 
}

删除:

void Delete(struct Student *pHead,int number)
{
    int i;
    struct Student *pTemp;/*临时指针*/ 
    struct Student *pPre;/*表示要删除结点前的结点*/ 
    pTemp=pHead;/*得到链表的头结点*/ 
    pPre=pTemp;
    for(i=0;i<number;i++)
    {/*通过for循环使得Temp指向要删除的结点*/ 
        pPre=pTemp;
        pTemp=pTemp->next; 
    }
    pPre->next=pTemp->next;/*连接删除结点两边的结点*/ 
    free(pTemp);/*释放要删除结点的内存空间*/ 
    iCount--;/*减少链表中的结点个数*/ 
}

三、双向链表
双向链表含有一个数据域和两个链域。链域分为存储直接后继结点地址的右链域,和存储直接前驱结点地址的左链域。

建立与遍历:

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define N 10

typedef struct Node
{
    char name[20];
    struct Node *llink,*rlink;
}STUD;

STUD *creat(int);void print(STUD *);

int main()
{
    int number;
    char studname[20];
    STUD *head,*searchpoint;
    number=N;
    head=creat(number);
    print(head);
    printf("请输入你要查找的人的姓名:");
    scanf("%s",studname);
    searchpoint=search(head,studname);
    printf("你所要查找的人的姓名是:%s",*&searchpoint->name); 
    return 0;
}

STUD *creat(int n)
{
    STUD *p,*h,*s;
    int i;
    if((h=(STUD *)malloc(sizeof(STUD)))==NULL)
    {
        printf("不能分配内存空间");
        exit(0);        
    }
    h->name[0]='\0';
    h->llink=NULL;
    h->rlink=NULL;
    p=h;
    for(i=0;i<n;i++)
    {
        if((s=(STUD *)malloc(sizeof(STUD)))==NULL)
        {
        printf("不能分配内存空间");
        exit(0);        
        }
        p->rlink=s;
        printf("请输入第%d个人的姓名",i+1);
        scanf("%s",s->name);
        s->llink=p;
        s->rlink=NULL;
        p=s;
    }
    h->llink=s;
    p->rlink=h;
    return(h);
}

void print(STUD *h)
{
    int n;
    STUD *p;
    p=h->rlink;
    printf("数据信息为:\n");
    while(p!=h)
    {
        printf("%s ",&*(p->name));
        p=p->rlink;
    }
    printf("\n");
}

元素查找:
查找函数 STUD *search(STUD *,char *);
STUD *search(STUD *h,char *x)
{
STUD *p;
char *y;
p=h->rlink;
while(p!=h)
{
y=p->name;
if(strcmp(y,x)==0)
return§;
else
p=p->rlink;
}
printf(“没有查到该数据!”);
}
四、循环链表
循环链表的建立不需要专门的头节点,单链表的最后一个结点的指针指向NULL,而循环链表的最后一个结点的指针指向链表头结点。头尾相连形成了一个环形的数据链。
判断循环链表是否为尾结点时,只需要判断该节点的指针域是否指向链表的头结点。

五、合并链表

void merge(struct stud *La,struct stud *Lb)
{
    struct stud *a,*b,*c;
    c=La;
    a=La->next;/* 合并前 */
    b=Lb->next;
    while(a!=NULL && b!=NULL)/* La和Lb都没处理完 */
    {
        if(a->num <= b->num)
        {
            c->next=a;
            c=a;
            a=a->next;
        }
        else
        {
            c->next=b;
            c=b;
            b=b->next;
        }
    }
    if(a!=NULL)
        c->next=a;/* 若La没有处理完 */
    else
        c->next=b;/* 若Lb没有处理完 */
    free(Lb); /* 释放Lb的头结点 */
}

本文整理自:韩亦乐的博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值