链表操作(不带头节点的)
链表其实蛮简单的,但如果一段时间不用的话马上让你写还真不一定能写的出来,这里总结一下,作为温习。
结构声明
typedef int elemType;//根据自己的需要来
//单链表结点类型
typedef struct ListNode{
elemType element;
struct ListNode *next;
}Node;
初始化
// 初始化线性表,即置单链表的表头指针为空
void initList(Node *pNode)
{
pNode = NULL;
printf("%s: init success\n",__FUNCTION__);
}
创建链表
// 创建单链表 - 从尾部插入元素
Node *createList_end(Node *pHead)
{
Node *newNode = NULL;
Node *pEnd = NULL;
pEnd = (Node*)malloc(sizeof(Node));
elemType data;
while (scanf("%d", &data) != EOF)
{
newNode = (Node*)malloc(sizeof(Node));
newNode->next = NULL;
newNode->element = data;
if (pHead == NULL)
pHead = newNode;
else
pEnd->next = newNode;
pEnd = newNode;//插入新元素后,新元素为新的尾节点
}
printf("%s: create list success\n",__FUNCTION__);
return pHead; //返回链表的头指针
}
向链表尾插入一个元素
//向单链表的末尾添加一个元素
void 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;
return;
}
向链表头插入一个元素
//向单链表的表头插入一个元素
void 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;
return;
}
往位置i插入一个节点
// 往位置 i 插入节点
void insertList(Node **pNode,elemType insertElem, int position)
{
Node *pInsert;
Node *pCur;
Node *pTmp;
pCur = *pNode;
pTmp = pCur;
while (--position > 1 && pCur->next != NULL)
{
pCur = pCur->next;
}
pInsert = (Node *)malloc(sizeof(Node));
memset(pInsert,0,sizeof(Node));
pInsert->element = insertElem;
pInsert->next = pCur->next;
pCur->next = pInsert;
}
释放链表
//释放链表所有节点
void FreeList(Node *pHead)
{
Node* pNode = NULL;
while(pHead)
{
pNode = pHead;
pHead = pHead->pNext;
free(pNode);
}
return;
}
删除链表尾部节点
//删除链表尾部节点
void DeleteListTail(Node *pHead)
{
Node *pTemp = pHead;
while (pTemp->pNext->pNext != NULL)
{
pTemp = pTemp->pNext;
}
free(pTemp->pNext);
pTemp->pNext = NULL;
}
删除链表表头
//删除链表头部节点
void DeleteListHead(Node *pHead)
{
Node *pTemp = pHead;
pHead = pHead->next
free(pTemp);
pTemp = NULL;
}
链表逆序(非递归)
//链表逆序(非递归)
Node* reverse(Node* head)
{
if(head == NULL || head->next == NULL)
return head;
Node* pre = head;
Node* cur = head->next;
Node* nx;
while(cur != NULL)
{
nx = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
head->next = NULL;
head = pre;
return head;
}
链表逆序(递归)
//头节点head的下一个节点head->next将是逆序后的新链表的尾节点
//链表逆序(递归)
Node* recurReverse(Node* head)
{
if(head == NULL || head->next == NULL)
{
return head;
}
Node* newHead = recurReverse(head->next);
Node* newEnd = head->next;
newEnd->next = head; //新尾节点指向head
head->next = NULL;
return newHead;
}
关于逆序递归的算法,这里有个图描述的挺清楚的,可以查阅一下
有序链表排序(非递归)
/* 输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的
*
* @param head1 第一个有序链表
* @param head2 第二个有序链表
* @return 合并后的有序链表头
*/
public static Node merge(Node head1, Node head2) {
// 如果第一个链表为空,返回第二个链表头结点
if (head1 == null)
return head2;
// 如果第二个结点为空,返回第一个链表头结点
if (head2 == null)
return head1;
// 创建一个临时结点
Node root = new Node();
// 用于指向合并后的新链的尾结点
Node pointer = root;
// 当两个链表都不为空就进行合并操作
while (head1 != null && head2 != null)
{
// 下面的操作合并较小的元素
if (head1.value < head2.value)
{
pointer.next = head1;
head1 = head1.next;
} else
{
pointer.next = head2;
head2 = head2.next;
}
// 将指针移动到合并后的链表的末尾
pointer = pointer.next;
}
// 如果第一个链表的元素未处理完将其,接到合并链表的最后一个结点之后
if (head1 != null)
pointer.next = head1;
// 如果第二个链表的元素未处理完将其,接到合并链表的最后一个结点之后
if (head2 != null)
pointer.next = head2;
// 返回处理结果
return root.next;
}
有序链表排序(递归)
public static Node merge2(Node head1, Node head2)
{
if (head1 == null)
return head2;
if (head2 == null)
return head1;
Node tmp = head1;
if (tmp.value < head2.value)
{
//如果第一个链表的头结点小,就递归处理第一个链表的下一个结点和第二个链表的头结点
tmp.next = merge2(head1.next, head2);
}
else
{
tmp = head2;
tmp.next = merge2(head1, head2.next);
}
return tmp;
}