链表的基本操作

Example 1

////////////////////////////////////////////    
//单链表的初始化,建立,插入,查找,删除。//    
////////////////////////////////////////////     
#include <stdio.h>    
#include <stdlib.h>    
typedef int ElemType;    
////////////////////////////////////////////     
//定义结点类型     
typedef struct Node    
{    
    ElemType data;              //单链表中的数据域     
    struct Node *next;          //单链表的指针域     
}Node,*LinkedList;    
////////////////////////////////////////////     
//单链表的初始化    
LinkedList LinkedListInit()    
{    
    Node *L;    
    L = (Node *)malloc(sizeof(Node));   //申请结点空间     
    if(L == NULL)                       //判断是否有足够的内存空间     
        printf("申请内存空间失败/n");    
    L->next = NULL;                  //将next设置为NULL,初始长度为0的单链表     
}    
////////////////////////////////////////////     
//单链表的建立1,头插法建立单链表    
LinkedList LinkedListCreatH()    
{    
    Node *L;    
    L = (Node *)malloc(sizeof(Node));   //申请头结点空间    
    L->next = NULL;                      //初始化一个空链表    
        
    ElemType x;                         //x为链表数据域中的数据    
    while(scanf("%d",&x) != EOF)    
    {    
        Node *p;    
        p = (Node *)malloc(sizeof(Node));   //申请新的结点     
        p->data = x;                     //结点数据域赋值     
        p->next = L->next;                    //将结点插入到表头L-->|2|-->|1|-->NULL     
        L->next = p;     
    }    
    return L;     
}     
////////////////////////////////////////////     
//单链表的建立2,尾插法建立单链表    
LinkedList LinkedListCreatT()    
{    
    Node *L;    
    L = (Node *)malloc(sizeof(Node));   //申请头结点空间    
    L->next = NULL;                  //初始化一个空链表    
    Node *r;    
    r = L;                          //r始终指向终端结点,开始时指向头结点     
    ElemType x;                         //x为链表数据域中的数据    
    while(scanf("%d",&x) != EOF)    
    {    
        Node *p;    
        p = (Node *)malloc(sizeof(Node));   //申请新的结点     
        p->data = x;                     //结点数据域赋值     
        r->next = p;                 //将结点插入到表头L-->|1|-->|2|-->NULL     
        r = p;     
    }    
    r->next = NULL;     
        
    return L;       
}    
////////////////////////////////////////////     
//单链表的插入,在链表的第i个位置插入x的元素    
LinkedList LinkedListInsert(LinkedList L,int i,ElemType x)    
{    
    Node *pre;                      //pre为前驱结点     
    pre = L;    
    int tempi = 0;    
    for (tempi = 1; tempi < i; tempi++)    
        pre = pre->next;                 //查找第i个位置的前驱结点     
    Node *p;                                //插入的结点为p    
    p = (Node *)malloc(sizeof(Node));    
    p->data = x;     
    p->next = pre->next;    
    pre->next = p;    
        
    return L;                               
}     
////////////////////////////////////////////     
//单链表的删除,在链表中删除值为x的元素    
LinkedList LinkedListDelete(LinkedList L,ElemType x)    
{    
    Node *p,*pre;                   //pre为前驱结点,p为查找的结点。     
    p = L->next;    
    while(p->data != x)              //查找值为x的元素     
    {       
        pre = p;     
        p = p->next;    
    }    
    pre->next = p->next;          //删除操作,将其前驱next指向其后继。     
    free(p);    
    return L;    
}     
/////////////////////////////////////////////    
int main()    
{    
    LinkedList list,start;    
/*  printf("请输入单链表的数据:");   
    list = LinkedListCreatH();  
    for(start = list->next; start != NULL; start = start->next)  
        printf("%d ",start->data);  
    printf("/n");  
*/  printf("请输入单链表的数据:");     
    list = LinkedListCreatT();    
    for(start = list->next; start != NULL; start = start->next)    
        printf("%d ",start->data);    
    printf("/n");    
    int i;    
    ElemType x;    
    printf("请输入插入数据的位置:");    
    scanf("%d",&i);    
    printf("请输入插入数据的值:");    
    scanf("%d",&x);    
    LinkedListInsert(list,i,x);    
    for(start = list->next; start != NULL; start = start->next)    
        printf("%d ",start->data);    
    printf("/n");    
    printf("请输入要删除的元素的值:");    
    scanf("%d",&x);    
    LinkedListDelete(list,x);     
    for(start = list->next; start != NULL; start = start->next)    
        printf("%d ",start->data);    
    printf("/n");    
        
    return 0;    
}     
   

