标签:数据结构--单链表的操作
#pragma once #include<stdio.h> #include<string.h> #include<assert.h> #include <stdlib.h> typedef int DataType; //定义一个结构体类型 typedef struct LinkNode { DataType data;//定义节点的数据 struct LinkNode *next;//保存下一个类型节点的地址 }LinkNode, *pLinkNode, *pList;//指向节点的指针 void InitLinkList(pList* pHead); void Destroy(pList *pHead); void PushBack(pList* pHead, DataType x); void PopBack(pList* pHead); void PushFront(pList* pHead, DataType x); void PopFront(pList* pHead); void PrintList(pList list); int GetListLength(pList head); pLinkNode Find(pList head, DataType x); void Insert(pList *pHead, pLinkNode pos, DataType x); void Remove(pList *pHead, DataType x); void RemoveAll(pList *pHead, DataType x); void Erase(pList *pHead, pLinkNode pos); void ReverseList(pList *pHead); void EraseNotTail(pLinkNode pos); //1 pHead是单链表的头指针,它指向表中第一个节点,若phead==null表示单链表是一个空表 void InitLinkList(pList* pHead)//pHead是单链表的头指针,它指向表中第一个节点,若phead==null表示单链表是一个空表 { assert(pHead); (*pHead)->next=NULL; } //2 由于在后边的 几个函数中都需要创建一个新的节点,所以将创建这个节点的过程直接分装成一个函数,使得程序简洁明了 pLinkNode BuyNode(DataType x) { pLinkNode newNode=(pLinkNode)malloc(sizeof(LinkNode)); //创建一个新节点 newNode->data=x; newNode->next=NULL; return newNode; } //3 尾插法建立单链表,首先判断当前链表是否为空,若为空 // 则直接插入节点,否则逐次遍历,将最后一个节点的指针域赋值要插入的节点 void PushBack(pList* pHead, DataType x) { assert(*pHead); pLinkNode cur=*pHead; pLinkNode newNode=BuyNode(x); //尾部插入 if(cur==NULL) { cur=newNode; return; } else { while(cur->next)//有节点 { cur=cur->next; } cur->next=newNode; } } //3尾删方法删除单链表,首先判断, //(1)若当前链表为空则不用删除直接返回 //(2)若链表只有一个节点(*pHead)->next==NULL,则释放*pHead,即可达到删除下一个节点的效果 //(3)若链表含有两个或两个以上的节点,则逐个遍历,当出现当前遍历的节点cur->next->next为空的时候通过free(cur->next)即可删除最后一个节点 void PopBack(pList* pHead)//尾删法 { pLinkNode cur=*pHead; assert(pHead); //没有节点 if(cur==NULL) { return; } //有一个节点 else if(cur->next==NULL) { free(cur); cur=NULL; } //有两个或者两个以上的节点 else { while(cur->next->next) { cur=cur->next; } free(cur->next); cur->next=NULL; } } //4 头插法建立单链表调用之前的BuyNode函数建立一个新的节点 //若当前链表为空则直接插入,否则将newNode->next=*pHead,再将*pHead=newNode void PushFront(pList* pHead, DataType x)//头插法 { pLinkNode newNode=BuyNode(x); assert(pHead); if(*pHead==NULL) { *pHead=newNode; return; } else { newNode->next=*pHead; *pHead=newNode; } } //5 头删法删除单链表的节点 //(1)若单链表为空,则直接返回 /*(2)否则保存要删除的首节点,然后*pHead=(*pHead)->next;将要删除的节点释放即可*/ void PopFront(pList* pHead)//头删法 { pLinkNode del; assert(pHead); if(*pHead==NULL) { return; } else { pLinkNode del=*pHead;//首先保存要删除的节点 *pHead=(*pHead)->next; free(del); del=NULL; } } //6 打印单链表 void PrintList(pList list)//打印单链表 { while(list) { printf("%d->",list->data); list=list->next; } printf("over"); } //7 由于链表是在堆上动态开辟的存储空间,所以使用完之后必须销毁 //如果当前链表为空,则直接返回,反之开始判断当前节点是否为空, //如果不为空,则保存并且释放掉,逐次向后遍历,即可达到销毁的目的 void Destroy(pList *pHead) { pLinkNode cur=*pHead; assert(pHead); if(*pHead==NULL) { return; } else { while(cur) { pLinkNode del=cur; cur=cur->next; free(del); del=NULL; } } } //8 计算链表的长度 //设计一个计数器,一次遍历,只要当前节点不为空,给计数器自增即可 int GetListLength(pList head) { int count=0; pLinkNode cur=head; while(cur) { count++; cur=cur->next; } return count; } //9 寻找链表中数据 //(1)首先判断如果当前链表为空,则查找失败直接返回 //(2)若当前节点不为空,则判断当前节点的数据域的值是否和要查找的数据相等, //若相等则返回当前节点,否则逐次向后遍历,直到最后 任然没有找到则返回空即可 pLinkNode Find(pList head, DataType x) { pLinkNode cur=head; if(cur==NULL) { return; } else { while(cur) if(cur->data==x) { return cur; } else cur=cur->next; } return NULL; } //10 在指定位置插入一个节点 //(1)断言要插入的位置是否合法 /*(2)调用函数创建节点pLinkNode newNode=BuyNode(x); (3)依次遍历当前节点和要插入的位置相等时newNode->next=cur->next,然后cur->next=newNode*/ void Insert(pList *pHead, pLinkNode pos, DataType x) { assert(pHead); assert(pos); pLinkNode newNode=BuyNode(x); pLinkNode cur=*pHead; while(cur!=pos) { cur=cur->next; } newNode->next=cur->next; cur->next=newNode; } //11 删除链表中某个指定位置的节点 //(1)若当前链表为空则直接返回 //(2)判断当前节点是否为空,若不为空则判断是否和要删除的节点只相等 //(3)若相等,则判断是否为头节点,然后在删除 //(4)若相等且不为头节点,则有 void Remove(pList *pHead, DataType x) { pLinkNode cur=*pHead; pLinkNode del=NULL; pLinkNode prev=NULL; assert(pHead); if(pHead==NULL) { return; } else { while(cur) { if(cur->data==x) { del=cur; if(cur==*pHead) { *pHead=(*pHead)->next; } else { prev->next=cur->next; } free(del); break; //循环不能一味的执行下去,因为只删除一次 } prev=cur; cur=cur->next; } } } void RemoveAll(pList *pHead, DataType x) { pLinkNode cur=*pHead; pLinkNode del=NULL; pLinkNode prev=NULL; assert(pHead); if(pHead==NULL) { return; } else { while(cur) { if(cur->data==x) { del=cur; if(cur==*pHead) { *pHead=(*pHead)->next; cur=*pHead; } else { prev->next=cur->next; cur=prev->next; } free(del); } else { prev=cur; cur=cur->next; } } } } //链表常见的面试题 //1 删除非尾节点(删除无头单链表的非尾节点) //(1)将当前节点和下一个节点的数据域交换,然后在删除下一个节点即可 void EraseNotTail(pLinkNode pos) { pLinkNode del=pos->next;//将要删除的节点保存起来,删除当前节点的下一个节点 pos->data=pos->next->data; /*交换当前即诶单和下一个节点的数据域*/ pos->next=del->next; free(del); del=NULL; } //2 反转链表 //头插问题,每次取下一个节点依次头插,将第一个节点的指针域赋值为空,然后取下一个节点进行头插 void ReverseList(pList *pHead) { pLinkNode pnewHead=NULL;/*一注意赋空值定*/ pLinkNode cur=*pHead; pLinkNode prev=NULL; if(cur==NULL) { return; } if(cur->next==NULL) { return; } while(cur) { prev=cur; cur=cur->next; prev->next=pnewHead; } *pHead=pnewHead; } //3 排序链表 (冒泡排序) void Bubblesort(pList *pHead) { pLinkNode end=NULL; pLinkNode cur=*pHead; assert(pHead); while(cur!=end) { while(cur&&(cur->next!=end)) { if(cur->data>cur->next->data) { DataType tmp=cur->data; cur->data=cur->next->data; cur->next->data=tmp; } cur=cur->next; } end=cur; cur=*pHead; } } //4 在当前节点前插入一个数据 //首先在pos后插入一个数据,然后将pos和它后边的数据进行交换,完了删除后边的节点即可 void InsertFrontNode(pLinkNode pos,DataType x) { pLinkNode newNode=BuyNode(x); assert(pos);//防止在空值后边插入一个数据 newNode->next=pos->next; pos->next=newNode; DataType tmp=pos->data; pos->data=pos->next->data; pos->next->data=tmp; } //5合并两个有序链表 pLinkNode Merge(pList l1,pList l2) { pLinkNode cur=NULL; pList newHead=NULL; if(l1==l2) { return l1; } if((l1==NULL)&&(l2!=NULL)) { return l2; } if((l1!=NULL)&&(l2==NULL)) { return l1; } if(l1->data<l2->data)//首先确定头结点 { newHead=l1; l1=l1->next; } else { newHead=l2; l2=l2->next; } while(l1&&l2) { if(l1->data<l2->data) { cur->next=l1->next; l1=l1->next; } else { cur->next=l1; l2=l2->next; } cur=cur->next; } if(l1) { cur->next=l1; } else { cur->next=l2; } return newHead; } //其实有几道面试题没来得及整理呢 测试部分代码: #define _CRT_SECURT_N0_WARNINGS 1 #include<stdio.h> #include"linklist.h" void Test1() { pList mylist; InitLinkList(&mylist); PushFront(&mylist,1); PushFront(&mylist,2); PushFront(&mylist,3); PushFront(&mylist,4); PrintList(mylist); } void Test2() { pList mylist; InitLinkList(&mylist); PushFront(&mylist,1); PushFront(&mylist,2); PushFront(&mylist,3); PushFront(&mylist,4); PrintList(mylist); EraseNotTail(2); PrintList(mylist); } void Test3() { pList l1; InitLinkList(&l1); PushFront(&l1,1); PushFront(&l1,3); PushFront(&l1,5); PushFront(&l1,7); PrintList(l1); pList l2; InitLinkList(&l2); PushFront(&l2,2); PushFront(&l2,4); PushFront(&l2,6); PushFront(&l2,8); PrintList(l2); pList l; l=Merge(l1,l2); PrintList(l); } int main() { void Test2(); system("pause"); }
标签:数据结构--单链表的操作
原文地址:http://10808695.blog.51cto.com/10798695/1737121