Python与C++实现单链表

5 篇文章 0 订阅
4 篇文章 2 订阅

算法与数据结构是编程基础,最近初学Python,学习新语言的同时回顾很久以前学习的数据结构,数据结构的实现本质与语言无关。

单链表的实现点:

1.链表初始化的时候,头结点可以只定义指针域而不定义数据域,也可以在初始化列表(C++)直接定义头结点指针域与数据域。

2.单链表插入操作:

单链表的插入操作相对简单,如上图,p2为插入的指针,2Node为插入结点,直接p2->next=head->next,head->next=p2即可。

3.单链表删除操作:

仍以上图为例,如需从右侧图删除2Node结点至左侧,直接head->next=p1即可

插入与删除需要考虑到结点所处的位置(链表头,链表尾),C++中析构时需要创建辅助变量,不然会出现指针悬挂(野指针)的问题。

Python实现

'''单链表的操作
is_empty() 链表是否为空
length() 链表长度
travel() 遍历整个链表
add(data) 链表头部添加元素
append(data) 链表尾部添加元素
insert(pos, data) 指定位置添加元素
remove(data) 删除节点
find(data) 查找节点是否存在'''
class SingleNode(object):
    """单链表的结点"""
    def __init__(self,data):
        # _data存放数据元素
        self.data = data
        # _next是下一个节点的标识
        self.next = None


class SingleLinkList(object):
    """单链表"""
    def __init__(self):
        self._head = None

    def is_empty(self):
        """判断链表是否为空"""
        return self._head == None

    def length(self):
        p = self._head
        count = 0
        while p != None:
            count += 1
            p = p.next
        return count

    def travel(self):
        p=self._head
        while p!=None:
            print(p.data," ")
            p=p.next

    def add(self,data):
        item = SingleNode(data)
        item.next = self._head
        self._head = item

    def append(self,data):
        item = SingleNode(data)
        if self.is_empty():
            self.add(data)
        else:
            p=self._head
            while p.next!=None:
                p=p.next
            item.next=p.next
            p.next=item

    def find(self,data):
        '''比较直接的想法是定位到data所在节点,但是单链表这样处理无法快速定位data的前驱,所以返回p.next.data==d的p指针'''
        p=self._head
        while p.next:
            if p.next.data==data:
                return p
            p=p.next
        return None

    def insert(self,pos,data):
        if pos <= 0:
            self.add(data)
            # 若指定位置超过链表尾部,则执行尾部插入
        elif pos > (self.length() - 1):
            self.append(data)
            # 找到指定位置
        else:
            item = SingleNode(data)
            p=self._head
            for i in range (1,pos):
                p=p.next
            item.next=p.next
            p.next=item

    def remove(self,data):
        h = self._head
        if h.data == data:
            self._head = h.next
        else:
            if not self.find(data):
                print("Not found!Please change your data!")
                return
            else:
                p = self.find(data)
                q = p.next
                p.next = q.next

if __name__ == "__main__":
    ll = SingleLinkList()
    ll.add(1)
    ll.add(2)
    ll.append(3)
    ll.travel()
    ll.insert(2, 4)
    print ("length:",ll.length())
    ll.travel()
    ll.remove(2)
    print ("length:",ll.length())
    ll.travel()

C++实现

#include <iostream>
using namespace std;

class List {
public:
	List(){create_List();}
	~List(){clear();}

	//函数声明
	void create_List();
	//从头节点进行插入
	void insert(const int& d);
	//在指定位置插入
	void insert_pos(const int&d,const int&d1);
	//删除指定数据的节点
	void erase(const int& d);
    //修改指定数据
    void updata(const int& d,const int& d1);
    //反转链表函数
    void reverse();
	void reverse_print();

	
    //打印
    void print();
    //节点结构
    struct Node{
		int data;
		Node* next;
		Node(const int& d):data(d),next(NULL){}
       
    };


    Node * head;//头节点
    //清理链表函数
	//逆序打印
	void ReversePrint(Node* head);
    void clear(){
        //从头节点开始循环删除
      //      delete p;//delete是否会删除对应值,还是只是像free一样将内存控制权移交给系统?
        //    p = q;//不能注释掉第一句话,然后delete p,再将p->next的值赋给p,必然会出现指针悬挂
	
          Node* p =head;
		  while(p)
		  {
			  Node* q =p->next;
			  delete p;
			  p=q;
		  }
        //在对指针进行delete操作时需要很小心,要避免出现指针悬挂的问题。
    }
    //查找数据d的上一个节点位置的函数
    //为了方便后面删除操作
    Node* find(const int& d){
       Node *p =head;
	   while (p){
		   if(p->next->data==d)
			   break;
		   p=p->next;
	   }
		return p;
    }
};

//创建头结点
void List::create_List()
{
     head = new Node(0);
}
//从头插入一个节点,先赋值自身后继,再赋值其前一个元素的后继,类内声明类外定义
void List::insert(const int& d)
{
    Node* q =new Node(d);
	q->next=head->next;
	head->next=q;

}
//打印函数
void List::print()
{
	Node* p =head->next;
	while(p)
	{
		cout<<p->data<<endl;
		p=p->next;
	}
    
}
//在d位置之前插入d1
void List::insert_pos(const int& d,const int& d1)
{
	Node* p =find(d);
	Node* q = new Node(d1);
	q->next=p->next;
	p->next=q;

}

//删除data为某值的节点
void List::erase(const int& d)
{
	Node* p = find(d);
	Node* q = p->next;
	p->next=q->next;

    
}

//修改指定数据
void List::updata(const int& d,const int& d1)
{
  Node* p = find(d);
  p->next->data=d1;
}

//反转链表
void List::reverse()
{
    Node * p = head->next;//头结点之后的第1个节点
    Node * q = p->next;//头结点之后的第2节点
    Node * m = q->next;//头结点之后的第3个节点
    p->next = NULL;//将头接点之后的第1个节点的next指针置为空
    //根据m是否为空来判断 以此逆序每一个节点
    while(m){
        q->next = p;
        p = q;
        q = m;
        m = m->next;
    }
    //将最后一个节点逆序
    q->next = p;
    //将头从新指向新的的第1个节点(之前的最后一个节点)
    head ->next = q;
}

void List::reverse_print()
{
	ReversePrint(head->next);
}

void List::ReversePrint(Node *head)//递归实现逆序打印(不改变链表结构),比较尴尬的是会输出默认的头结点的data值,为0,
//由于使用递归调用,所以并不方便修改代码体,传参的时候用->next后移一位即可,因为不是顺序存储结构,
//所以不能采用head++的方式
{  
    if(head!=NULL)  
    {  
        if(head->next!=NULL)  
            ReversePrint(head->next);  
        cout<<head->data<<endl;  
    }  
}  

int main(int argc, const char * argv[])
{

    // insert code here...
    List list;
    list.insert(30);
    list.insert(20);
    list.insert(10);
//	list.insert(40);
    list.insert_pos(10, 5);
    list.print();
    cout << "---------------------" << endl;
    list.erase(10);
    list.print();
    cout << "---------------------" << endl;
    list.reverse();
    list.print();
    cout << "---------------------" << endl;
    list.updata(5, 8);
    list.print();
	cout << "---------------------" << endl;
	//list.reverse_print();
    return 0;
}

图片于以下博客引用:

https://www.cnblogs.com/leaver/p/6718421.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值