Example 2

#define NULL 0
#define TYPE struct stu
#define LEN sizeof(struct stu)

struct stu{
	int num;
	int age;
	struct stu *next;
}

TYPE *create(int n){
	struct stu *phead, *pf, *pb;
	int i;
	for(i=0; i<n; i++){
		pb = (TYPE *)malloc(LEN);
		printf("input number and age\n");
		scanf("%d%d",&pb->num,&pb->age);
		if (i == 0){
			pf=head=pb;
		}else{
			pf->next=pb;
		}

		pb->next=NULL;
		pf=pb;

		return(head);

	}
}

Example3

最近在复习数据结构,想把数据结构里面涉及的都自己实现一下,完全是用C语言实现的。
自己编写的不是很好,大家可以参考,有错误希望帮忙指正,现在正处于编写阶段,一共将要实现19个功能。到目前我只写了一半,先传上来,大家有兴趣的可以帮忙指正,谢谢
在vs2010上面编译运行无错误。
每天都会把我写的新代码添加到这个里面。直到此链表完成。
#include "stdafx.h"
#include "stdio.h"
#include <stdlib.h>
#include "string.h"
 
typedef int elemType ;
 
/************************************************************************/
/*             以下是关于线性表链接存储(单链表)操作的18种算法        */
 
/* 1.初始化线性表,即置单链表的表头指针为空 */
/* 2.创建线性表,此函数输入负数终止读取数据*/
/* 3.打印链表,链表的遍历*/
/* 4.清除线性表L中的所有元素,即释放单链表L中所有的结点,使之成为一个空表 */
/* 5.返回单链表的长度 */
/* 6.检查单链表是否为空,若为空则返回1,否则返回0 */
/* 7.返回单链表中第pos个结点中的元素,若pos超出范围,则停止程序运行 */
/* 8.从单链表中查找具有给定值x的第一个元素,若查找成功则返回该结点data域的存储地址,否则返回NULL */
/* 9.把单链表中第pos个结点的值修改为x的值,若修改成功返回1,否则返回0 */
/* 10.向单链表的表头插入一个元素 */
/* 11.向单链表的末尾添加一个元素 */
/* 12.向单链表中第pos个结点位置插入元素为x的结点,若插入成功返回1,否则返回0 */
/* 13.向有序单链表中插入元素x结点,使得插入后仍然有序 */
/* 14.从单链表中删除表头结点,并把该结点的值返回,若删除失败则停止程序运行 */
/* 15.从单链表中删除表尾结点并返回它的值,若删除失败则停止程序运行 */
/* 16.从单链表中删除第pos个结点并返回它的值,若删除失败则停止程序运行 */
/* 17.从单链表中删除值为x的第一个结点,若删除成功则返回1,否则返回0 */
/* 18.交换2个元素的位置 */
/* 19.将线性表进行快速排序 */
 
 
/************************************************************************/
typedef struct Node{    /* 定义单链表结点类型 */
    elemType element;
    Node *next;
}Node;
 
 
/* 1.初始化线性表,即置单链表的表头指针为空 */
void initList(Node **pNode)
{
    *pNode = NULL;
    printf("initList函数执行,初始化成功\n");
}
 
