数据结构复习之单链表:基本操作及逆序打印、逆转、合并等
2015-08-18 10:07
621 查看
二叉树的定义
与上面等价、但更简洁的二叉树定义如下:
定义好数据结构之后,就可以写各种操作函数了:
#include “stdafx.h” #include<malloc.h> struct ListNode; typedef int ValueType; typedef struct ListNode* ListNode; /* List是指向ListNode结构体首地址的指针,若定义List list,要使用list->value来访问结构体中的变量值,“->”运算符是取指针所指向的值。若定义struct ListNode list,则list只是个struct,访问成员变量value要使用list.value */ typedef ListNode List; //单链表,这里使用的链表没有专门的头节点,头结节点与其他节点一样,存有一个value struct ListNode { ValueType value; struct ListNode *next; //VS2010中可省略这一行的struct };
与上面等价、但更简洁的二叉树定义如下:
typedef struct ListNode { ValueType value; struct ListNode *next; }*ListNode, *List;
定义好数据结构之后,就可以写各种操作函数了:
void nodeInit(ListNode node, ValueType value, ListNode next) { node->value=value; node->next=next; } int listLen(List list) { if(list==NULL) return 0; int len=1; ListNode p=list; while(p->next!=NULL) { len++; p=p->next; } return len; } //搜索简洁版:返回目标节点 ListNode find1(List list, ValueType val) { if(list == NULL) return NULL; ListNode p=list; while(p->next!=NULL && p->value != val) { p=p->next; } if(p->next == NULL) return NULL; return p; } //find的另一版本:若找到则返回元素的位置序号(从0开始),否则返回-1 int find2(List list,ValueType theValue) { if(list == NULL) return -1; ListNode* p; p=list; int position=0; int len=listLen(list); while(p->next != NULL && p->value != theValue) { position++; p = p->next; } if(position+1 ==len && p->value != theValue) return -1; return position; } //找到pos节点的前驱节点 ListNode findPrev(List list, ListNode node) { ValueType val = node->value; int thePos=find(list,val); //pos节点的位置 if(list==NULL || thePos == -1 || thePos == 0) return NULL; ListNode p = list; ListNode q = p->next; while(q != NULL && q->value != val) { p = p->next; q = q->next; } return p; //这是在保证pos节点存在于链表中且不是头节点的情况下才返回的 } //插入简洁版:在list中node节点后面插入inserted节点 void insert1(List list, ListNode node, ListNode inserted) { if(list == NULL || node == NULL || inserted == NULL) return; ListNode p = list; while(p->value != node->value) { p = p->next; } if(p->value != node->value) //没找到 return; if(p->next == NULL) //在表尾插入 p->next = inserted; else { inserted->next = p->next; p->next = inserted; } } //在链表list中下标为position的节点后面插入值value void insert2(List *listAddr, int position, ValueType value) { List newNode = (ListNode )malloc(sizeof(struct ListNode)); if(newNode == NULL) { printf("分配内存出错"); return; } newNode->value = value; if(*listAddr == NULL) { *listAddr = newNode; newNode->next = NULL; return; } ListNode temp=*listAddr; if(position < 0) //这时在链表最前面插入节点 { *listAddr=newNode; newNode->next = temp;//(ListNode )temp; } else if(position+1 >= listLen(*listAddr)) { while(temp->next != NULL) { temp = temp->next; } temp->next = newNode; newNode->next = NULL; } else { int i=0; while(i < position) { temp = temp->next; i++; } newNode->next = temp->next; temp->next = newNode; } } //删除节点 void removeNode(List *list, ValueType value) { if(list == NULL || *list == NULL) return; ListNode pToBeDeleted = *list; if((*list)->value == value) { *list=(*list)->next; free(pToBeDeleted); pToBeDeleted = NULL; } else { ListNode pre; while(pToBeDeleted != NULL && pToBeDeleted->value != value) { pre=pToBeDeleted; pToBeDeleted = pToBeDeleted->next; } if(pToBeDeleted == NULL) { if(pre->value != value) //value不在链表中 return; //value位于最后一个节点中 pre->next = NULL; free(pToBeDeleted); } else { pre->next = pToBeDeleted->next; free(pToBeDeleted); pToBeDeleted = NULL; } } } //删除链表 void removeList(List list) { ListNode p,temp; p=list; while(p != NULL) { temp=p->next; free(p); p=temp; } list = NULL; } //从尾到首打印节点值,这个方法会改变链表结构,不好 void print(List list) { if(list == NULL) return; //int len=listLen(list); ListNode p,pre=NULL; p=list; while(p->next != NULL) { pre=p; p = p->next; } printf("\n%d",p->value); free(p); if(pre != NULL) pre->next = NULL; print(list); } //上面方法的改进版 void printNodesReversing(List list) { if(list == NULL) return; if(list->next != NULL) printNodesReversing(list->next); printf("%d\n",list->value); } //快速删除节点:可在O(1)时间内完成(对于非尾节点) //可能会对头指针操作,所以list一定要用指向指针的指针!! void fastDelet(List *list, ListNode toBeDeleted) { if(!list || !toBeDeleted) return; if(toBeDeleted->next == NULL) //先处理特殊情况可能代码更容易写出来 { //特殊情况:list只有一个节点 if(*list == toBeDeleted) { free(*list); *list = NULL; toBeDeleted =NULL; return; } ListNode p = *list; ListNode pre = NULL; while(p->next != NULL) { pre = p; p = p->next; } pre->next = NULL; free(toBeDeleted); toBeDeleted = NULL; } else { ListNode next = toBeDeleted->next; toBeDeleted->value = next->value; toBeDeleted->next = next->next; free(next); } } //查找链表的倒数第k(k>=1)个节点 ListNode findK(List list, int k) { int len = listLen(list); if(k < 1 || k > len) return NULL; ListNode p1 = list; ListNode p2 = list; int count = len; while(p1->next != NULL) { count--; if(count <= len - k) { p2 = p2->next; } p1 = p1->next; } return p2; } //链表逆转 //解法1:从后往前逆转,递归依次找到最后一个节点。时间O(n^2) void reverseList1(List list, int length, List newList, ListNode lastNode) { //if(list == NULL) // return; if(length <= 0) return; List reversed; ListNode p = list; ListNode pre = NULL; for(int i = 0; i < length; i++) { pre = p; p = p->next; } //if(pre == NULL) //出口 // return; ListNode newList = p; newList->next = pre; lastNode = pre; reverseList1(list, length-1, newList,lastNode->next); } //解法2:从前往后逆转,把断开的地方缓存起来。时间O(n) List reverseList2(List list) { if(list == NULL) return NULL; ListNode newHead = NULL; //逆转之后的新表头 ListNode lastNewHead; //上一个表头 ListNode p = list; while(p->next != NULL) { lastNewHead = newHead; newHead = p; newHead->next = lastNewHead; p = p->next; } lastNewHead = newHead; newHead = p; newHead->next = lastNewHead; return newHead; } //合并两个有序链表仍保持有序,这里以升序为例 //方法1:归并排序中有序数组的合并思想,但需要定义好几个指针,比较麻烦,且容易出错 List mergeLists1(List list1, List list2) { if(list1 == NULL) return list2; if(list2 == NULL) return list1; List newList = NULL; ListNode p1 = list1; ListNode p2 = list2; ListNode lastNode = NULL; //合并的链表尾节点 if(p1->value <= p2->value) { newList = p1; lastNode = p1; p1 = p1->next; } else { newList = p2; lastNode = p2; p2 = p2->next; } while(p1 != NULL && p2 != NULL) { ListNode temp = NULL; if(p1->value <= p2->value) { temp = p1->next; lastNode->next = p1; p1 = temp; } else { temp = p2->next; lastNode->next = p2; p2 = temp; } lastNode = lastNode-> next; } if(p1 != NULL) lastNode->next = p1; if(p2 != NULL) lastNode->next = p2; return newList; } //方法2:利用递归,简洁明了 ListNode mergeLists2(List l1, List l2) { if(l1 == NULL) return l2; if(l2 == NULL) return l1; ListNode newList; ListNode temp; if(l1->value <= l2->value) { temp = l1->next; //要断开l1,先缓存 newList = l1; newList->next = mergeLists2(temp, l2); } else { temp = l2->next; newList = l2; newList->next = mergeLists2(l1, temp); } return newList; }
相关文章推荐
- [C/C++]反转链表
- 用VBScript写合并文本文件的脚本
- C#实现基于链表的内存记事本实例
- oracle列合并的实现方法
- 使用BAT一句话命令实现快速合并JS、CSS
- Lua教程(七):数据结构详解
- SQL 合并多行记录的方法总汇
- 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解
- C#自适应合并文件的方法
- C#数据结构揭秘一
- 数据结构之Treap详解
- C语言实现带头结点的链表的创建、查找、插入、删除操作
- C++实现简单的学生管理系统
- GridView单元格合并
- 如何合并多个 .NET 程序集
- JavaScript数据结构和算法之图和图算法
- 使用UglifyJS合并/压缩JavaScript的方法
- 高性能WEB开发 JS、CSS的合并、压缩、缓存管理
- 多个js与css文件的合并方法详细说明
- 使用不同的方法结合/合并两个JS数组