[数据结构学习]单链表常用操作

想到数据结构和算法的学习就头疼,对于我一个学java的来说,真后悔当初没有好好学了(c、c++的知识基本也快忘光光了),

可是还得硬着头皮学呀(考虑到明年找工作的事儿),就先从单链表下手吧,

想想若是让我这个新手一个一个的写算法去实现,似乎还不太现实。

还是先参考别人的把基础搞清楚,以后再慢慢深入学习比较合适~

参考原文:http://blog.csdn.net/xiajun07061225/article/details/9246573

注:自己只是在此基础上加了 头插法和尾插法建立单链表(带头结点)、单链表插入结点、单链表清空这三个操作。

话不多说,开始单链表的学习->Go

代码如下:

#include <iostream>
#include <stack>
#include <cstdlib>

using namespace std;

//单链表节点数据结构定义
typedef struct link_node_s{
	int m_val;
	struct link_node_s *next;
}link_node_t,*link_list_t;

//函数:创建单链表(头插法)
link_list_t create_linklist(int *a,int n);

//函数:创建单链表(头插法,带头结点)
link_list_t create_linklist2(int *a,int n);

//函数:创建单链表(尾插法,带头结点)
link_list_t create_linklist3(int *a,int n);

//函数:打印单链表(从头到尾)
void print_linklist(link_list_t head);

//函数:打印单链表(从头到尾,带头结点)
void print_linklist2(link_list_t t);

//函数:打印单链表(从尾到头)
void print_linklist_reverse(link_list_t head);

//函数:新建链表节点
link_list_t creart_linknode(int val);

//函数:带头结点的单链表插入操作
void insert_linklist(link_list_t *t,int i,int val);

//函数:清空单链表
void empty_linklist(link_list_t *t);

//函数:删除链表中的某一个节点(前提条件:该节点一定存在)
//性能要求:在O(1)时间复杂度内实现
void delete_node_exist(link_list_t *head,link_list_t node_deleted);

//函数:删除链表中数据值等于给定值的节点
void delete_node(link_list_t *head,int val);

//函数:获得链表中的倒数第K个节点
link_list_t get_kth_node(link_list_t head,int k);

//函数:反转链表
link_list_t reverse_linklist(link_list_t head);

//函数:合并两个已排序的链表(递归方法实现)
link_list_t merge_linklist_recursive(link_list_t head1,link_list_t head2);

int main(){
	const int num1 = 8;
	const int num2 = 10;
	int *a = new int[num1];
	int *b = new int[num2];
	int *a_sorted = new int[num1];
	int *b_sorted = new int[num2];

    /**********************简单测试********************/
    //测试1
	int *c = new int[num2]{1,6,3,7,9,3,4,5,6,7};
	link_list_t list3 = create_linklist(c,num2);
	print_linklist(list3);//因为是头插法,所以会逆序输出,7是头结点

    //测试2
	link_list_t list4 = create_linklist2(c,num2);
	print_linklist2(list4);

    //测试3
	link_list_t list5 = create_linklist3(c,num2);
	print_linklist2(list5);

    //测试4
    insert_linklist(&list5,0,99);
	print_linklist2(list5);

	//测试5
	empty_linklist(&list5);
    print_linklist2(list5);
    /***************************************************/

    //生成创建链表所需数据
	for(int i = 0;i < num1;++i){
		*(a + i) = rand() % 100;
		*(a_sorted + i) = 50 - i * 2 + 8;
	}

	for(int i = 0;i < num2;++i){
		*(b + i) = rand() % 200;
		*(b_sorted + i) = 50 - i * 4 + 1;
	}

	cout << "**********创建链表测试**********" << endl;
	link_list_t list1 = create_linklist(a,num1);
	link_list_t list2 = create_linklist(b,num2);
	link_list_t list_sorted1 = create_linklist(a_sorted,num1);
	link_list_t list_sorted2 = create_linklist(b_sorted,num2);

	cout << "**********输出链表测试(正向输出)**********" << endl;
	cout << "链表1:" << endl;
	print_linklist(list1);
    cout << "链表2:" << endl;
	print_linklist(list2);
	cout << "链表1(已序):" << endl;
	print_linklist(list_sorted1);
	cout << "链表2(已序):" << endl;
	print_linklist(list_sorted2);


	cout << "**********输出链表测试(逆向输出)**********" << endl;
	print_linklist_reverse(list1);


	cout << "**********获取链表的倒数第K个节点测试**********" << endl;
	int k = 3;
	link_list_t kth_node = get_kth_node(list1,k);
	if(NULL == kth_node)
		cout << "链表中倒数第" << k << "个节点不存在" << endl;
	else
		cout << "链表中倒数第" << k <<"个节点是: " <<kth_node->m_val << endl;

	k = 8;
	kth_node = get_kth_node(list1,k);
	if(NULL == kth_node)
		cout << "链表中倒数第" << k << "个节点不存在" << endl;
	else
		cout << "链表中倒数第" << k <<"个节点是: " <<kth_node->m_val << endl;

	k = 11;
	kth_node = get_kth_node(list1,k);
	if(NULL == kth_node)
		cout << "链表中倒数第" << k << "个节点不存在" << endl;
	else
		cout << "链表中倒数第" << k <<"个节点是: " <<kth_node->m_val << endl;


	cout << "**********删除链表中一定存在的节点测试(注意传递的是链表的引用)**********" << endl;
	link_list_t node_deleted = list1;
	while(node_deleted->m_val != *(a + 4))
		node_deleted = node_deleted->next;

	cout << "删除节点" << *(a + 4) << "之后的单链表:" << endl;
	delete_node_exist(&list1,node_deleted);
	print_linklist(list1);

	node_deleted = list1;
	while(node_deleted->m_val != *(a + 6))
		node_deleted = node_deleted->next;

	cout << "删除节点" << *(a + 6) << "之后的单链表:" << endl;
	delete_node_exist(&list1,node_deleted);
	print_linklist(list1);

	cout << "**********删除链表中值等于给定值的节点测试(不一定存在,输入参数是int型值)**********" << endl;
	const int val_deleted = 22;
	delete_node(&list1,val_deleted);
	cout << "删除值等于" << val_deleted << "之后的链表:" << endl;
	print_linklist(list1);


	cout << "**********合并链表测试**********" << endl;
	link_list_t merge_list_head = merge_linklist_recursive(list_sorted1,list_sorted2);
	print_linklist(merge_list_head);

	return 0;
}