/* 2.创建线性表,此函数输入负数终止读取数据*/
Node *creatList(Node *pHead)
{
    Node *p1;
    Node *p2;
 
    p1=p2=(Node *)malloc(sizeof(Node)); //申请新节点
    if(p1 == NULL || p2 ==NULL)
    {
        printf("内存分配失败\n");
        exit(0);
    }
    memset(p1,0,sizeof(Node));
 
    scanf("%d",&p1->element);    //输入新节点
    p1->next = NULL;         //新节点的指针置为空
    while(p1->element > 0)        //输入的值大于0则继续,直到输入的值为负
    {
        if(pHead == NULL)       //空表,接入表头
        {
            pHead = p1;
        }
        else               
        {
            p2->next = p1;       //非空表,接入表尾
        }
        p2 = p1;
        p1=(Node *)malloc(sizeof(Node));    //再重申请一个节点
        if(p1 == NULL || p2 ==NULL)
        {
        printf("内存分配失败\n");
        exit(0);
        }
        memset(p1,0,sizeof(Node));
        scanf("%d",&p1->element);
        p1->next = NULL;
    }
    printf("creatList函数执行,链表创建成功\n");
    return pHead;           //返回链表的头指针
}
 
/* 3.打印链表,链表的遍历*/
void printList(Node *pHead)
{
    if(NULL == pHead)   //链表为空
    {
        printf("PrintList函数执行,链表为空\n");
    }
    else
    {
        while(NULL != pHead)
        {
            printf("%d ",pHead->element);
            pHead = pHead->next;
        }
        printf("\n");
    }
}
 
/* 4.清除线性表L中的所有元素,即释放单链表L中所有的结点,使之成为一个空表 */
void clearList(Node *pHead)
{
    Node *pNext;            //定义一个与pHead相邻节点
 
    if(pHead == NULL)
    {
        printf("clearList函数执行,链表为空\n");
        return;
    }
    while(pHead->next != NULL)
    {
        pNext = pHead->next;//保存下一结点的指针
        free(pHead);
        pHead = pNext;      //表头下移
    }
    printf("clearList函数执行,链表已经清除\n");
}
 
/* 5.返回单链表的长度 */
int sizeList(Node *pHead)
{
    int size = 0;
 
    while(pHead != NULL)
    {
        size++;         //遍历链表size大小比链表的实际长度小1
        pHead = pHead->next;
    }
    printf("sizeList函数执行,链表长度 %d \n",size);
    return size;    //链表的实际长度
}
 
/* 6.检查单链表是否为空,若为空则返回1,否则返回0 */
int isEmptyList(Node *pHead)
{
    if(pHead == NULL)
    {
        printf("isEmptyList函数执行,链表为空\n");
        return 1;
    }
    printf("isEmptyList函数执行,链表非空\n");
 
    return 0;
}
 
/* 7.返回单链表中第pos个结点中的元素,若pos超出范围,则停止程序运行 */
elemType getElement(Node *pHead, int pos)
{
    int i=0;
 
    if(pos < 1)
    {
        printf("getElement函数执行,pos值非法\n");
        return 0;
    }
    if(pHead == NULL)
    {
        printf("getElement函数执行,链表为空\n");
        return 0;
        //exit(1);
    }
    while(pHead !=NULL)
    {
        ++i;
        if(i == pos)
        {
            break;
        }
        pHead = pHead->next; //移到下一结点
    }
    if(i < pos)                  //链表长度不足则退出
    {
        printf("getElement函数执行,pos值超出链表长度\n");
        return 0;
    }
 
    return pHead->element;
}
 
/* 8.从单链表中查找具有给定值x的第一个元素,若查找成功则返回该结点data域的存储地址,否则返回NULL */
elemType *getElemAddr(Node *pHead, elemType x)
{
    if(NULL == pHead)
    {
        printf("getElemAddr函数执行,链表为空\n");
        return NULL;
    }
    if(x < 0)
    {
        printf("getElemAddr函数执行,给定值X不合法\n");
        return NULL;
    }
    while((pHead->element != x) && (NULL != pHead->next)) //判断是否到链表末尾,以及是否存在所要找的元素
    {
        pHead = pHead->next;
    }
    if((pHead->element != x) && (pHead != NULL))
    {
        printf("getElemAddr函数执行,在链表中未找到x值\n");
        return NULL;
    }
    if(pHead->element == x)
    {
        printf("getElemAddr函数执行,元素 %d 的地址为 0x%x\n",x,&(pHead->element));
    }
 
    return &(pHead->element);//返回元素的地址
}
 
