单链表的实现(不带头节点)
来源:互联网 发布:英雄创造历史 知乎 编辑:程序博客网 时间:2024/04/30 03:36
//单链表的操作 (不带表头节点)#include <stdlib.h>#include <stdio.h>#include <string.h>#define MALLOC(p,s) \if( !( (p) = malloc(s) ) ) { \ fprintf(stderr,"Insufficient memory.\n"); \ exit(EXIT_FAILURE); \}typedef struct listNode *listPtr;struct listNode{ int data; listPtr link;};/* 1.初始化线性表,即置单链表的表头指针为空 */void initList(listPtr *pNode){ *pNode = NULL; printf("initList函数执行,初始化成功\n");}//创建两个节点链表, first 指向第一个节点,second指向第二个节点//返回变量first指向表头listPtr create(){ /* create a linked list with two node */ listPtr first, second; MALLOC(first, sizeof(*first) ); MALLOC(second, sizeof(*second) ); second->link = NULL; second->data = 20; first ->data = 10; first->link = second; return first;}listPtr getNode(int item){ listPtr newNode; MALLOC(newNode, sizeof(*newNode)); memset(newNode, 0, sizeof(*newNode)); newNode->data = item; newNode->link = NULL; return newNode;}//计算单链表的长度int length( listPtr lead ){ int len = 0; while( lead ) { ++len; lead = lead->link; } return len;}//链表的插入,要在链表中的任意位置x之后插入一个节点,节点的数据域是50//函数的参数有两个,first指向表头,如果first为空指针,则返回后它的值//变成指向数据域为50的指针,由于这个指针的内容可能改变,必须传这个指针的地址//形参声明为listPtr *first,第二个参量值x不会改变,因此不用传它的地址。函数调用//语句应为insert(&first, x),first是表头,x指向插入的位置void insert(listPtr *first, listPtr x ){ /* insert a new node with data = 50 into the chain first after node x */ listPtr tempNode; MALLOC(tempNode, sizeof(*tempNode)); tempNode->data = 50; if ( *first ) { // not NULL tempNode->link = x->link; //在x与其后继节点之间插入tempNode指向的节点 x->link = tempNode; } else { // empty list tempNode->link = NULL; *first = tempNode; }}//在链表的表头插入一个元素,若成功返回1,失败返回0;int insertFront(listPtr *front, int x ){ listPtr p; MALLOC(p, sizeof(*p) ); memset(p, 0, sizeof(*p) ); p->data = x; p->link = (*front); *front = p; printf("向表头插入元素 %d 成功\n", x); return 1;}//单链表的正向排序//将item插入到一个从小到大排序的有序链表中void insertSort(listPtr *front, const int item ){ listPtr newNode; newNode = getNode(item); if( *front == NULL ) {// empty list *front = newNode; } else if ( (*front)->data >= newNode->data ) { // 在第一个节点之前插入 newNode->link = *front; *front = newNode; } else { listPtr curr = *front; listPtr prev = NULL; //找到需要插入的位置 while(newNode->data > curr->data && curr->link != NULL ) { prev = curr; curr = curr->link; } //如果是在中间位置,把newNode插入到prev和curr之间 if ( curr->data >= newNode->data ) { newNode->link = curr; prev->link = newNode; } else { //位置在末尾,把newNode插入到curr之后 curr->link = newNode; } }}//将一个节点按节点中值的升序插入到一个链表中listPtr insertNode( listPtr front, listPtr node ){ listPtr prev = NULL; listPtr curr = front; while( curr != NULL && curr->data < node->data ) { prev = curr; curr = curr->link; } if ( curr == front ) { node->link = front; front = node; } else { //插入到 prev和curr之间 prev->link = node; node->link = curr; } return front;}//将两个有序链表head1和head2合并成一个链表,依然有序,使用递归方法以及非递归方法//非递归合并listPtr mergeList( listPtr head1, listPtr head2 ){ //若果有一个是空表则返回另一个 if ( head1 == NULL ) return head2; if ( head2 == NULL ) return head1; // neither list is NULL,find the shorter one listPtr head ; //指向两个表中较长的那个表的表头 listPtr p; //指向较短的那个表表头 listPtr nextP; //指向p之后 if(length(head1) > length(head2)) { head = head1; p = head2; } else { head = head2; p = head1; } //将较短表中的元素逐个插入到较长的表中 while ( p != NULL ) { nextP = p->link; //保存p的下一结点 head = insertNode(head, p); //将p插入到目标链表中 p = nextP; // p指向将要插入的下一个节点 } return head;}//递归合并两个有序链表listPtr mergeRecursive(listPtr head1, listPtr head2 ){ listPtr head = NULL; if ( head1 == NULL ) return head2; if (head2 == NULL ) return head1; if (head1->data < head2->data ) { head = head1; head->link = mergeRecursive( head1->link, head2 ); } else { head = head2; head->link = mergeRecursive( head1, head2->link ); } return head;}//打印链表,最先打印first的数据域,然后first的值用它自己的link域值替换//这样访问链表的所有节点知道结束。void printList(listPtr first ){ printf("The list contains: "); for( ; first; first = first->link ) printf("%4d", first->data ); printf("\n");}//将链表反向listPtr invert(listPtr lead ){ /* invert the list pointed to by lead */ listPtr trail, middle; middle = NULL; while ( lead ) { trail = middle; middle = lead; lead = lead->link; middle->link = trail; } return middle;}//把两个单向链表ptr1, ptr2连接起来,函数复杂度是O(prt1长度)//函数不申请新节点,连接就放在ptr1中listPtr concatenate( listPtr ptr1, listPtr ptr2 ){ /* produce a new list that pointed to by ptr1 * is changed permanently */ listPtr temp; /* check for empty lists */ if ( !ptr1 ) return ptr2; if ( !ptr2 ) return ptr1; /* neither list is empty, find end of first list */ for ( temp = ptr1; temp->link; temp = temp->link ); /* link end of first to start of second */ temp->link = ptr2; return ptr1;}//清空链表,当程序不再需要链表时,应当即使释放链表所占用的内存//通过重复删除表头节点直至链表为空(front = NULL)来清空一个链表void freeList(listPtr *front){ listPtr p; //不能删除空链表的front节点 while( *front != NULL) { // p指向原来的front节点 p = *front; //把front移到下一个节点 *front = (*front)->link; free( p ); } printf("已清空链表\n");}//在链表总查找具有特定值target的第一个节点,若查找成功返回指向该节点的指针,失败返回NULLlistPtr find( listPtr front, const int target ){ listPtr p = front; while ( p != NULL && p->data != target ) { p = p->link; } return p;}//删除链表中的节点,删除节点需要考虑节点所在的位置。 假设first指向表头,x指向待删除节点,//指向x的直接前驱节点。如果待删除节点是表头,因此必须改变first的值,如果不是表头节点只需要//将trail的链域改变,让它指向x所指向的节点即可void deleteNode(listPtr *first, listPtr x ){ /* delete x from the list, trail is the preceding node * and *first is the front of the list */ listPtr trail; // 指向x的前驱节点 if ( x == (*first) ) trail = NULL; else { // x is not the first, find the position of trail for(trail = *first; trail->link != x; trail= trail->link); } if(trail != NULL) { //trail is not NULL, means it is not the first trail->link = x->link; } else { *first = (*first)->link; } free(x);}//判断一位链表是否有环, 有环返回1,无环返回0int hasLoop(listPtr front){ listPtr fast = front; listPtr slow = front; while(fast != NULL && fast->link != NULL) { slow = slow->link; // 1 step fast = fast->link->link; // 2 step if( fast == slow) return 1; } return 0;}//删除一个具有特定值的节点,如果链表中存在值target则删除找到的第一个匹配的节点//否则不改变链表。函数可能会改变头结点,所以要传递该指针的地址或引用void eraseValue(listPtr *front, const int target){ int found = 0; //如果找到节点,将设置为1 listPtr curr; //用于遍历链表 listPtr trail; // 跟在curr的后面 curr = *front; trail = NULL; //扫面链表直到找到目标节点或者到达链表尾 while ( curr != NULL && !found ) { if( curr->data == target ) { // have a match //要删除的是不是表头节点 if(trail == NULL) { *front = (*front)->link; // remove the first node } else { trail->link = curr->link; // erase the intermediate node } free(curr); found = 1; } else { trail = curr; curr = curr->link; } }}int main(){ listPtr list1 = create(); insertFront(&list1,30); insertFront(&list1, 40); printList(list1); listPtr list2 = create(); list2 = invert(list2); printList(list2); listPtr list3 = concatenate(list1, list2); printList(list3); listPtr p = find(list3, 10); deleteNode(&list3, p); printList(list3); int size = length(list3); printf("The size of list3 is: %d\n", size); freeList(&list3); listPtr head = getNode(3); int i; for (i = 10; i > 0; i--) insertSort(&head, i); printList(head); insertNode(head,getNode(100)); printList(head); listPtr k; initList(&k); for (i = 10; i > 0; i--) k = insertNode(k, getNode(i+10)); printList(k); listPtr j = NULL; for (i = 17; i < 25; i++) j = insertNode(j, getNode(i)); printList(j); //listPtr m = mergeList(j,k); listPtr m = mergeRecursive(j, k); printList(m); return 0;}
0 0
- 单链表的实现(不带头节点)
- 带头节点和不带头节点的单链表的区别
- 数据结构双语课->不带头节点的单链表实现
- 不带头节点的链表尾插法C++实现
- 带头节点单链表的实现
- C语言实现单链表节点的删除(不带头结点)
- C语言实现单链表(不带头结点)节点的插入
- 不带头节点的单链表及其基本操作(Java实现)
- 数据结构(一)单链表的基本操作(不带头节点)
- SlinkList(不带头节点的单链表)20171003
- 实验2 不带头节点的单链表
- 递归算法-不带头节点的单链表
- 带头节点的单链表的实现
- C语言实现单链表节点的删除(带头结点)
- C语言实现单链表的节点插入(带头结点)
- 链表的创建(带头节点以及不带头节点)
- 带头节点和不带头节点的链表
- 带头节点的单链表
- 模态视图 push pop
- Non-Blocking Sockets in TCP/IP (The Client)
- HDU 1150 Machine Schedule
- 数据倾斜总结
- Java UDP使用Socket进行网络聊天(1)
- 单链表的实现(不带头节点)
- iOS算法(一)置快速排序算法
- 方法的重写与重载区别
- 抽象类与抽象方法
- memcpy 函数
- CSS布局+static relative fixed absolute
- cocospod 安装和使用
- 快速提高 Vi/Vim 使用效率的原则与途径
- Socket 功能在 Service 中实现【这才是实际的使用情况】