//函数:创建单链表(头插法,不带头结点)
//a为指向整型数组的指针,n为链表的长度
link_list_t create_linklist(int *a,int n){
	link_list_t head = NULL;

	if(NULL == a || 0 == n)
		return NULL;

	for(int i = 0;i < n;++i){
		link_list_t new_node = creart_linknode(*(a + i));

		if(NULL == head){
			head = new_node;
		}
		else{
			new_node->next = head;
			head = new_node;
		}
	}
	return head;
}

//函数:创建单链表(头插法,带头结点)
link_list_t create_linklist2(int *a,int n){
	if(NULL == a || 0 == n)
		return NULL;

    //创建头结点
    link_list_t head=new link_node_t;
	head->next=NULL;

	for(int i = 0;i < n;++i){
		link_list_t new_node = creart_linknode(*(a + i));
        new_node->next = head->next;//要插入的新结点指向链表的第一个结点
        head->next = new_node;
	}
	return head;
}

//函数:创建单链表(尾插法,带头结点)
//需要设置一个尾指针r
link_list_t create_linklist3(int *a,int n){
	if(NULL == a || 0 == n)
		return NULL;

    //创建头结点
    link_list_t head=new link_node_t;
	head->next=NULL;
	//设置尾指针
    link_list_t r=head;

	for(int i = 0;i < n;++i){
		link_list_t new_node = creart_linknode(*(a + i));
        r->next=new_node;
        r=new_node;
	}
	return head;
}

//函数:新建链表节点
link_list_t creart_linknode(int val){
	link_list_t node = new link_node_t;
	node->m_val = val;
	node->next = NULL;
	return node;
}

//函数:打印单链表
void print_linklist(link_list_t head){
	link_list_t node = head;

	cout << "正向输出单链表" << endl;
	while(node != NULL){
		cout << node->m_val << " ";
		node = node->next;
	}
	cout << endl;
	return;
}

//函数:打印单链表(带头结点)
void print_linklist2(link_list_t t){
	t=t->next;
	cout << "正向输出单链表" << endl;
	while(t != NULL){
		cout << t->m_val << " ";
		t = t->next;
	}
	cout << endl;
	return;
}

//函数:打印单链表(从尾到头)
void print_linklist_reverse(link_list_t head){
	stack<int> node_stack;//这里定义了一个存放整型元素的栈
	link_list_t node = head;
	while(node != NULL){
		node_stack.push(node->m_val);
		node = node->next;
	}

	cout << "逆向输出单链表" << endl;
	while(!node_stack.empty()){
		cout << node_stack.top() << " ";
		node_stack.pop();
	}
	cout << endl;
	return;
}

//函数:带头结点的单链表插入操作
//前提:插入位置小于表长
void insert_linklist(link_list_t *t,int i,int val){//在第i个位置插入结点,该结点数据域为val
    link_list_t s=*t;
    if(s->next==NULL){
        return;
    }

    int n=0;
    while(n<i){
        s=s->next;
        n++;
    }
    //此时,t指向第i-1个结点
    link_list_t node=new link_node_t;
    node->m_val=val;
    node->next=s->next;
    s->next=node;
    return;
}