/* 9.把单链表中第pos个结点的值修改为x的值,若修改成功返回1,否则返回0 */
int modifyElem(Node *pNode,int pos,elemType x)
{
    Node *pHead;
    pHead = pNode;
    int i = 0;
 
    if(NULL == pHead)
    {
        printf("modifyElem函数执行,链表为空\n");
    }
    if(pos < 1)
    {
        printf("modifyElem函数执行,pos值非法\n");
        return 0;
    }
    while(pHead !=NULL)
    {
        ++i;
        if(i == pos)
        {
            break;
        }
        pHead = pHead->next; //移到下一结点
    }
    if(i < pos)                  //链表长度不足则退出
    {
        printf("modifyElem函数执行,pos值超出链表长度\n");
        return 0;
    }
    pNode = pHead;
    pNode->element = x;
    printf("modifyElem函数执行\n");
     
    return 1;
}
 
/* 10.向单链表的表头插入一个元素 */
int insertHeadList(Node **pNode,elemType insertElem)
{
    Node *pInsert;
    pInsert = (Node *)malloc(sizeof(Node));
    memset(pInsert,0,sizeof(Node));
    pInsert->element = insertElem;
    pInsert->next = *pNode;
    *pNode = pInsert;
    printf("insertHeadList函数执行,向表头插入元素成功\n");
 
    return 1;
}
 
/* 11.向单链表的末尾添加一个元素 */
int insertLastList(Node **pNode,elemType insertElem)
{
    Node *pInsert;
    Node *pHead;
    Node *pTmp; //定义一个临时链表用来存放第一个节点
 
    pHead = *pNode;
    pTmp = pHead;
    pInsert = (Node *)malloc(sizeof(Node)); //申请一个新节点
    memset(pInsert,0,sizeof(Node));
    pInsert->element = insertElem;
 
    while(pHead->next != NULL)
    {
        pHead = pHead->next;
    }
    pHead->next = pInsert;   //将链表末尾节点的下一结点指向新添加的节点
    *pNode = pTmp;
    printf("insertLastList函数执行,向表尾插入元素成功\n");
 
    return 1;
}
 
/* 12.向单链表中第pos个结点位置插入元素为x的结点,若插入成功返回1,否则返回0 */
 
 
/* 13.向有序单链表中插入元素x结点,使得插入后仍然有序 */
/* 14.从单链表中删除表头结点,并把该结点的值返回,若删除失败则停止程序运行 */
/* 15.从单链表中删除表尾结点并返回它的值,若删除失败则停止程序运行 */
/* 16.从单链表中删除第pos个结点并返回它的值,若删除失败则停止程序运行 */
/* 17.从单链表中删除值为x的第一个结点,若删除成功则返回1,否则返回0 */
/* 18.交换2个元素的位置 */
/* 19.将线性表进行快速排序 */
 
/******************************************************************/
int main()
{
    Node *pList=NULL;
    int length = 0;
 
    elemType posElem;
 
    initList(&pList);       //链表初始化
    printList(pList);       //遍历链表,打印链表
 
    pList=creatList(pList); //创建链表
    printList(pList);
     
    sizeList(pList);        //链表的长度
    printList(pList);
 
    isEmptyList(pList);     //判断链表是否为空链表
     
    posElem = getElement(pList,3);  //获取第三个元素,如果元素不足3个,则返回0
    printf("getElement函数执行,位置 3 中的元素为 %d\n",posElem);   
    printList(pList);
 
    getElemAddr(pList,5);   //获得元素5的地址
 
    modifyElem(pList,4,1);  //将链表中位置4上的元素修改为1
    printList(pList);
 
    insertHeadList(&pList,5);   //表头插入元素12
    printList(pList);
 
    insertLastList(&pList,10);  //表尾插入元素10
    printList(pList);
 
    clearList(pList);       //清空链表
    system("pause");
     
}