//函数:清空单链表
void empty_linklist(link_list_t *t){
    link_list_t s=*t;
    link_list_t u;
    while(s->next!=NULL){
        u=s->next;
        s->next=u->next;
        delete u;
        u=NULL;
    }
}

//函数:删除链表中的某一个节点(前提条件:该节点一定存在)
//性能要求:在O(1)时间复杂度内实现
void delete_node_exist(link_list_t *head,link_list_t node_deleted){//注意head参数为指针类型
	//算法思想:
	//通过拷贝要删除节点的后继节点的内容覆盖要删除节点的内容,然后删除要删除节点的后继节点即可
	//要考虑的特殊情况是:要删除的节点是链表尾部节点,仍然需要遍历链表
	if(NULL == head || NULL == node_deleted)
		return;

	//要删除的节点不是尾节点
	if(node_deleted->next != NULL){
		link_list_t next_node = node_deleted->next;
		node_deleted->m_val = next_node->m_val;
		node_deleted->next = next_node->next;

		delete next_node;//删除节点
		next_node = NULL;//同时指向NULL;因为delete一个指针之后,只是回收指针指向位置的空间,而指针本身的值不变.你需要手工将其赋值为NULL。
	}
	//链表中只有一个节点
	else if(*head == node_deleted){
		delete node_deleted;
		node_deleted = NULL;
		*head = NULL;
	}
	//要删除的节点是尾节点
	else{
		link_list_t node = *head;
		while(node->next != node_deleted)
			node = node->next;

		node->next = node_deleted->next;
		delete node_deleted;
		node_deleted = NULL;
	}
	return;
}

//函数:删除链表中数据值等于给定值的节点
void delete_node(link_list_t *head,int val){
	if(NULL == head){
		cout << "Delete node failed :The node to be delete not exist!" << endl;
		return;
	}

	if(val == (*head)->m_val){
		link_list_t node = *head;
		*head = (*head)->next;
		delete node;
		node=NULL;
		return;
	}
	//首先判断该节点是否存在链表中
	link_list_t node = *head;
	while(node->next != NULL){
		if(val == node->next->m_val)
			break;
		node = node->next;
	}
	//存在满足条件的节点
	if(node->next != NULL){
		link_list_t node_delete = node->next;
		node->next = node_delete->next;
		delete node_delete;
		node_delete=NULL;
	}
	else
		cout << "删除失败:链表中不存在值等于" << val << "的节点" << endl;
	return;
}

//函数:获得链表中的倒数第K个节点
link_list_t get_kth_node(link_list_t head,int k){
	//性能:只需遍历链表一遍即可
	//算法思想:设置两个指针,一个指向链表头部,一个指向第k个节点,然后两个指针同时向后移动,当第二个指针指向链表的尾节点时,第一个指针指向的节点便是倒数第K个节点
	//注意代码的鲁棒性,防止程序的崩溃
	if(NULL == head || k <= 0)
		return NULL;

	//设置两个指针
	link_list_t p1 = head,p2 = head;
	int i = 0;
	//第二个指针向前走k-1步
	while(i < k - 1 && p2->next != NULL){
		p2 = p2->next;
		++i;
	}
	//注意链表中总节点数小于K的情况
	if(i != k - 1 && NULL == p2->next)
		return NULL;

	//两个指针同时向后前进
	while(p2->next != NULL){
		p1 = p1->next;
		p2 = p2->next;
	}
	return p1;
}

//函数:反转链表
//返回值:反转之后的链表头节点
link_list_t reverse_linklist(link_list_t head){
	//链表为空或者只有一个节点
	if(NULL == head || NULL == head->next)
		return head;

	link_list_t prev_node = NULL,next_node,cur_node = head,head_reverse;
	while(cur_node != NULL){
		next_node = cur_node->next;
		if(NULL == next_node)
			head_reverse = cur_node;//原链表尾节点即逆转后链表的头节点
		cur_node->next = prev_node;
		prev_node = cur_node;
		cur_node = next_node;
	}
	return head_reverse;
}

//函数:合并两个已排序的链表(递归方法实现)
link_list_t merge_linklist_recursive(link_list_t head1,link_list_t head2){
	if(NULL == head1)
		return head2;
	else if(NULL == head2)
		return head1;

	link_list_t merge_head = NULL;

	if(head1->m_val < head2->m_val){
		merge_head = head1;
		merge_head->next = merge_linklist_recursive(head1->next,head2);
	}
	else{
		merge_head = head2;
		merge_head->next = merge_linklist_recursive(head1,head2->next);
	}
	return merge_head;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值