单链表的基本操作大全之C语言实现

1. 单链表的定义

链表是通过一组任意的存储单元来存储线性表中的数据元素,这些存储单元可以是连续的也可以是不连续的。为了建立起数据元素之间的关系,对于每个数据元素除了存放数据元素自身的信息外,还必须有包含的指示该元素直接后继元素存储位置的信息,这两部分信息组成一个结点,即每个结点都有至少包括两个域,一个域存储数据元素信息,称为数据域,另一个域存储直接后继的地址,称为指针域。

    typedef struct node{
        int data;    //数据域
        struct node *next;    //指针域
    }NODE;

当n个元素的线性表通过每个结点的指针域连接成了一条“链子”,我们形象的称之为链表。

2. 建立单链表

建立单链表有两种方法,一种是头插法,一种是尾插法。
在主函数中调用函数时,使用一个NODE *类型的指针接收函数的返回值。

2.1初始化一个链表结点

每次malloc的结点都要初始化,因此写成一个函数。

    //初始化一个节点
    NODE *initnode(NODE *pnode, int data)
    {
            pnode = (NODE *)malloc(sizeof(NODE));
            pnode->data = data;//初始化数据域
            pnode->next = NULL;//初始化指针域为NULL

            return pnode;
    }

2.2头插法建立链表

在链表的头部插入结点建立单链表,称为“头插法”。

    //创建一个新节点(头插法)
    NODE *createlink_byhead(NODE *phead, int data)
    {
            NODE *pnode = initnode(pnode, data);//初始化一个结点
            NODE *ptmp = phead;

        if(NULL == phead){    //链表为空,直接返回初始化的结点
                return pnode;
        }else{
                phead = pnode;    //将新申请的结点插在phead后面,也就是整个链表的最前面
                pnode->next = ptmp;
        }

        return phead;
}

因为每次新结点都会插在链表的头部,则数据读入的顺序和线性表中的逻辑顺序正好相反。

2.3尾插法建立链表

在链表的尾部插入结点建立单链表,简称”尾插法“。

    //创建一个链表节点(尾插法)
    NODE *createlink_bytail(NODE *phead, int data)
    {
            NODE *pnode = initnode(pnode, data);//初始化结点
            NODE *ptmp = phead;

        if(NULL == phead){//当链表为空,直接返回初始化的结点
                return pnode;
        }else{
                while(ptmp->next != NULL){//找到最后一个结点,插在尾部
                        ptmp = ptmp->next;
                }
                ptmp->next = pnode;
        }

        return phead;
    }

尾插法读入的数据与线性表中的逻辑顺序相同

3. 链表的长度

    //求链表长度
    int linklen(NODE *phead)
    {
            int len = 0;//计数器
            NODE *ptmp = phead;

            while(ptmp != NULL){//遍历链表,计数器加1
                    len++;
                    ptmp = ptmp->next;
            }

            return len;
    }

这个算法的时间复杂度为O(n)

4. 按值查找操作

   //按值查找
    NODE *searchnode(NODE *phead, int key)
    {
        NODE *ptmp = phead;

        if(NULL == phead){    //链表为空,直接返回
                return NULL;
        }
        while(ptmp->data != key && ptmp->next != NULL){//没找到key && 链表没找完
                ptmp = ptmp->next; //指针移动
        }
        if(ptmp->data == key) //找到key,返回该结点地址
                return ptmp;
        if(ptmp->next == NULL)//没找到,返回空
                return NULL;
    }

这个算法的时间复杂度为O(n)

5.插入操作

插入操作也分为两种,一种是插在目标值得前面,简称“前插法”,另一种是插在目标值的后面,简称“后插法”。

5.1前插法

 //向前插入
    NODE *insertnode_bypre(NODE *phead, int data, int key)
    {
        NODE *pnode = initnode(pnode, data);//初始化插入的结点
        NODE *ptmp = phead;

        if(NULL == phead){//链表为空,直接返回初始化的结点
                return pnode;
        }else if(phead->data == key){//处理第一个结点是否为目标结点
                phead = pnode;
                pnode->next = ptmp;
        }else{
                while(ptmp->next != NULL && ptmp->next->data != key){//循环遍历,没找完 && 没找到
                        ptmp = ptmp->next;
                }
                if(NULL == ptmp->next){//没找到的情况
                        printf("insert key NOT FOUND\n");
                }else{//把新节点插入目标结点的前面
                        ptmp->next->data == key;
                        pnode->next = ptmp->next;
                        ptmp->next = pnode;
                }
        }
        return phead;
    }

前插法单独处理了第一个结点,是因为前插法会改变phead的值,而且前插法查找目标结点必须知道目标节点的前驱结点的next值,所以从第二个结点开始处理。

5.2后插法

   //向后插入
    NODE *insertnode_byback(NODE *phead, int data, int key)
    {
        NODE *pnode = initnode(pnode, data);//初始化插入的结点
        NODE *ptmp = searchnode(phead, key);//查找到目标结点

        if(NULL == ptmp){//处理链表为空,或没找到
                printf("link is empty or not found key\n");
                return phead;
        }
        if(NULL == ptmp->next){//如果key为最后一个结点
                ptmp->next = pnode;
        }else{ //将新节点插入在目标结点的后面
                pnode->next = ptmp->next;
                ptmp->next = pnode;
        }

        return phead;
}

后插法要单独处理尾结点的情况,因为插入操作不相同。
前插法和后插法的时间复杂度都为O(n)

6.删除操作

  //删除节点
    NODE *delnode(NODE *phead, int key)
    {
        NODE *ptmp = phead;
        NODE *tmp = NULL;

        if(NULL == phead){//处理链表为空的情况
                printf("link is empty, del fail\n");
                return NULL;
        }else if(phead->data == key){//单独处理第一个结点
                phead = phead->next;
                free(ptmp);
                ptmp = NULL;
        }else{
                while(ptmp->next != NULL && ptmp->next->data != key){ //没找完 && 没找到
                        ptmp = ptmp->next;
                }
                if(NULL == ptmp->next){ //没找到
                        printf("del key NOT FOUND\n");
                        return phead;
                }
                if(ptmp->next->data == key){ //找到目标结点删除之
                        tmp = ptmp->next;
                        ptmp->next = tmp->next;
                        free(tmp);
                        tmp = NULL;
                }
        }
        return phead;
}

单独处理第一个结点还是因为要知道要删除目标结点的前驱结点
删除操作算法时间复杂度为O(n)

7.链表的倒置

链表的倒置算法思路:一次取出原链表中的每一个结点,将其作为第一个结点插入新链表中。

  //链表的倒置
    NODE *reverselink(NODE *phead)
    {
        NODE *ptmp = NULL;//创建一个新链
        NODE *tmp = NULL;

        if(NULL == phead){//处理链表为空
                printf("link is empty\n");
                return NULL;
        }else{
                while(phead != NULL){//将旧链上的结点链到新链上
                        tmp = phead;
                        phead = phead->next;
                        tmp->next = ptmp;
                        ptmp = tmp;
                }
        }
        return ptmp;
}

8.链表的排序(冒泡排序)

    //链表排序(冒泡)
    NODE *linksort(NODE *phead)
    {
        NODE *p = NULL; //i
        NODE *q = NULL; //j
        NODE *r = NULL; 
        NODE tmp; 

        for(p = phead; p; p = p->next){
                for(q = p->next; q; q = q->next){
                        if(p->data > q->data){
                                tmp = *p;//整个结点交换
                                *p = *q;
                                *q = tmp;
                                r = p->next;//将指针换回去
                                p->next = q->next;
                                q->next = r;
                        }
                }
        }

        return phead;
    }

冒泡排序的时间复杂度为O(n²)

posted @ 2017-09-03 22:26  苏小北1024  阅读(780)  评论(0编辑  收藏  举报